一、ONNX基础认知:什么是ONNX、ONNX的生态定位、为什么端侧推理需要ONNX
1.1 什么是ONNX?说白了就是个模型通用格式
ONNX,全称Open Neural Network Exchange。名字挺长,但核心就一句话:它是深度学习模型的"通用语言"。
我刚开始做模型部署那会儿,最头疼的就是框架不互通。PyTorch训练好的模型,想放到TensorRT上推理?得先转一遍。想放到NCNN上跑?又得转一遍。每个框架都有自己的序列化格式,就像每个国家都说自己的方言,交流起来特别费劲。
ONNX就是来解决这个问题的。它定义了一套标准的数据结构和算子集。你只要把模型导出成ONNX格式,理论上就能在任何支持ONNX的推理引擎上运行。嗯,这里要注意,我说的是"理论上"——实际落地时还是会遇到不少坑,这个后面会细说。
ONNX的核心价值:
- 框架解耦:训练用PyTorch,推理用ONNX Runtime,互不依赖
- 一次导出,多处运行:ONNX模型可以在CPU、GPU、NPU、DSP上跑
- 生态开放:微软、Facebook、亚马逊等巨头都在推
1.2 ONNX的生态定位——它到底站在哪一层?
要理解ONNX的定位,你得先看看深度学习模型的生命周期:
- 训练阶段:PyTorch、TensorFlow、PaddlePaddle...各玩各的
- 导出阶段:ONNX登场,把模型转成标准格式
- 优化阶段:ONNX Runtime、TensorRT、OpenVINO等工具做图优化、量化
- 部署阶段:在端侧设备上跑推理
ONNX就卡在"导出"和"优化"之间。它不负责训练,也不直接做推理加速。它的角色是中间桥梁。
我个人习惯把ONNX比作"翻译官"。训练框架说中文,推理引擎说英文,ONNX就是那个能听懂两边话的翻译。没有它,你每次换推理后端都得重写一遍模型。
| 层级 | 代表工具 | ONNX的角色 |
|---|---|---|
| 训练框架 | PyTorch, TensorFlow | 导出ONNX模型 |
| 中间表示 | ONNX | 标准模型格式 |
| 推理引擎 | ONNX Runtime, TensorRT | 加载并优化ONNX |
| 端侧硬件 | CPU, GPU, NPU | 执行推理 |
一个小技巧:我在项目中经常遇到这种情况——PyTorch模型直接转TensorRT会报错。这时候我会先转成ONNX,再用ONNX转TensorRT。虽然多了一步,但成功率高出不少。说白了,ONNX就是那个"保险丝"。
1.3 为什么端侧推理需要ONNX?
这个问题我经常被问到。有人觉得:"我直接用PyTorch Mobile不就行了?干嘛多此一举?"
原因有三点,我一个个说。
1.3.1 端侧硬件碎片化严重
你想想看,手机端有高通、联发科、苹果、华为...每个芯片厂商都有自己的NPU或DSP。它们支持的算子、数据类型、内存布局都不一样。
如果你直接用PyTorch Mobile,它只能跑在CPU上。想用NPU加速?对不起,不支持。但ONNX不一样。ONNX Runtime针对不同硬件做了适配层。你只要一份ONNX模型,它就能自动选择最优的硬件后端。
我曾经在一个项目里,需要在骁龙888和麒麟9000上跑同一个模型。如果用原生框架,得维护两套代码。换成ONNX后,一份模型搞定。嗯,虽然中间也踩了不少算子兼容的坑,但整体效率提升很明显。
1.3.2 模型优化工具链成熟
ONNX生态里有一整套优化工具:
- ONNX Runtime:微软出品,支持图优化、算子融合、量化
- ONNX Simplifier:简化模型结构,去掉冗余节点
- ONNX Quantizer:做INT8量化,减少模型体积
- ONNX MLIR:用MLIR做底层编译优化
这些工具都是围绕ONNX格式设计的。你只要把模型转成ONNX,就能享受整个生态的红利。
举个例子:一个ResNet50模型,原始PyTorch模型大小约98MB。经过ONNX导出+INT8量化后,可以压缩到25MB左右。在端侧推理时,速度能提升2-3倍。这个收益,你直接用PyTorch Mobile是拿不到的。
1.3.3 跨平台部署的"统一语言"
端侧部署的场景太杂了:Android、iOS、Linux、RTOS...每个平台都有自己偏好的推理框架。
但ONNX是跨平台的。你可以在Windows上导出模型,在Linux上做优化,最后部署到Android手机上。整个过程模型格式不变。
我记得有一次,客户要求模型同时跑在iOS和Android上。如果分别用Core ML和NCNN,得维护两套转换脚本。后来我直接用ONNX Runtime,一份模型两端跑。虽然ONNX Runtime在iOS上的性能不如Core ML极致,但开发效率高太多了。
避坑指南:我曾经以为ONNX是万能的。直到有一次,我把一个包含自定义算子的模型导出成ONNX,结果在端侧推理时直接崩溃。后来才发现,ONNX的算子集是有限的。如果你的模型用了某些冷门算子,导出时可能会失败。所以我的建议是:在训练阶段就考虑ONNX兼容性,尽量用ONNX支持的算子。
1.4 小结
ONNX不是什么神秘的东西。它就是一套标准,一个中间格式。它的价值在于:
- 让模型在不同框架间自由流动
- 让端侧推理能利用硬件加速能力
- 让优化工具链能统一发力
说白了,如果你只做云端推理,ONNX可能不是必须的。但如果你做端侧推理,面对各种碎片化的硬件和平台,ONNX几乎是绕不开的选择。
下一章,我会带你手把手导出一个ONNX模型,并讲讲那些导出时容易踩的坑。嗯,到时候见。