1. ONNX基础认知:什么是ONNX、为什么需要ONNX、ONNX的生态与工具链概览
1.1 什么是ONNX?说白了就是个模型“通用语言”
ONNX,全称是Open Neural Network Exchange。名字挺长,但核心意思就一个:让不同AI框架之间能互相“对话”。
我刚开始做模型部署那会儿,最头疼的就是框架切换。PyTorch训练好的模型,想转到TensorRT上推理?得先转成Caffe,再转成ONNX,中间还可能报错。那时候我就想,要是有一个统一的中间格式就好了。
ONNX就是干这个的。它定义了一套标准的数据结构、算子集合和计算图表示。你可以在PyTorch里训练,导出成ONNX,然后直接扔到ONNX Runtime、TensorRT或者OpenVINO里跑。说白了,它就是个“翻译官”,让不同框架之间不再鸡同鸭讲。
核心要点:ONNX是一种中间表示(Intermediate Representation, IR),它不依赖任何特定的训练框架,只描述模型的计算逻辑。
1.2 为什么需要ONNX?我踩过的坑告诉你
你可能觉得,我就在PyTorch里一条路走到黑不行吗?嗯,我以前也这么想。直到有一次,客户要求模型必须跑在华为昇腾芯片上。PyTorch原生不支持,TensorRT也不行,只能转成OM格式。而ONNX就是通往OM的必经之路。
总结下来,ONNX解决了三个核心痛点:
- 框架解耦:训练用PyTorch,部署用ONNX Runtime,互不绑架。你换框架,模型不用重写。
- 硬件适配:不同硬件厂商(NVIDIA、Intel、华为、AMD)都优先支持ONNX。你导出一次,到处部署。
- 生态互通:ONNX连接了训练、优化、量化、推理整个链条。没有它,每一步都得手动适配。
我的经验:如果你做模型部署,ONNX几乎是绕不开的一环。哪怕你只用PyTorch,也建议养成导出ONNX的习惯。万一哪天要换硬件,你就知道这个习惯有多值钱了。
1.3 ONNX的生态与工具链概览
ONNX不是孤零零的一个格式,它背后有一套完整的工具链。我把它分成三块:
1.3.1 模型导出与转换
- PyTorch → ONNX:用
torch.onnx.export(),这是最常用的路径。我建议导出时加上dynamic_axes参数,让输入尺寸可变。 - TensorFlow → ONNX:用
tf2onnx工具。注意TensorFlow的算子命名和ONNX不太一样,有时候需要手动映射。 - 其他框架:Keras、MXNet、Caffe2 都有对应的转换工具。不过说实话,PyTorch和TensorFlow占了90%的场景。
1.3.2 模型优化与调试
- ONNX Runtime:微软出品的推理引擎,支持CPU、GPU、甚至手机端。我项目里90%的ONNX模型都用它跑。
- ONNX Simplifier:一个神器。它能帮你简化计算图,去掉冗余节点。我遇到过模型导出后多出几百个Shape节点,跑一遍simplify就干净了。
- Netron:可视化工具。拖进去一个ONNX文件,就能看到完整的计算图。调试时我必开它。
1.3.3 硬件后端支持
| 硬件平台 | 推理引擎 | ONNX支持情况 |
|---|---|---|
| NVIDIA GPU | TensorRT | 原生支持,性能最优 |
| Intel CPU/GPU | OpenVINO | 支持,需转IR格式 |
| 华为昇腾 | MindSpore Lite | 支持,需转OM格式 |
| AMD GPU | ROCm | 通过ONNX Runtime支持 |
| ARM/手机端 | ONNX Runtime Mobile | 支持,需精简算子 |
注意:不是所有ONNX算子都能在所有硬件上跑。比如TensorRT就不支持某些动态Shape的算子。我曾经在导出时没注意,结果部署时发现算子不支持,只能手写自定义实现。嗯,这个坑后面章节会详细讲。
1.4 一个简单的ONNX导出示例
光说不练假把式。我写个最简单的例子,让你感受一下ONNX导出有多快:
import torch
import torch.nn as nn
# 定义一个简单的网络
class SimpleModel(nn.Module):
def __init__(self):
super().__init__()
self.fc = nn.Linear(10, 5)
def forward(self, x):
return self.fc(x)
model = SimpleModel()
dummy_input = torch.randn(1, 10)
# 导出ONNX
torch.onnx.export(
model,
dummy_input,
"simple_model.onnx",
input_names=["input"],
output_names=["output"],
dynamic_axes={"input": {0: "batch_size"}, "output": {0: "batch_size"}}
)
print("ONNX模型导出成功!")
这段代码跑完,你就能在当前目录看到 simple_model.onnx 文件。用Netron打开它,你会看到一个线性层,输入输出都标明了。嗯,就是这么简单。
1.5 本章小结
ONNX不是什么高深的东西。它就是AI模型界的“普通话”,让不同框架、不同硬件之间能顺畅沟通。我个人觉得,掌握ONNX是模型部署工程师的必备技能。后面的章节,我们会深入自定义算子注册,那才是真正考验功底的地方。
下一章,我会带你手写第一个自定义算子。准备好了吗?