4、ONNX基础概念:ONNX计算图、节点与张量、ONNX opset版本、IR版本

好,咱们进入ONNX的核心概念部分。说实话,很多同学一开始接触ONNX,就被一堆术语搞懵了——计算图、节点、张量、opset、IR……感觉像在学一门新语言。别急,我带你一个一个捋清楚。

4.1 ONNX计算图:模型骨架

ONNX计算图,说白了就是描述模型运算流程的一张“地图”。它把整个神经网络拆解成一系列步骤,每个步骤就是一个节点,节点之间通过张量连接。

我个人习惯把计算图想象成“流水线”:

  • 节点(Node):就是流水线上的工位,每个工位干一件事,比如卷积、池化、激活。
  • 张量(Tensor):就是流水线上传递的“零件”,也就是数据。
  • 边(Edge):就是工位之间的传送带,定义了数据流向。

举个例子,一个简单的卷积神经网络,它的计算图大概长这样:

输入张量 → Conv节点 → Relu节点 → Pool节点 → Flatten节点 → Gemm(全连接)节点 → 输出张量

每个节点都有输入和输出,输入输出都是张量。你想想看,这不就是典型的“有向无环图”吗?

核心要点:ONNX计算图是静态图,一旦定义好,结构就固定了。这和TensorFlow的Eager模式(动态图)不同,更接近TF1.x的静态图风格。

4.2 节点与张量:模型的基本单元

咱们深入看看节点和张量这两个核心概念。

4.2.1 节点(Node)

每个节点代表一个算子操作。ONNX定义了一套标准算子库,比如:

  • Conv:卷积操作
  • Relu:ReLU激活函数
  • MaxPool:最大池化
  • Gemm:矩阵乘法(全连接层)
  • Add:张量加法
  • Reshape:张量形状变换

每个节点都有三个关键属性:

  • op_type:算子类型,比如"Conv"
  • input:输入张量名称列表
  • output:输出张量名称列表
  • attribute:算子参数,比如卷积的kernel_shape、strides

我记得有一次排查模型转换问题,发现某个自定义算子没被ONNX支持,结果模型死活转不过去。后来我查了ONNX算子列表,才发现需要自己实现一个自定义节点。嗯,这里要注意,不是所有TensorFlow算子都能直接映射到ONNX。

4.2.2 张量(Tensor)

张量就是多维数组,是ONNX中数据的基本载体。它包含:

  • 数据类型:float32、int64、bool等
  • 形状:比如[N, C, H, W](注意,ONNX默认是NCHW格式)
  • 数据值:实际存储的数值

避坑指南:我曾经在转换一个图像模型时,发现推理结果完全不对。查了半天,原来是TensorFlow默认用NHWC,而ONNX用NCHW。数据排布不一样,结果当然天差地别。所以转换时一定要确认数据格式!

4.3 ONNX opset版本:算子的“方言”

opset,全称是Operator Set,翻译过来就是“算子集”。它定义了某个版本下,ONNX支持哪些算子,以及每个算子的行为。

为什么会这样?因为深度学习框架在不断发展,新的算子不断出现,旧算子也可能有行为变更。ONNX通过opset版本来管理这种变化。

举个例子:

  • opset 7:支持基本的Conv、Relu、Gemm等
  • opset 10:增加了对量化算子的支持
  • opset 13:改进了Softmax的行为
  • opset 15:增加了对更多NLP算子的支持

我建议你在转换模型时,尽量使用较新的opset版本(比如opset 15或更高),因为新版本通常修复了旧版本的bug,也支持更多算子。但也要注意,目标推理引擎可能只支持特定opset版本。

重要提醒:不同opset版本之间,同一个算子的行为可能不同。比如opset 12之前的Softmax,默认axis=1;opset 13之后,默认axis=-1。如果你不指定axis,转换后的模型行为可能和预期不一致。

查看当前ONNX支持的opset版本,可以用这个命令:

import onnx
print(onnx.defs.onnx_opset_version())  # 输出当前ONNX版本支持的最高opset

4.4 IR版本:模型文件的“格式规范”

IR,全称Intermediate Representation,中间表示。它定义了ONNX模型文件的整体结构规范。

说白了,IR版本就是告诉你:一个ONNX文件应该长什么样,包含哪些部分,各部分如何组织。

目前ONNX主要有两个IR版本:

IR版本 说明 主要变化
IR v3 早期版本,功能有限 不支持稀疏张量、外部数据
IR v4 当前主流版本 支持稀疏张量、外部数据、模型元数据更丰富
IR v5 最新版本(ONNX 1.12+) 支持函数(Function)、训练相关算子

我个人习惯使用IR v4版本,兼容性最好。如果你需要用到函数(Function)特性,比如把重复的子图封装成函数,那就得用IR v5。

查看ONNX模型的IR版本:

import onnx
model = onnx.load("model.onnx")
print(model.ir_version)  # 输出IR版本号,比如6代表IR v4

核心总结:

  • 计算图:模型的骨架,描述运算流程
  • 节点:计算图中的算子操作
  • 张量:节点之间传递的数据
  • opset版本:定义算子行为和可用算子集合
  • IR版本:定义模型文件的整体结构规范

这四个概念,你搞清楚了,ONNX就算入门了。下一章,咱们会动手把TensorFlow模型转成ONNX,到时候这些概念都会用上。