必须调用 model.eval() 并确保输入为固定 shape 的 torch.Tensor,否则因训练态层或动态控制流导致静默错误或 RuntimeError;dynamic_axes 是变长输入的必需声明,导出后须用 onnx.checker 和 onnxruntime 双重验证。

能导出,但必须满足模型处于 eval() 模式、输入是固定 shape 的 torch.Tensor、且不包含动态控制流(如 Python if 分支依赖 tensor 值)——否则会静默出错或导出结果不可用。
为什么 torch.onnx.export 一运行就报 RuntimeError: Exporting model with dynamic axes is not supported
这个错误通常不是因为你用了动态轴,而是因为模型里有未处理的 torch.jit.trace 不支持的操作,或者输入 dummy_input 的 shape 被意外改变(比如在 forward 中做了 .view(-1, ...) 但 batch 维不是固定值)。更常见的是:你忘了调用 model.eval(),导致 dropout/batchnorm 层引入训练态随机行为,ONNX 导出器无法推断确定性图结构。
实操建议:
- 导出前务必执行
model.eval(),并确认没在 forward 中手动调用model.train() - 用
torch.no_grad()包裹导出过程,避免梯度相关副作用 - 检查
dummy_input是否为纯torch.Tensor(不能是 list/tuple of tensors,除非显式用input_names和dynamic_axes声明) - 如果模型含自定义 op 或非标准 torch 函数(如
torch.einsum在旧版 ONNX 不支持),先降级到已知兼容的等价写法
如何正确设置 dynamic_axes 让 ONNX 支持变长输入
dynamic_axes 不是可选优化项,而是当你需要 batch size 或 sequence length 可变时的**必需声明**。它告诉 ONNX 哪些维度在推理时可能变化,否则导出的模型只能接受和 dummy_input 完全一致的 shape。
立即学习“Python免费学习笔记(深入)”;
仅使用 Python 将 Claw Code 虚拟化框架与 OpenClaw 集成,提供 184 种工具和 200 多条命令,用于安全分析和代码质量...
示例:对图像分类模型支持任意 batch,对 NLP 模型支持变长 token 序列:
torch.onnx.export(
model,
dummy_input,
"model.onnx",
input_names=["input"],
output_names=["output"],
dynamic_axes={
"input": {0: "batch_size", 2: "height", 3: "width"}, # 图像:BCHW 中 B/H/W 可变
"output": {0: "batch_size"}
}
)注意:
- 字典 key 必须和
input_names/output_names一致,不能写成"x"却声明input_names=["input"] - value 是
{dim_index: axis_name},axis_name 只是字符串标识,不参与计算,但要唯一且有意义(方便后续推理引擎绑定) - 如果你只希望 batch 可变,其他维度固定,就只写
{0: "batch_size"},别多加没用的条目
导出后验证 ONNX 模型是否真的可用
导出成功 ≠ 模型能跑。很多问题(如算子不支持、类型转换失败)只在加载或推理时暴露。必须做两步验证:
- 用
onnx.load("model.onnx")加载,再调用onnx.checker.check_model()—— 这能捕获格式错误、shape 不匹配等基础问题 - 用
onnxruntime.InferenceSession加载并传入和dummy_input同 shape 的 numpy 数据,执行一次session.run()—— 这才能发现算子 fallback 失败、dtype 不兼容等运行时错误 - 特别注意输出值是否和 PyTorch 原始输出接近(
np.allclose(torch_out.numpy(), onnx_out, atol=1e-5)),数值漂移过大说明某层被重写了(如某些 BN 层导出后默认用 inference mode 但参数未冻结)
最易被忽略的一点:PyTorch 版本和 ONNX opset 版本强耦合。opset_version=12 在 PyTorch 1.9+ 才稳定支持 torch.where 的完整语义;用低版本导出高版本模型,可能生成非法节点。导出前查清你用的 PyTorch 对应推荐的 opset_version,别无脑设成最新。

















