性能问题
ONNX Runtime
如何分析我那个超级慢的 WebNN 实现?
ONNX Runtime Web 的 WebNN 执行提供程序需要通过 freeDimensionOverrides 为所有符号维度指定固定的整数值,否则优化不会生效。
哇!修正参数名称后速度提升了 100 倍!
其他资源
为什么在 Intel GPU 上看不到性能提升?
在驱动程序版本 31.0.101.5518 到 32.0.101.6083 之间,Intel GPU 上默认禁用 DirectML 元命令的执行。若要在受影响的 GPU 驱动程序上启用元命令并评估性能,请添加以下标志:
gpu-flag
--disable_dml_meta_commands_for_gpu=0注意:此标志仅影响 GPU 推理,对 NPU 运算没有影响。
Transformers.js
为什么我的 Transformers.js 流水线在 WebNN 上很慢?
Transformers.js 运行在 ONNX Runtime Web 之上,因此原因相同:WebNN 需要固定形状,如果没有 free_dimension_overrides,Transformers.js 会输出警告,并且你可能会看到明显的性能下降。请在 session_options.freeDimensionOverrides 中设置这些覆盖,或在模型 config.json 的 transformers.js_config 下设置。请参阅自由维度覆盖和 Transformers.js 教程。
LiteRT.js
为什么我的 LiteRT.js 模型在 WebNN 上很慢?
检查模型有多少部分运行在 WebNN 上
WebNN 并不会运行每个模型的所有算子。WebNN 无法运行的算子会在 WebAssembly 上执行,而 WebNN 与 WebAssembly 之间的每次交接都会耗费时间。被拆分成许多部分的模型可能比完全在 CPU 上运行更慢。
- 在
loadAndCompile()之后读取model.isFullyAccelerated。当它为false时,模型只有部分被委托,并且 LiteRT.js 会在控制台中记录Model not fully compiled for webnn。 - 在控制台中查找
not delegatable消息,它们会指出被拒绝的算子。 - 在
@litertjs/model-tester中运行模型,它会比较 CPU、WebGPU 和 WebNN 加速器,显示模型有多少部分被委托,并报告与 CPU 结果之间的数值差异。
在你的硬件上比较各个加速器
请对每个加速器分别测量同一个模型,而不要假设某一个更快:
compare-accelerators.js
// 假定 loadLiteRt() 已经完成。
import { loadAndCompile, Tensor } from '@litertjs/core';
const bytes = new Uint8Array(await (await fetch('/models/model.tflite')).arrayBuffer());
for (const accelerator of ['wasm', 'webgpu', 'webnn']) {
const model = await loadAndCompile(bytes, { accelerator });
const input = new Tensor(new Float32Array(1 * 3 * 224 * 224), [1, 3, 224, 224]);
(await model.run(input)).forEach((tensor) => tensor.delete()); // 预热
const start = performance.now();
for (let i = 0; i < 20; i++) {
(await model.run(input)).forEach((tensor) => tensor.delete());
}
console.log(accelerator, 'fully accelerated:', model.isFullyAccelerated,
`${((performance.now() - start) / 20).toFixed(1)} ms per run`);
input.delete();
model.delete();
}有帮助的做法
- 使用固定的输入形状转换模型,因为 WebNN 使用固定形状编译图。
- 尝试
webNNOptions.precision: 'fp16',前提是模型和设备支持。它可能更快并占用更少内存,但会在精度上有所损失,因此请对比输出结果。 - 设置
devicePreference和powerPreference为你想要的目标设备,例如'npu'和'low-power'。它们只是提示,最终由浏览器做出选择。 - 只编译一次。
loadAndCompile()承担了开销最大的工作,因此请只创建一次模型,并在每次run()时复用。 - 量化大型模型以减小体积和内存压力,例如使用 AI Edge Quantizer。
有关各选项,请参阅 LiteRT.js 教程。
Last updated on