定义
ONNX(Open Neural Network Exchange,开放神经网络交换)是一种开放的模型中间格式,支持 TensorFlow、PyTorch、Caffe 等主流框架导出的模型互操作。模型经 ONNX 转换后可部署至边缘设备、NPU 或 GPU,配合 TensorRT 等运行时优化,实现跨平台推理。适用于工业视觉、缺陷检测、OCR 等边缘 AI 场景。
工作流程
训练阶段在 PyTorch、TensorFlow 等框架完成;导出为 ONNX 格式(.onnx 文件);ONNX Runtime、TensorRT、OpenVINO、各 NPU SDK 可加载 ONNX 进行推理。ONNX 支持算子扩展,部分自定义算子需各运行时适配。模型优化(量化、剪枝、算子融合)可在 ONNX 或运行时层面进行,TensorRT 可将 ONNX 进一步优化为引擎文件。
应用场景
工业视觉缺陷检测、目标检测、分类;安防人脸识别、行为分析;OCR 文字识别;语音识别。边缘 AI 网关、工控机、嵌入式设备通过 ONNX Runtime 或厂商 SDK 加载 ONNX 模型,实现本地推理,降低延迟与带宽需求。
中间表示与运行时差异
图结构保存算子而不保存训练
开放交换格式保存的是一张已经定下来的计算图:节点是算子,边是张量的形状和数据类型,权重作为初始值写在文件里。优化器状态、数据增强和损失函数不会跟着走。因此它解决的是“换一个推理软件还能不能把同一张图跑起来”,不是把训练工程完整搬家。同一份文件可以被不同运行时读取,但每个运行时只保证自己实现过的算子,文件能打开不等于每一层都在目标芯片上执行。
图里还记录 opset 版本。版本决定某个算子的属性该怎么解释,例如填充方式、缩放坐标或是否允许动态轴。导出端用新版本写文件,运行端只认识旧版本,就会在加载时报缺算子,或者更糟:静默用旧语义算出不同的数。部署包里应同时留下导出日志和 opset 号,而不是只拷贝一个扩展名正确的文件。
导出前要固定输入形状
使用这种中间文件的前提,是推理时的输入张量能够在导出时说清楚。图像高宽、批量和序列长度若留成完全动态,下游编译器往往拒绝,或者只能走很慢的回退路径。应在导出前用现场真实的分辨率跑一次推理,把预处理的颜色顺序、归一化系数和布局记进同一份说明。布局从通道在前改成通道在后,数值全部错位,但文件本身不会报错。
它适合模型结构已经冻结、希望在多个推理后端之间交接的场合。还在频繁改网络、或者依赖训练框架里的自定义 CUDA 算子时,导出会丢层。此时应先把自定义算子换成可导出的等价实现,再谈上板。接收端若是只吃私有引擎的编译器,中间文件只是入口,真正运行的是编译后的另一份产物,两份都要版本管理。
版本对齐与自定义算子
常见错误是用桌面推理跑通就认为板端一致。桌面运行时把未实现的算子转回框架执行,板端没有那套框架,加载直接失败。要在目标运行时上做逐层比对,至少抽几张现场图片看输出差异,而不是只看文件大小。另一个错误是预处理写在训练代码里却没写进导出说明,板上用了另一套缩放,精度下降被误判成量化问题。
权重在转换时被折叠进常量,后续再改一两个阈值并不能热补,必须重新导出。多名工程师各自导出、文件名相同而 opset 不同,会让现场设备行为随“最后一次拷贝”变化。把导出命令、输入样例和运行时版本绑在一起归档,才能在数月后复现同一次推理结果。
量化参数也不该在板端临时重算。校准集一旦更换,尺度跟着变,同一张现场图片的输出分布会整体平移,旧阈值全部失效。应把校准集版本和阈值一起归档,更换相机或光源时主动重做,而不是等误报增多后再猜是模型坏了。