ONNX 入门教程:图优化、量化与部署
1. ONNX 不是另一个推理框架
ONNX 是一个格式标准——它描述"计算图长什么样"。真正的推理由 Runtime 执行:
训练框架 ONNX 格式 部署目标
───────── ────────── ───────────
PyTorch ────┐ ONNX Runtime (CPU/GPU)
TensorFlow ─┼──→ model.onnx ──→ TensorRT (NVIDIA)
scikit-learn┘ OpenVINO (Intel)
CoreML (Apple)
WebNN (浏览器)
2. 图优化:ONNX Runtime 的加速原理
session_options = ort.SessionOptions()
session_options.graph_optimization_level = ort.GraphOptimizationLevel.ORT_ENABLE_ALL
session = ort.InferenceSession("model.onnx", session_options)
三个优化级别:
| 级别 |
典型优化 |
| Basic |
常量折叠、冗余节点消除 |
| Extended |
算子融合(Conv+BN+ReLU → 单算子) |
| Layout |
NCHW → NHWC 转换(适配特定硬件) |
3. 量化:FP32 → INT8
from onnxruntime.quantization import quantize_dynamic, QuantType
quantize_dynamic(
"resnet18.onnx", # 输入
"resnet18_int8.onnx", # 输出(~1/4 大小)
weight_type=QuantType.QInt8,
)
print("量化完成!模型缩小 75%")
| 量化类型 |
精度损失 |
大小 |
速度 |
| FP32(原始) |
0 |
100% |
1x |
| FP16 |
<0.1% |
50% |
1.5-2x |
| INT8 动态 |
<0.5% |
25% |
1.5-2x |
| INT8 静态 |
<1% |
25% |
2-4x |
4. 多平台部署速查
trtexec --onnx=model.onnx --saveEngine=model.trt --fp16
mo --input_model model.onnx --output_dir openvino_model/
coremltools.converters.onnx.convert(model="model.onnx")
5. 调试技巧
import onnx
model = onnx.load("model.onnx")
# 查看算子列表
op_types = set()
for node in model.graph.node:
op_types.add(node.op_type)
print(f"算子类型: {op_types}")
# 查看输入输出 shape
for inp in model.graph.input:
shape = [d.dim_value for d in inp.type.tensor_type.shape.dim]
print(f"输入: {inp.name} {shape}")
6. 常见坑
| 问题 |
原因 |
解决 |
| opset 不兼容 |
导出用的 opset 版本 Runtime 不支持 |
降低 opset 或升级 Runtime |
| 动态 shape 失败 |
某些后端不支持动态轴 |
导出时固定 batch size |
| 自定义算子无法导出 |
PyTorch 中使用非标准操作 |
用 torch.onnx.is_in_onnx_export() 分支处理 |
思考题
- ONNX 的图优化与 PyTorch 的
torch.jit.trace 有何本质区别?
- 为什么 INT8 量化造成的精度损失通常小于 1%?原理是什么?
- ONNX 和 TorchScript 都是"模型序列化格式",什么时候选 ONNX?