ONNX 推理优化深入:图优化与执行提供者
FreeGuideOnline
最新
2026-06-27
python
优化前:Dynamic Shape -> Gather -> ...
优化后:直接替换为常数节点
##### 2. 节点消除(Node Elimination)
- **Identity 消除**:删除无操作的 Identity 节点。
- **Dropout 去除**:推理时 Dropout 等于乘以 1,可直接删除。
- **Slice 消除**:对整体进行无意义切片(如取全部)会被移除。
##### 3. 算子融合(Operator Fusion)
这是性能提升最显著的技术。把多个小算子合并成一个优化的内核,减少内存读写和启动开销。
典型融合模式:
- **Conv + BatchNorm + ReLU** → 单一融合卷积
- **Gemm + Relu** → 融合 GEMM
- **LayerNorm 模式** 由多个 primitive 节点重组为高效 LayerNorm
- **Attention 模式匹配** 将 `Softmax(Q*K^T)*V` 等结构融合为 Flash Attention 类算子
##### 4. 内存布局优化
调整张量的内存排布(如从 NCHW 变为 NHWC),以更好地匹配硬件指令集,减少转置操作。
##### 5. 子图重写
将一组连续操作替换为更高效的自定义算子。例如,在 CUDA EP 下,ORT 会将某些 attention 子图重写为 `MultiHeadAttention` 融合节点。
---
### 执行提供者:让计算跑在最合适的硬件上
执行提供者(Execution Provider, EP)是 ONNX Runtime 的后端引擎,负责将优化后的节点实际调度到硬件上计算。**不同的 EP 对应不同的加速库和硬件**。
#### 主要执行提供者一览
| 执行提供者 | 硬件/后端 | 特点 |
|------------|------------|------|
| **CPUExecutionProvider** | x86, ARM 多核 CPU | 默认 EP,支持标量 + 向量优化(如 MKL-DNN / OneDNN) |
| **CUDAExecutionProvider** | NVIDIA GPU | 使用 cuBLAS、cuDNN 等,需 CUDA 环境 |
| **TensorrtExecutionProvider** | NVIDIA GPU | 利用 TensorRT 引擎构建极致的推理速度,需要 JIT 编译或离线引擎 |
| **OpenVINOExecutionProvider** | Intel CPU/GPU/VPU | 针对 Intel 硬件的极致优化,支持异构推理 |
| **CoreMLExecutionProvider** | Apple Silicon / 神经引擎 | 在 macOS/iOS 上调用 ANE 加速 |
| **DnnlExecutionProvider** | Intel CPU / GPU | 基于 oneDNN,与 CPU EP 有时重叠,可视为深度优化版 |
| **ROCmExecutionProvider** | AMD GPU | 使用 MIOpen 等,支持 AMD 加速卡 |
| **DirectMLExecutionProvider** | Windows GPU(AMD/Intel/NVIDIA) | 通过 DirectML API 在 DX12 兼容 GPU 上运行 |
#### 如何注册与选择 EP?
在创建 `InferenceSession` 时提供 EP 列表,ORT 会将节点分配到支持它的第一个 EP 上。如果某个节点不被某个 EP 支持,会回退到后续 EP。
**示例:同时使用 CUDA 和 CPU 作为后备**
```python
import onnxruntime as ort
providers = [
('CUDAExecutionProvider', {
'device_id': 0,
'arena_extend_strategy': 'kNextPowerOfTwo',
'gpu_mem_limit': 2 * 1024 * 1024 * 1024, # 2GB
'cudnn_conv_algo_search': 'EXHAUSTIVE',
'do_copy_in_default_stream': True,
}),
'CPUExecutionProvider'
]
session = ort.InferenceSession('model.onnx', providers=providers)
EP 选择策略与工具
- 自动选择:ORT 会按你传入的 providers 顺序尝试注册。第一个成功注册的 EP 将尝试承接所有节点。
- 手动分区:一些复杂场景下,你可能希望部分子图在 GPU 运行,其余在 CPU 运行。可以通过
InferenceSession的enable_escalation和 fallback 机制实现。也可使用onnxruntime.transformers库的optimize_model进行针对性分区。
关键建议:
- 对于纯 GPU 推理,使用
CUDAExecutionProvider+CPUExecutionProvider作为 fallback。 - 追求 NVIDIA GPU 上的极致性能,应考虑
TensorrtExecutionProvider,但需要接受较长的首次编译时间。 - 在 Intel 处理器上,
OpenVINOExecutionProvider往往比默认 CPU EP 更快,尤其针对视觉模型。 - Apple 设备上,开启
CoreMLExecutionProvider可大幅降低功耗并提升速度。
实际调优工作流
结合图优化和执行提供者,一套典型优化流程如下:
-
导出并验证 ONNX 模型
import torch.onnx torch.onnx.export(...) # 使用 onnx.checker 验证合法性 -
设定图优化级别
在SessionOptions中设置graph_optimization_level:sess_options = ort.SessionOptions() sess_options.graph_optimization_level = ort.GraphOptimizationLevel.ORT_ENABLE_ALL可选值:
ORT_DISABLE_ALL,ORT_ENABLE_BASIC(常量折叠等)、ORT_ENABLE_EXTENDED(融合等)、ORT_ENABLE_ALL(含内存布局优化)。 -
选择执行提供者
根据目标硬件构造 provider 列表,如先CUDA,后CPU。 -
启用并行执行
sess_options.execution_mode = ort.ExecutionMode.ORT_PARALLEL sess_options.inter_op_num_threads = 2 # 控制不同节点间并行 sess_options.intra_op_num_threads = 4 # 控制单个算子内部并行 -
基准测试与迭代
使用onnxruntime.PerfTest或 Python 的timeit对比不同优化配置,特别注意:- 首次推理时常有 EP 寄存器初始化开销,取稳定后的数据。
TensorRTEP 首次构建引擎较慢,可预先用trtexec生成引擎并加载。
-
高级:使用 ONNX Runtime 的图形优化工具
python -m onnxruntime.tools.optimize_onnx_model --input model.onnx --output model_opt.onnx