1. ONNX基础认知:ONNX是什么、为什么需要ONNX、ONNX生态与工具链概览
各位同学,咱们今天聊聊ONNX。说实话,我第一次接触ONNX是在一个跨平台部署的项目里。当时模型在PyTorch上跑得飞起,换到TensorRT就各种报错。折腾了两天,差点把电脑砸了。后来同事甩给我一句:「试试ONNX吧。」嗯,从那以后,我的部署流程就再也没离开过它。
1.1 ONNX是什么?
ONNX,全称Open Neural Network Exchange。直译过来就是「开放神经网络交换格式」。说白了,它就是一个模型的中转站。
你想想看,深度学习框架那么多:PyTorch、TensorFlow、Keras、PaddlePaddle……每个框架都有自己的模型格式。PyTorch的.pt文件,TensorFlow的.pb文件,PaddlePaddle的.pdmodel。这些格式互不兼容。你拿PyTorch训练好的模型,想部署到TensorRT上?对不起,得先转一圈。
ONNX就是来解决这个问题的。它定义了一套统一的模型描述格式。不管你是用哪个框架训练的,只要导出成ONNX格式,就能被各种推理引擎读取。我个人的习惯是:所有模型最终都走ONNX,省心。
核心要点:ONNX不是一个新的框架,而是一个中间表示(Intermediate Representation, IR)。它只描述模型的计算图结构和权重参数,不负责训练。
1.2 为什么需要ONNX?
这个问题我问过很多刚入行的同学。他们的第一反应是:「直接用原框架部署不行吗?」
行,当然行。但现实很骨感。
我给你列几个我在项目中遇到的真实场景:
- 场景一:模型用PyTorch训练,但客户要求部署在NVIDIA Jetson上,用TensorRT加速。PyTorch的TorchScript在TensorRT上兼容性并不好。
- 场景二:团队里有人用TensorFlow,有人用PyTorch。模型要统一部署到同一个推理引擎上。总不能维护两套部署代码吧?
- 场景三:模型要跑在手机端(iOS/Android)。原框架的运行时库太大,动辄几百MB。ONNX Runtime轻量多了。
ONNX的价值就在这里:一次导出,到处运行。它把模型从框架的束缚中解放出来。你想想看,这多像Java的「一次编译,到处运行」?
我的建议:如果你做的项目涉及多个平台(PC、手机、边缘设备),或者团队里框架不统一,ONNX几乎是必选项。别等到部署时再临时抱佛脚。
1.3 ONNX生态与工具链概览
ONNX不是孤零零的一个格式。它背后有一套完整的工具链。我把它分成三块:
1.3.1 模型导出工具
这是最常用的一环。各大框架都提供了导出ONNX的接口:
| 框架 | 导出方式 | 备注 |
|---|---|---|
| PyTorch | torch.onnx.export() | 最成熟,支持动态轴 |
| TensorFlow | tf2onnx 工具 | 需要额外安装 |
| PaddlePaddle | paddle.onnx.export() | 飞桨官方支持 |
| Keras | keras2onnx | 社区维护 |
我个人用得最多的是PyTorch的导出接口。举个例子:
import torch
import torchvision.models as models
# 加载一个预训练模型
model = models.resnet18(pretrained=True)
model.eval()
# 构造一个虚拟输入
dummy_input = torch.randn(1, 3, 224, 224)
# 导出ONNX
torch.onnx.export(
model,
dummy_input,
"resnet18.onnx",
input_names=["input"],
output_names=["output"],
dynamic_axes={"input": {0: "batch_size"}, "output": {0: "batch_size"}}
)
嗯,这里要注意:dynamic_axes参数很关键。它允许你导出时指定哪些维度是动态的。比如batch size。如果不设,导出的模型就固定batch size为1了。我曾经因为这个踩过坑,后来养成了习惯:只要不确定,就设成动态。
1.3.2 模型推理引擎
导出ONNX之后,用什么来跑?主流的选择有:
- ONNX Runtime(ORT):微软出品,官方亲儿子。支持CPU、GPU、甚至NPU。我大部分项目都用它。
- TensorRT:NVIDIA的推理引擎。只支持NVIDIA GPU。性能极强,但需要额外优化。
- OpenVINO:Intel的推理引擎。适合Intel CPU和集成显卡。
- CoreML:苹果的推理引擎。用于iOS设备。
- NCNN / TNN / MNN:移动端推理引擎。腾讯、阿里、小米都有开源。
你可能会问:「这么多引擎,我该选哪个?」
我的经验是:先看目标平台。如果是服务器端NVIDIA GPU,首选TensorRT。如果是边缘设备(Jetson),也是TensorRT。如果是普通CPU服务器,ONNX Runtime就够了。如果是手机端,NCNN或MNN更合适。
避坑指南:我曾经把一个包含自定义算子的模型直接导出ONNX,然后扔给TensorRT。结果TensorRT不认识那个算子,直接报错。后来我才知道,ONNX只支持标准算子集。自定义算子需要注册或者用替代方案。所以,导出前最好检查一下模型里有没有非标准操作。
1.3.3 模型优化与调试工具
ONNX生态里还有一堆辅助工具:
- Netron:可视化ONNX模型结构。我调试模型时必开它。能直观看到每一层的输入输出形状。
- ONNX Simplifier:简化模型。去掉一些冗余的节点,比如Cast、Identity。能让模型更小、更快。
- ONNX Optimizer:图优化。比如常量折叠、算子融合。能提升推理速度。
- ONNX Shape Inference:形状推断。有些模型导出时形状信息丢失,可以用这个工具补全。
举个例子,用ONNX Simplifier简化模型:
python -m onnxsim resnet18.onnx resnet18_simplified.onnx
一行命令,模型大小可能减少10%-20%。我每次导出ONNX后,都会跑一遍这个。已经成了肌肉记忆。
1.4 小结
这一章咱们聊了ONNX是什么、为什么需要它、以及它的生态工具链。说白了,ONNX就是深度学习模型界的「通用语言」。它让模型不再被框架绑架,让部署变得更灵活。
下一章,我会带你手把手导出第一个ONNX模型。到时候咱们再细聊那些坑和技巧。
记住:ONNX不是银弹,但它能解决你80%的部署问题。