onnx之模型文件语法介绍
ONNX最核心的语法结构介绍
📚 ONNX核心语法全景图
ONNX模型本质上是一个由Protocol Buffers定义的嵌套数据结构。我们可以把它想象成一个俄罗斯套娃,最外层是模型,打开后是计算图,再打开是节点和张量。

📖 语法详解:逐层拆解
1. 模型层(ModelProto)—— 身份证
每个ONNX文件最外层都是一个ModelProto,它定义了模型的"身份证信息"。
文本语法示例:
< ir_version: 8, // ONNX中间表示版本 opset_import: [ "" : 18 ], // 导入的算子集(默认域为空字符串) producer_name: "PyTorch", producer_version: "2.1.0", model_version: 1, doc_string: "这是一个简单的线性模型" > agraph ... // 后面是计算图内容
关键字段详解:
| 字段 | 类型 | 含义 | 实践意义 |
|---|---|---|---|
ir_version |
int64 | ONNX IR规范版本 | 决定了模型结构的解析方式 |
opset_import |
repeated | 导入的算子集列表 | 每个算子集由(domain, version)唯一标识 |
producer_name |
string | 生成工具名称 | 调试时追溯来源 |
graph |
GraphProto | 核心计算图 | 模型的主体内容 |
算子集(opset_import)的深层理解:
-
默认算子集(domain="")是所有模型必须导入的
-
可以导入多个自定义算子集(如
com.microsoft、com.nvidia) -
每个算子集版本号单调递增,新版本可能新增、修改或弃用算子
-
运行时必须支持所有导入算子集,否则拒绝执行
2. 计算图层(GraphProto)—— 施工图
GraphProto是整个模型的核心,它描述了计算的具体流程。
文本语法示例:
agraph (float[N, 128] X, float[128, 10] W, float[10] B) => (float[N, 10] C)
{
T = MatMul(X, W)
S = Add(T, B)
C = Softmax(S)
}
等价Python API构造:
from onnx import helper, TensorProto
# 定义输入输出张量
X = helper.make_tensor_value_info('X', TensorProto.FLOAT, ['N', 128])
W = helper.make_tensor_value_info('W', TensorProto.FLOAT, [128, 10])
B = helper.make_tensor_value_info('B', TensorProto.FLOAT, [10])
C = helper.make_tensor_value_info('C', TensorProto.FLOAT, ['N', 10])
# 定义节点
node1 = helper.make_node('MatMul', ['X', 'W'], ['T'])
node2 = helper.make_node('Add', ['T', 'B'], ['S'])
node3 = helper.make_node('Softmax', ['S'], ['C'])
# 构建图
graph = helper.make_graph(
[node1, node2, node3], # 节点列表,**必须按拓扑序**[citation:2]
'linear_graph',
[X, W, B], # 输入
[C] # 输出
)
3. 节点层(NodeProto)—— 施工工序
每个NodeProto代表计算图中的一个算子,是实际执行计算的基本单元。
文本语法中的节点:
T = MatMul(X, W) // 输出 = 算子名(输入1, 输入2, ...)
节点构成要素:
| 要素 | 含义 | 示例 |
|---|---|---|
| 算子类型 | 执行的操作 | MatMul、Add、Conv |
| 输入 | 输入张量名列表 | ['X', 'W'] |
| 输出 | 输出张量名列表 | ['T'] |
| 属性 | 算子参数(常量) | kernel_shape, pads, strides |
重要概念:输入vs属性
输入表示动态计算得到的值,属性是图中固定的常量。这种区分对硬件实现很重要,因为属性可能在编译期就确定。
4. 张量层(ValueInfoProto/TensorProto)—— 材料清单
ONNX中有两种"材料":一种是流动的中间结果(ValueInfoProto),一种是固定的权重(TensorProto)。
ValueInfoProto(中间结果声明):
# 定义形状为[10,10]的浮点张量
tensor_info = helper.make_tensor_value_info(
'a',
TensorProto.FLOAT, # 数据类型
[10, 10] # 形状(可用维度符号,如'N'、'batch')
)
TensorProto(常量数据):
import numpy as np from onnx import numpy_helper # 将numpy数组转为ONNX常量 weights = np.random.randn(128, 10).astype(np.float32) weights_tensor = numpy_helper.from_array(weights, name='W') # 将常量添加到图的initializer列表中 graph.initializer.append(weights_tensor)
🔍 实战:用"语法眼"看一个真实模型
让我们用刚才学的语法知识,解读一个真实ONNX模型的文本输出。下面这个例子来自MMDeploy教程:
text
ir_version: 8
graph {
node {
input: "a"
input: "x"
output: "c"
op_type: "Mul"
}
node {
input: "c"
input: "b"
output: "output"
op_type: "Add"
}
name: "linear_func"
input { # 输入a的声明
name: "a"
type {
tensor_type {
elem_type: 1 # FLOAT类型
shape {
dim {dim_value: 10}
dim {dim_value: 10}
}
}
}
}
input { name: "x" ... } # 输入x
input { name: "b" ... } # 输入b
output { name: "output" ... } # 输出
}
opset_import {version: 15}
语法分析:
-
模型层:
ir_version: 8表示遵循ONNX IR v8规范;opset_import {version: 15}表示使用默认算子集v15 -
图层:
graph包含2个节点、3个输入、1个输出 -
节点层:先
Mul后Add,符合拓扑序(因为Add依赖Mul的输出c) -
张量层:所有输入输出都是形状[10,10]的float32
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)