重要提示:此信息仅适用于 ONNX Runtime 1.10 及更早版本。请使用更新的版本。

ONNX Runtime 移动性能调优

了解不同优化如何影响性能,并获取使用 ORT 格式模型进行性能测试的建议。

ONNX Runtime Mobile 可用于在 Android 平台上使用 NNAPI(通过 NNAPI 执行提供程序 (EP))执行 ORT 格式模型,以及在 iOS 平台上使用 CoreML(通过 CoreML EP)执行模型。

首先,请回顾 在 ONNX Runtime Mobile 中使用 NNAPI在 ONNX Runtime 中使用 CoreML 中的介绍性详细信息。

重要提示: 为简洁起见,本页中的示例均指 NNAPI EP。此信息同样适用于 CoreML EP,因此下文中任何对“NNAPI”的引用都可以替换为“CoreML”。
在 ONNX Runtime 1.9 版本中添加了对创建 CoreML 感知型 ORT 格式模型的支持,类似于创建 NNAPI 感知型 ORT 格式模型

目录

1. ONNX 模型优化示例

ONNX Runtime 会对 ONNX 模型应用优化以提高推理性能。这些优化在导出 ORT 格式模型之前发生。有关可用优化的更多详细信息,请参阅图优化文档。

了解不同优化级别如何影响模型中的节点非常重要,因为这将决定模型有多少部分可以使用 NNAPI 或 CoreML 执行。

基本

基本优化会删除冗余节点并执行常量折叠。在修改模型时,这些优化仅使用 ONNX 操作符。

扩展

扩展优化会用自定义的内部 ONNX Runtime 操作符替换一个或多个标准 ONNX 操作符,以提升性能。每个优化都有一个适用于它的 EP 列表。它将只替换分配给该 EP 的节点,并且替换的节点将使用相同的 EP 执行。

布局

布局优化可能是硬件特定的,涉及 ONNX 使用的 NCHW 图像布局与 NHWC 或 NCHWc 格式之间的内部转换。它们在优化级别设置为“all”时启用。

  • 对于 ONNX Runtime 1.8 之前的版本,在创建 ORT 格式模型时,不应使用布局优化。
  • 对于 ONNX Runtime 1.8 或更高版本,可以启用布局优化,因为硬件特定优化会自动禁用。

创建优化后的 ORT 格式模型时的优化结果

以下是当仅启用 CPU EP 并应用于 MNIST 模型时,基本扩展优化中发生的变化示例。优化级别在创建 ORT 格式模型时指定。

  • 基本级别,我们组合了 Conv 和 Add 节点(加法通过 Conv 的“B”输入完成),我们将 MatMul 和 Add 组合成一个 Gemm 节点(加法通过 Gemm 的“C”输入完成),并执行常量折叠以移除一个 Reshape 节点。
    • python <ORT repository root>/tools/python/convert_onnx_models_to_ort.py --optimization_level basic /dir_with_mnist_onnx_model
  • 扩展级别,我们还使用内部 ONNX Runtime FusedConv 操作符融合了 Conv 和 Relu 节点。
    • python <ORT repository root>/tools/python/convert_onnx_models_to_ort.py --optimization_level extended /dir_with_mnist_onnx_model

Changes to nodes from basic and extended optimizations

使用 NNAPI EP 执行优化后的 ORT 格式模型的结果

如果在运行时注册了 NNAPI EP,它将有机会选择加载模型中它可以执行的节点。这样做时,它会尽可能多地将节点组合在一起,以最大程度地减少在 CPU 和 NNAPI 之间复制数据以执行节点的开销。每组节点都可以被视为一个子图。每个子图中的节点越多,子图越少,性能就会越好。

对于每个子图,NNAPI EP 将创建一个NNAPI 模型,该模型复制原始节点的处理过程。它将创建一个执行此 NNAPI 模型并执行 CPU 和 NNAPI 之间任何所需数据复制的函数。ONNX Runtime 将用一个调用此函数的单个节点替换加载模型中的原始节点。

如果 NNAPI EP 未注册或无法处理某个节点,则该节点将使用 CPU EP 执行。

下面是一个 MNIST 模型的示例,比较了如果在运行时注册 NNAPI EP,ORT 格式模型会发生什么。

由于基本级别优化会生成一个仅使用 ONNX 操作符的模型,因此 NNAPI EP 能够处理模型的大部分,因为 NNAPI 可以执行 Conv、Relu 和 MaxPool 节点。这是通过单个 NNAPI 模型完成的,因为所有 NNAPI 可以处理的节点都已连接。我们预计使用 NNAPI 会使此模型获得性能提升,因为单个 NNAPI 节点在 CPU 和 NNAPI 之间进行设备复制的开销很可能低于使用 NNAPI 一次性执行多个操作所节省的时间。

扩展级别优化引入了自定义的 FusedConv 节点,NNAPI EP 会忽略这些节点,因为它只会处理使用 NNAPI 可以处理的 ONNX 操作符的节点。这导致两个节点使用 NNAPI,每个节点处理一个 MaxPool 操作。此模型的性能可能会受到不利影响,因为 CPU 和 NNAPI 之间设备复制的开销(在两个 NNAPI 节点之前和之后都需要)不太可能超过每次使用 NNAPI 执行单个 MaxPool 操作所节省的时间。通过不注册 NNAPI EP,使模型中的所有节点都使用 CPU EP 执行,可能会获得更好的性能。

Changes to nodes by NNAPI EP depending on the optimization level the model was created with

2. 初始性能测试

最佳优化设置因模型而异。有些模型可能在使用 NNAPI 时表现更好,有些则不然。由于性能是模型特有的,您必须运行性能测试以确定最适合您模型的组合。

建议运行性能测试

  • 启用 NNAPI,并使用基本级别优化创建的 ORT 格式模型
  • 禁用 NNAPI,并使用扩展所有级别优化创建的 ORT 格式模型
    • ONNX Runtime 1.8 或更高版本使用所有,早期版本使用扩展

对于大多数场景,预计这两种方法之一将产生最佳性能。

如果使用具有基本级别优化和 NNAPI 的 ORT 格式模型产生相同或更好的性能,则可能通过创建 NNAPI 感知型 ORT 格式模型来进一步提高性能。此模型的区别在于,更高级别的优化仅应用于无法使用 NNAPI 执行的节点。是否有任何节点属于此类别取决于模型。

3. 创建 NNAPI 感知型 ORT 格式模型

NNAPI 感知型 ORT 格式模型将保留 ONNX 模型中所有可以使用 NNAPI 执行的节点,并允许对任何剩余节点应用扩展优化。

对于我们的 MNIST 模型,这意味着在应用基本优化后,红色阴影中的节点保持不变,绿色阴影中的节点可以应用扩展优化。

Show nodes that are preserved as NNAPI can execute them, and nodes that are considered by extended optimizations

要创建 NNAPI 感知型 ORT 格式模型,请按照以下步骤操作。

  1. 通过从源代码构建 ONNX Runtime,创建一个包含 NNAPI EP 的 ONNX Runtime“完整”构建。

    此构建可在任何平台上进行,因为 NNAPI EP 可用于创建 ORT 格式模型,而无需 Android NNAPI 库,因为此过程中没有模型执行。构建时,如果缺少任何标志,请将 --use_nnapi --build_shared_lib --build_wheel 添加到构建标志中。

    请勿添加 --minimal_build 标志。

    • Windows
        <ONNX Runtime repository root>\build.bat --config RelWithDebInfo --use_nnapi --build_shared_lib --build_wheel --parallel
      
    • Linux
        <ONNX Runtime repository root>/build.sh --config RelWithDebInfo --use_nnapi --build_shared_lib --build_wheel --parallel
      

    注意:对于 ONNX Runtime 1.10 及更早版本,如果您之前使用简化操作符内核进行了最小构建,则需要运行 git reset --hard 以确保在执行“完整”构建之前撤销所有操作符内核排除。否则,您可能由于缺少内核而无法加载 ONNX 格式模型。

  2. 从构建输出目录安装 python wheel。
    • Windows:位于 build/Windows/<config>/<config>/dist/<package name>.whl
    • Linux:位于 build/Linux/<config>/dist/<package name>.whl。包名称将根据您的平台、Python 版本和构建参数而异。<config> 是构建命令中 --config 参数的值。
            pip install -U build\Windows\RelWithDebIfo\RelWithDebIfo\dist\onnxruntime_noopenmp-1.7.0-cp37-cp37m-win_amd64.whl
      
  3. 按照标准说明运行 convert_onnx_models_to_ort.py 来创建 NNAPI 感知型 ORT 格式模型,并启用 NNAPI (--use_nnapi),将优化级别设置为扩展所有(例如 --optimization_level extended)。这将允许在 NNAPI 无法处理的任何节点上运行更高级别的优化。
       python <ORT repository root>/tools/python/convert_onnx_models_to_ort.py --use_nnapi --optimization_level extended /models
    

    必须安装从启用了 NNAPI 的“完整”构建中获得的 python 包,--use_nnapi 才能成为有效选项

    创建的这个 ORT 模型可以与包含 NNAPI EP 的最小构建一起使用。