1. ONNX基础:ONNX发展史、ONNX生态、ONNX模型结构解析、ONNX Runtime安装

各位同学,欢迎来到《ONNX模型与OpenVINO部署实战》的第一章。

说实话,每次带新人做模型部署,我第一件事就是让他们搞懂ONNX。为什么?因为在实际工程中,你永远不知道甲方给的是PyTorch还是TensorFlow,甚至可能是某个冷门框架。ONNX就是那个“万能转换器”。

这一章,咱们把ONNX的来龙去脉、生态结构、以及最关键的Runtime安装,一次性讲透。

1.1 ONNX发展史:从微软内部工具到行业标准

ONNX的全称是Open Neural Network Exchange,直译就是“开放神经网络交换格式”。

2017年,微软和Facebook联合推出了这个项目。我记得当时PyTorch刚火起来,TensorFlow还是老大,两个框架互不兼容。模型从研究到生产,中间要经历“九九八十一道转换工序”,痛苦得很。

ONNX的初衷很简单:让模型能跨框架、跨平台、跨硬件运行。说白了,就是给深度学习模型搞了个“通用语言”。

几个关键时间节点:

  • 2017年9月:微软和Facebook联合发布ONNX 1.0,支持Caffe2、PyTorch、CNTK等框架。
  • 2018年:ONNX加入Linux基金会,成为开源社区项目。AWS、Intel、IBM等巨头纷纷加入。
  • 2019年:ONNX Runtime正式发布,解决了“ONNX模型谁来跑”的问题。
  • 2020年至今:ONNX成为AI部署的事实标准。几乎所有主流框架都支持导出ONNX格式。

核心观点:ONNX不是框架,是“中间表示”。它不负责训练,只负责“翻译”和“搬运”。

1.2 ONNX生态:你需要的工具链都在这里

ONNX的生态,我习惯把它分成三层:

层级 工具/组件 作用
模型转换层 torch.onnx、tf2onnx、onnx.helper 将训练好的模型导出为ONNX格式
模型优化层 onnx-simplifier、onnxoptimizer 简化计算图、去除冗余节点、常量折叠
推理执行层 ONNX Runtime、TensorRT、OpenVINO 加载ONNX模型并执行推理

这里我想重点聊聊onnx-simplifier。我在项目中遇到过好几次,导出的ONNX模型里有一堆“if-else”节点和形状推断操作,推理速度慢得离谱。用simplifier一跑,节点数直接砍半。嗯,这个工具我建议你装到开发环境里,早晚用得上。

另外,ONNX的算子集(Operator Set)也在不断更新。目前已经到opset 21了。你想想看,每个版本都会新增或修改一些算子。如果你用的框架版本太老,导出的模型可能在新版Runtime上跑不了。避坑指南:导出时指定opset版本,比如opset_version=11或13,兼容性最好

1.3 ONNX模型结构解析:一张图看懂计算图

ONNX模型本质上是一个有向无环图(DAG)。我刚开始接触时,觉得这玩意儿很玄乎。后来拆开一个模型文件一看,其实就三样东西:

  • 节点(Node):每个节点代表一个算子,比如Conv、Relu、Add。
  • 张量(Tensor):节点之间的输入输出数据,包括权重、偏置、中间特征图。
  • 图(Graph):所有节点和边的集合,定义了数据流动的路径。

举个例子,一个简单的卷积网络,ONNX结构大概长这样:

# 伪代码展示ONNX图结构
graph {
    node: Conv (input: "input", output: "conv1_out")
    node: Relu (input: "conv1_out", output: "relu1_out")
    node: MaxPool (input: "relu1_out", output: "pool1_out")
    ...
    initializer: weight_conv1 (shape: [64,3,3,3])
    initializer: bias_conv1 (shape: [64])
    input: "input" (shape: [1,3,224,224])
    output: "output" (shape: [1,1000])
}

你可能会问:“为什么我导出的ONNX文件比原始模型大?” 原因很简单——ONNX把权重参数也打包进去了。这些参数以initializer的形式存储在模型文件中。我曾经把一个ResNet50导出成ONNX,文件从200MB涨到250MB,就是因为权重格式从float16转成了float32。

小技巧:用Netron工具(一个在线模型可视化工具)打开ONNX文件,可以直观看到计算图结构。我调试模型时,经常用它来检查节点连接是否正确。

1.4 ONNX Runtime安装:三步搞定

ONNX Runtime是微软推出的跨平台推理引擎。说白了,它就是用来“跑”ONNX模型的。安装方式很简单,我推荐用pip直接装:

# CPU版本(最常用)
pip install onnxruntime

# GPU版本(需要CUDA和cuDNN)
pip install onnxruntime-gpu

# 验证安装
python -c "import onnxruntime; print(onnxruntime.__version__)"

这里有几个坑,我踩过不止一次:

  • 版本匹配问题:onnxruntime-gpu的版本必须和CUDA版本对应。比如onnxruntime 1.15.0对应CUDA 11.8。装错了会报“DLL load failed”错误。
  • Python版本:建议用Python 3.8-3.11,太老或太新的版本可能没有预编译包。
  • Windows用户注意:如果遇到“找不到msvcp140.dll”,去装个Visual C++ Redistributable就好了。

警告:不要在生产环境用pip install --upgrade onnxruntime。我曾经手贱升级了版本,结果模型推理结果全变了。后来发现是算子实现有差异。建议锁定版本号,比如onnxruntime==1.15.0。

安装完成后,写个简单的推理脚本测试一下:

import onnxruntime as ort
import numpy as np

# 创建推理会话
session = ort.InferenceSession("model.onnx")

# 获取输入输出信息
input_name = session.get_inputs()[0].name
output_name = session.get_outputs()[0].name

# 构造随机输入
input_data = np.random.randn(1, 3, 224, 224).astype(np.float32)

# 执行推理
output = session.run([output_name], {input_name: input_data})
print("推理结果形状:", output[0].shape)

这段代码虽然简单,但包含了ONNX Runtime推理的核心流程:创建会话、获取输入输出、构造数据、执行推理。我在实际项目中,基本就是在这个框架上做扩展,比如加个预处理、后处理、性能统计之类的。

小结

这一章我们聊了ONNX的来龙去脉、生态工具、模型结构,以及Runtime的安装。说实话,ONNX本身不复杂,但它的生态很庞大。你只要记住:ONNX是桥梁,Runtime是引擎,工具链是辅助

下一章,我们会动手把PyTorch模型导出成ONNX,然后踩一踩那些常见的坑。嗯,到时候你会感谢今天装好的onnx-simplifier的。