算子详解 #
算子概述 #
ONNX 定义了一套标准算子集,涵盖深度学习中常用的各种操作。每个算子都有明确的输入、输出和属性定义。
算子分类 #
text
┌─────────────────────────────────────────────────────────────┐
│ ONNX 算子分类 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 神经网络层 (Neural Network) │
│ ├── Conv - 卷积 │
│ ├── ConvTranspose - 转置卷积 │
│ ├── MaxPool / AveragePool - 池化 │
│ ├── BatchNormalization - 批归一化 │
│ ├── Dropout - 随机失活 │
│ ├── Gemm - 通用矩阵乘法 │
│ └── InstanceNormalization - 实例归一化 │
│ │
│ 激活函数 (Activation) │
│ ├── Relu - ReLU │
│ ├── Sigmoid - Sigmoid │
│ ├── Tanh - Tanh │
│ ├── LeakyRelu - Leaky ReLU │
│ ├── Softmax - Softmax │
│ ├── PRelu - PReLU │
│ ├── Elu - ELU │
│ └── Selu - SELU │
│ │
│ 数学运算 (Math) │
│ ├── Add, Sub, Mul, Div - 四则运算 │
│ ├── MatMul - 矩阵乘法 │
│ ├── Pow, Sqrt, Exp, Log - 指数对数 │
│ ├── Abs, Neg, Sign - 符号运算 │
│ ├── ReduceMean, ReduceSum, ReduceMax - 归约运算 │
│ └── Clip, Ceil, Floor - 数值处理 │
│ │
│ 张量操作 (Tensor) │
│ ├── Reshape - 形状变换 │
│ ├── Transpose - 转置 │
│ ├── Concat - 拼接 │
│ ├── Split - 分割 │
│ ├── Slice - 切片 │
│ ├── Gather - 收集 │
│ ├── Flatten - 展平 │
│ ├── Squeeze / Unsqueeze - 维度操作 │
│ └── Pad - 填充 │
│ │
│ 控制流 (Control Flow) │
│ ├── If - 条件分支 │
│ └── Loop - 循环 │
│ │
└─────────────────────────────────────────────────────────────┘
神经网络层算子 #
Conv(卷积) #
卷积是深度学习中最核心的算子之一。
text
┌─────────────────────────────────────────────────────────────┐
│ Conv 算子详解 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 输入: │
│ ├── X: 输入张量 [N, C_in, H, W] │
│ ├── W: 权重张量 [C_out, C_in/group, kH, kW] │
│ └── B: 偏置张量 [C_out] (可选) │
│ │
│ 输出: │
│ └── Y: 输出张量 [N, C_out, H_out, W_out] │
│ │
│ 属性: │
│ ├── kernel_shape: 卷积核大小 [kH, kW] │
│ ├── strides: 步长 [sH, sW] │
│ ├── pads: 填充 [pH_begin, pW_begin, pH_end, pW_end] │
│ ├── dilations: 膨胀率 [dH, dW] │
│ ├── group: 分组数 │
│ └── auto_pad: 自动填充模式 │
│ │
│ 输出尺寸计算: │
│ H_out = floor((H + pH_begin + pH_end - dH*(kH-1) - 1) / sH + 1) │
│ W_out = floor((W + pW_begin + pW_end - dW*(kW-1) - 1) / sW + 1) │
│ │
└─────────────────────────────────────────────────────────────┘
python
from onnx import helper, TensorProto
conv_node = helper.make_node(
"Conv",
inputs=["X", "W", "B"],
outputs=["Y"],
kernel_shape=[3, 3],
strides=[1, 1],
pads=[1, 1, 1, 1],
dilations=[1, 1],
group=1
)
depthwise_conv = helper.make_node(
"Conv",
inputs=["X", "W"],
outputs=["Y"],
kernel_shape=[3, 3],
strides=[1, 1],
pads=[1, 1, 1, 1],
group=64
)
MaxPool / AveragePool(池化) #
text
┌─────────────────────────────────────────────────────────────┐
│ Pool 算子详解 │
├─────────────────────────────────────────────────────────────┤
│ │
│ MaxPool: │
│ ├── 输入: X [N, C, H, W] │
│ ├── 输出: Y [N, C, H_out, W_out] │
│ └── 属性: kernel_shape, strides, pads │
│ │
│ AveragePool: │
│ ├── 输入: X [N, C, H, W] │
│ ├── 输出: Y [N, C, H_out, W_out] │
│ └── 属性: kernel_shape, strides, pads, count_include_pad │
│ │
│ GlobalAveragePool: │
│ ├── 输入: X [N, C, H, W] │
│ └── 输出: Y [N, C, 1, 1] │
│ │
└─────────────────────────────────────────────────────────────┘
python
maxpool_node = helper.make_node(
"MaxPool",
inputs=["X"],
outputs=["Y"],
kernel_shape=[2, 2],
strides=[2, 2],
pads=[0, 0, 0, 0]
)
avgpool_node = helper.make_node(
"AveragePool",
inputs=["X"],
outputs=["Y"],
kernel_shape=[2, 2],
strides=[2, 2],
pads=[0, 0, 0, 0]
)
global_avgpool = helper.make_node(
"GlobalAveragePool",
inputs=["X"],
outputs=["Y"]
)
BatchNormalization(批归一化) #
text
┌─────────────────────────────────────────────────────────────┐
│ BatchNormalization 算子 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 输入: │
│ ├── X: 输入张量 [N, C, ...] │
│ ├── scale: 缩放参数 γ [C] │
│ ├── B: 偏置参数 β [C] │
│ ├── input_mean: 均值 μ [C] │
│ └── input_var: 方差 σ² [C] │
│ │
│ 输出: │
│ └── Y: 归一化后的张量 │
│ │
│ 计算公式: │
│ Y = scale * (X - mean) / sqrt(var + epsilon) + B │
│ │
│ 属性: │
│ ├── epsilon: 防止除零的小数值 │
│ └── momentum: 移动平均动量(训练时使用) │
│ │
└─────────────────────────────────────────────────────────────┘
python
bn_node = helper.make_node(
"BatchNormalization",
inputs=["X", "scale", "B", "mean", "var"],
outputs=["Y"],
epsilon=1e-5,
momentum=0.9
)
Gemm(通用矩阵乘法) #
text
┌─────────────────────────────────────────────────────────────┐
│ Gemm 算子详解 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 输入: │
│ ├── A: 矩阵 A │
│ ├── B: 矩阵 B │
│ └── C: 偏置矩阵 C (可选) │
│ │
│ 输出: │
│ └── Y: 输出矩阵 │
│ │
│ 计算公式: │
│ Y = alpha * A' * B' + beta * C │
│ 其中 A' = transA ? A^T : A │
│ B' = transB ? B^T : B │
│ │
│ 属性: │
│ ├── alpha: A*B 的缩放因子 │
│ ├── beta: C 的缩放因子 │
│ ├── transA: 是否转置 A │
│ └── transB: 是否转置 B │
│ │
│ 常用于全连接层: │
│ Y = X @ W^T + B │
│ │
└─────────────────────────────────────────────────────────────┘
python
fc_node = helper.make_node(
"Gemm",
inputs=["X", "W", "B"],
outputs=["Y"],
alpha=1.0,
beta=1.0,
transA=0,
transB=1
)
激活函数算子 #
ReLU 系列 #
text
┌─────────────────────────────────────────────────────────────┐
│ 激活函数算子 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ReLU: │
│ Y = max(0, X) │
│ │
│ LeakyReLU: │
│ Y = X if X >= 0 else alpha * X │
│ 属性: alpha (默认 0.01) │
│ │
│ PReLU: │
│ Y = X if X >= 0 else slope * X │
│ 输入: X, slope (可学习参数) │
│ │
│ ELU: │
│ Y = X if X >= 0 else alpha * (exp(X) - 1) │
│ 属性: alpha (默认 1.0) │
│ │
│ SELU: │
│ Y = scale * (max(0, X) + min(0, alpha * (exp(X) - 1))) │
│ 默认: alpha=1.67326, scale=1.0507 │
│ │
└─────────────────────────────────────────────────────────────┘
python
relu_node = helper.make_node("Relu", inputs=["X"], outputs=["Y"])
leaky_relu = helper.make_node(
"LeakyRelu",
inputs=["X"],
outputs=["Y"],
alpha=0.01
)
prelu_node = helper.make_node(
"PRelu",
inputs=["X", "slope"],
outputs=["Y"]
)
elu_node = helper.make_node(
"Elu",
inputs=["X"],
outputs=["Y"],
alpha=1.0
)
Sigmoid / Tanh / Softmax #
text
┌─────────────────────────────────────────────────────────────┐
│ 其他激活函数 │
├─────────────────────────────────────────────────────────────┤
│ │
│ Sigmoid: │
│ Y = 1 / (1 + exp(-X)) │
│ 输出范围: (0, 1) │
│ │
│ Tanh: │
│ Y = (exp(X) - exp(-X)) / (exp(X) + exp(-X)) │
│ 输出范围: (-1, 1) │
│ │
│ Softmax: │
│ Y = exp(X) / sum(exp(X)) │
│ 属性: axis (默认 -1, 最后一维) │
│ 输出和为 1 │
│ │
│ Softplus: │
│ Y = log(1 + exp(X)) │
│ │
│ Softsign: │
│ Y = X / (1 + |X|) │
│ │
└─────────────────────────────────────────────────────────────┘
python
sigmoid_node = helper.make_node("Sigmoid", inputs=["X"], outputs=["Y"])
tanh_node = helper.make_node("Tanh", inputs=["X"], outputs=["Y"])
softmax_node = helper.make_node(
"Softmax",
inputs=["X"],
outputs=["Y"],
axis=-1
)
数学运算算子 #
四则运算 #
text
┌─────────────────────────────────────────────────────────────┐
│ 四则运算算子 │
├─────────────────────────────────────────────────────────────┤
│ │
│ Add: Y = A + B │
│ Sub: Y = A - B │
│ Mul: Y = A * B │
│ Div: Y = A / B │
│ │
│ 支持广播机制: │
│ [3, 4] + [4] -> [3, 4] │
│ [3, 4] + [3, 1] -> [3, 4] │
│ [3, 4] + [1, 4] -> [3, 4] │
│ │
│ 属性: │
│ └── broadcast: 是否广播 (opset < 7) │
│ │
└─────────────────────────────────────────────────────────────┘
python
add_node = helper.make_node("Add", inputs=["A", "B"], outputs=["Y"])
sub_node = helper.make_node("Sub", inputs=["A", "B"], outputs=["Y"])
mul_node = helper.make_node("Mul", inputs=["A", "B"], outputs=["Y"])
div_node = helper.make_node("Div", inputs=["A", "B"], outputs=["Y"])
矩阵运算 #
text
┌─────────────────────────────────────────────────────────────┐
│ 矩阵运算算子 │
├─────────────────────────────────────────────────────────────┤
│ │
│ MatMul: │
│ 矩阵乘法 Y = A @ B │
│ 支持 N 维张量(最后两维做矩阵乘法) │
│ │
│ Gemm: │
│ 通用矩阵乘法 Y = alpha * A' @ B' + beta * C │
│ │
│ MatMulInteger: │
│ 整数矩阵乘法(用于量化) │
│ │
│ QLinearMatMul: │
│ 量化线性矩阵乘法 │
│ │
└─────────────────────────────────────────────────────────────┘
python
matmul_node = helper.make_node(
"MatMul",
inputs=["A", "B"],
outputs=["Y"]
)
归约运算 #
text
┌─────────────────────────────────────────────────────────────┐
│ 归约运算算子 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ReduceMean: │
│ 沿指定轴计算均值 │
│ 属性: axes, keepdims │
│ │
│ ReduceSum: │
│ 沿指定轴求和 │
│ │
│ ReduceMax / ReduceMin: │
│ 沿指定轴求最大/最小值 │
│ │
│ ReduceProd: │
│ 沿指定轴求积 │
│ │
│ ReduceL1 / ReduceL2: │
│ 沿指定轴计算 L1/L2 范数 │
│ │
│ ReduceLogSum: │
│ 沿指定轴计算对数和 │
│ │
└─────────────────────────────────────────────────────────────┘
python
reduce_mean = helper.make_node(
"ReduceMean",
inputs=["X"],
outputs=["Y"],
axes=[2, 3],
keepdims=True
)
reduce_sum = helper.make_node(
"ReduceSum",
inputs=["X", "axes"],
outputs=["Y"],
keepdims=False
)
张量操作算子 #
Reshape / Transpose #
text
┌─────────────────────────────────────────────────────────────┐
│ 形状操作算子 │
├─────────────────────────────────────────────────────────────┤
│ │
│ Reshape: │
│ 改变张量形状 │
│ 输入: data, shape │
│ shape 中可以使用 0 表示保持原维度大小 │
│ shape 中可以使用 -1 表示自动推断 │
│ │
│ Transpose: │
│ 转置张量维度 │
│ 属性: perm (维度排列) │
│ 例: [0, 2, 3, 1] 将 [N,C,H,W] 变为 [N,H,W,C] │
│ │
│ Flatten: │
│ 展平张量 │
│ 属性: axis (从哪个维度开始展平) │
│ │
│ Squeeze: │
│ 移除大小为 1 的维度 │
│ │
│ Unsqueeze: │
│ 插入大小为 1 的维度 │
│ │
└─────────────────────────────────────────────────────────────┘
python
reshape_node = helper.make_node(
"Reshape",
inputs=["data", "shape"],
outputs=["reshaped"]
)
transpose_node = helper.make_node(
"Transpose",
inputs=["data"],
outputs=["transposed"],
perm=[0, 2, 3, 1]
)
flatten_node = helper.make_node(
"Flatten",
inputs=["data"],
outputs=["flattened"],
axis=1
)
squeeze_node = helper.make_node(
"Squeeze",
inputs=["data", "axes"],
outputs=["squeezed"]
)
unsqueeze_node = helper.make_node(
"Unsqueeze",
inputs=["data", "axes"],
outputs=["unsqueezed"]
)
Concat / Split / Slice #
text
┌─────────────────────────────────────────────────────────────┐
│ 分割合并算子 │
├─────────────────────────────────────────────────────────────┤
│ │
│ Concat: │
│ 沿指定轴拼接张量 │
│ 属性: axis │
│ 输入: input1, input2, ... │
│ │
│ Split: │
│ 沿指定轴分割张量 │
│ 属性: axis, split (各部分大小) │
│ │
│ Slice: │
│ 切片张量 │
│ 输入: data, starts, ends, axes, steps │
│ │
│ Gather: │
│ 按索引收集元素 │
│ 输入: data, indices │
│ 属性: axis │
│ │
│ ScatterND: │
│ 按索引更新元素 │
│ │
└─────────────────────────────────────────────────────────────┘
python
concat_node = helper.make_node(
"Concat",
inputs=["input1", "input2", "input3"],
outputs=["output"],
axis=1
)
split_node = helper.make_node(
"Split",
inputs=["input"],
outputs=["output1", "output2"],
axis=1,
split=[2, 3]
)
slice_node = helper.make_node(
"Slice",
inputs=["data", "starts", "ends", "axes", "steps"],
outputs=["output"]
)
gather_node = helper.make_node(
"Gather",
inputs=["data", "indices"],
outputs=["output"],
axis=0
)
控制流算子 #
If 条件分支 #
text
┌─────────────────────────────────────────────────────────────┐
│ If 算子 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 输入: │
│ └── cond: 布尔条件 │
│ │
│ 属性: │
│ ├── then_branch: 条件为真时执行的子图 │
│ └── else_branch: 条件为假时执行的子图 │
│ │
│ 输出: │
│ └── outputs: 子图的输出 │
│ │
│ 示例: │
│ if cond: │
│ Y = A + B │
│ else: │
│ Y = A - B │
│ │
└─────────────────────────────────────────────────────────────┘
python
from onnx import helper
then_graph = helper.make_graph(
[helper.make_node("Add", inputs=["A", "B"], outputs=["Y"])],
"then_branch",
[],
[helper.make_tensor_value_info("Y", TensorProto.FLOAT, [1])]
)
else_graph = helper.make_graph(
[helper.make_node("Sub", inputs=["A", "B"], outputs=["Y"])],
"else_branch",
[],
[helper.make_tensor_value_info("Y", TensorProto.FLOAT, [1])]
)
if_node = helper.make_node(
"If",
inputs=["cond"],
outputs=["Y"],
then_branch=then_graph,
else_branch=else_graph
)
Loop 循环 #
text
┌─────────────────────────────────────────────────────────────┐
│ Loop 算子 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 输入: │
│ ├── M: 最大迭代次数(可选) │
│ ├── cond: 循环条件 │
│ └── v_initial: 初始状态变量 │
│ │
│ 属性: │
│ └── body: 循环体子图 │
│ │
│ 输出: │
│ └── v_final_and_scan_outputs: 最终状态和扫描输出 │
│ │
│ 循环体子图: │
│ 输入: iteration, cond, v_current │
│ 输出: cond, v_next, scan_outputs │
│ │
└─────────────────────────────────────────────────────────────┘
查询算子信息 #
使用 Python API #
python
import onnx
from onnx import defs
all_schemas = defs.get_all_schemas()
conv_schemas = defs.get_all_schemas_with_history("Conv")
latest_conv = defs.get_schema("Conv")
print(f"算子名: {latest_conv.name}")
print(f"版本: {latest_conv.since_version}")
print(f"域: {latest_conv.domain}")
print(f"文档: {latest_conv.doc}")
for input in latest_conv.inputs:
print(f"输入: {input.name}, 类型: {input.type_str}")
for output in latest_conv.outputs:
print(f"输出: {output.name}, 类型: {output.type_str}")
for attr in latest_conv.attributes:
print(f"属性: {attr.name}, 类型: {attr.type}")
列出所有算子 #
python
import onnx
from onnx import defs
all_ops = defs.get_all_operator_names()
print(f"共有 {len(all_ops)} 个算子")
for op in sorted(all_ops)[:20]:
schema = defs.get_schema(op)
print(f"{op}: since_version={schema.since_version}")
下一步 #
现在你已经了解了 ONNX 算子,接下来学习 模型转换,学习如何将各框架模型转换为 ONNX 格式!
最后更新:2026-04-04