超过 2GB 的 ONNX 模型能读入,为什么 check_model 仍然失败?
超过 2GB 的 ONNX external data 模型应按文件路径调用 check_model,避免把完整权重序列化成单个 ModelProto。保持外部数据文件布局,并用目标运行时做推理验收。
超过 2GB 的 ONNX 模型能读入,为什么 check_model 仍然失败?
对于已经使用 external data 保存的大模型,校验时优先传模型路径:
import onnx
onnx.checker.check_model("model.onnx")
如果先用 onnx.load() 读入全部外部权重,再把得到的对象传给 checker,可能遇到:
ModelProto exceeds maximum protobuf size of 2GB
原因在于对象形式的校验路径会序列化 ModelProto。外部权重被装回对象后,单个 protobuf 消息可能超过大小限制。ONNX 官方 issue #3273 在 ONNX 1.8.0 中给出了这一复现;当前文档仍要求超过 2GB 的模型使用路径校验。问题记录、大模型 external data 文档
两种调用看似相近,经过的路径不同
下面的代码在小模型中很常见,但大模型会在对象序列化时出问题:
import onnx
model = onnx.load("model.onnx")
onnx.checker.check_model(model)
将最后两行换成直接传路径的调用。ONNX checker 源码对文件路径使用独立入口,对模型对象则调用 SerializeToString()。checker 源码
如果只是查看图结构或 external data 引用,可以不加载权重:
import onnx
model = onnx.load("model.onnx", load_external_data=False)
for tensor in model.graph.initializer:
if tensor.data_location == onnx.TensorProto.EXTERNAL:
details = {entry.key: entry.value for entry in tensor.external_data}
print(tensor.name, details.get("location"))
这段代码只列出顶层 initializer 的引用,不负责复制权重,也不构成完整校验。
部署目录必须带上外部数据
external data 模型的 .onnx 文件可能很小,大量权重保存在其他文件中。迁移时应保持文件与其引用路径对应,不能只复制 .onnx。校验路径按官方文档布局组织模型及外部数据,先确认没有缺文件或权限问题,再调用 checker。
如果当前模型把所有权重都嵌入了一个超大 protobuf,需要回到保存或导出步骤,使用工具支持的 external data 方式重新输出。仅把文件切成几块,无法替代模型内的张量引用信息。
校验通过后仍需运行验收
从同一部署目录用目标推理运行时加载模型,固定输入检查输出形状和数值误差。这样才能同时覆盖文件布局和实际执行。
这里处理的是 check_model 的大对象序列化问题。某个 optimizer、转换器或模型抽取工具如果内部仍然把完整模型序列化,改外层 checker 调用未必能修好它,应继续查看对应堆栈与工具支持范围。不要通过关闭校验或截断权重来消除错误。


