news 2026/9/20 15:44:58

ONNX External Data 完全指南:加载、转换、校验与底层原理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ONNX External Data 完全指南:加载、转换、校验与底层原理
  • 人工智能
  • 深度学习
  • 机器学习

【免费下载链接】onnx

Open standard for machine learning interoperability

项目地址:https://gitcode.com/gh_mirrors/onn/onnx
点击查看免费下载

External Data 是 ONNX 标准中把张量数据从模型文件(.onnxprotobuf)中剥离、存放到独立外部文件的机制,用于突破 protobuf 序列化的 2GB 大小限制,并显著降低模型文件的加载内存占用。本文以 docs/ExternalData.md 为骨架,结合本仓库的 onnx/external_data_helper.py、onnx/init.py、onnx/serialization.py、onnx/checker.cc 与 onnx/onnx.in.proto 等源码,完整讲解外部数据的加载、转换、保存、校验流程以及TensorProto中相关字段的语义,帮助读者在实际工程中正确使用并安全处理外部数据模型。

一、为什么需要 External Data:2GB 边界与内存问题

ONNX 模型本质上是 protobuf 序列化的ModelProto。protobuf 的单个消息序列化大小上限为 2GB,这在 onnx/checker.py 中被常量MAXIMUM_PROTOBUF = 2147483647明确约束。当模型的权重(尤其是 LLM、大视觉模型的参数)逼近或超过该阈值时,onnx/serialization.py 中的序列化逻辑会直接抛出如下错误:

The proto size is larger than the 2 GB limit. Please use save_as_external_data to save tensors separately from the model file.

External Data 机制正是为此而生:把张量的原始二进制数据写到独立文件,模型文件内只保留描述"数据在哪"的键值对,从而绕开 2GB 上限,也让模型文件本身变得轻量、可版本化管理。这也是 ONNX 官方设计(见 docs/ExternalData.md 末尾引用的 onnx/onnx#678 提案)所确立的通用做法。

二、加载带有 External Data 的模型

2.1 默认方式:外部数据与模型同目录

如果外部数据文件与模型文件位于同一目录,直接用onnx.load()即可,加载过程会自动读取同目录下的外部数据:

import onnx onnx_model = onnx.load("path/to/the/model.onnx")

其底层行为可以在 onnx/init.py 的load_model中看到:load_external_data参数默认为True,加载时会取模型文件所在目录作为base_dir,并调用load_external_data_for_model(model, base_dir)把外部张量读入内存。

2.2 外部数据在其他目录:手动指定目录

若外部数据存放在与模型不同的目录,则需要两步完成加载:

import onnx from onnx.external_data_helper import load_external_data_for_model onnx_model = onnx.load("path/to/the/model.onnx", load_external_data=False) load_external_data_for_model(onnx_model, "data/directory/path/") # Then the onnx_model has loaded the external data from the specific directory

这里onnx.load(..., load_external_data=False)先只解析模型结构、跳过外部数据,随后用load_external_data_for_model()显式指定数据目录完成装载。

load_external_data_for_model()的实现(onnx/external_data_helper.py)会遍历模型中的所有张量,对每一个uses_external_data(tensor)为真的张量调用load_external_data_for_tensor(),将外部文件中的字节读入tensor.raw_data,然后把data_location复位为DEFAULT并清空external_data字段——加载完成后,内存中的模型与普通内嵌模型无异。

三、将模型转换为 External Data 格式

3.1 两步式:先转换、后保存

convert_model_to_external_data()只修改内存中的ModelProto标记,真正写文件发生在save_model()阶段,因此必须紧跟一次保存调用

import onnx from onnx.external_data_helper import convert_model_to_external_data onnx_model = ... # Your model in memory as ModelProto convert_model_to_external_data(onnx_model, all_tensors_to_one_file=True, location="filename", size_threshold=1024, convert_attribute=False) # Must be followed by save_model to save the converted model to a specific path onnx.save_model(onnx_model, "path/to/save/the/model.onnx") # Then the onnx_model has converted raw data as external data and saved to specific directory

各参数语义(对应 onnx/external_data_helper.py 的实现):

参数默认值说明
all_tensors_to_one_fileTrueTrue时所有张量写入由location指定的同一个外部文件;为False时每个张量单独一个文件,文件名为张量名(若张量名不是合法文件名,则回退为uuid.uuid1()生成的随机名)
locationNone外部文件相对模型文件的路径;不指定时使用uuid.uuid1()生成形如<uuid>.data的文件名。注意该路径必须是相对路径,传绝对路径会抛出ValueError;若目标文件已存在则抛出FileExistsError
size_threshold1024只有raw_data字节数≥ 该阈值的张量才会被转为外部数据;设为0可把所有带原始数据的张量全部外置
convert_attributeFalseFalse时只转换图初始器(initializer)张量;为True时连节点属性(attribute)中的张量也一并转换

3.2 一步式:保存时直接转外部数据

更常见的是把转换与保存合并为一次调用,使用onnx.save_model(..., save_as_external_data=True)

import onnx onnx_model = ... # Your model in memory as ModelProto onnx.save_model(onnx_model, "path/to/save/the/model.onnx", save_as_external_data=True, all_tensors_to_one_file=True, location="filename", size_threshold=1024, convert_attribute=False) # Then the onnx_model has converted raw data as external data and saved to specific directory

save_model的这些关键字参数(onnx/init.py)与convert_model_to_external_data完全对应。保存时真正执行落盘的是 onnx/external_data_helper.py 的write_external_data_tensors():它遍历所有uses_external_data且带raw_data的张量,调用save_external_data()把数据写入外部文件并回填offset/length,随后清空raw_data,使模型文件本体只保留描述信息。

四、onnx.checker 对 External Data 模型的校验

4.1 小于 2GB 的模型

当前 checker 支持直接校验带外部数据的模型,既可以传入已加载的ModelProto,也可以传入模型路径:

import onnx onnx.checker.check_model(onnx_model) # 传入已加载模型 onnx.checker.check_model("path/to/the/model.onnx") # 或传入模型路径

4.2 大于 2GB 的模型:必须传路径

对于超过 2GB 的模型,必须使用模型路径调用onnx.checker.check_model("path/to/the/model.onnx"),且外部数据文件必须与模型位于同一目录

import onnx onnx.checker.check_model("path/to/the/model.onnx") # onnx.checker.check_model(loaded_onnx_model) will fail if given >2GB model

原因在于:大于 2GB 的模型无法整体反序列化进内存的ModelProto(受 protobuf 2GB 上限约束),checker 需要从路径直接读取模型、结合同目录外部数据做流式校验。相关检查逻辑位于 onnx/checker.cc(如张量stored_externally时要求external_data必须包含location,见 checker.cc 第 144-162 行附近)。

五、TensorProto 中的两个外部数据字段

外部数据的语义由TensorProto消息中的两个字段定义,详见 onnx/onnx.in.proto。

5.1 data_location 字段

data_location记录该张量数据的存放位置,取值必须为以下两者之一:

  • DEFAULT——数据存储在 protobuf 消息内部,存放在raw_data(若已设置)中,否则存放在类型专用字段(如float_dataint64_data等)中;
  • EXTERNAL——数据存储在外部位置,具体位置由external_data字段描述。

若该字段未设置,则行为等同于DEFAULT(对应 proto 中的DataLocation枚举:DEFAULT = 0; EXTERNAL = 1;)。

5.2 external_data 字段

external_dataStringStringEntryProto类型的键值对列表(repeated),描述数据的外部位置。官方识别的键如下:

必选说明
"location"相对 ONNX protobuf 模型文件所在目录的文件路径;禁止使用..等向上目录组件,解析时应剥离
"offset"数据起始字节位置,以字符串形式存储的整数。建议为页大小(通常 4KB)的整数倍以支持 mmap;Windows 上建议为VirtualAlloc分配粒度(通常 64KB)的整数倍以支持内存映射
"length"数据包含的字节数,以字符串形式存储的整数
"checksum""location"指定文件的 SHA1 摘要

模型被加载后,所有external_data条目可能被追加一个("basepath", ...)键,其值为 ONNX 模型文件被加载时所在目录的路径。

5.3 外部数据文件的格式

外部数据文件中的字节内容与当前 ONNX 实现中raw_data字段的二进制格式完全一致:按固定宽度、小端序存储元素,浮点类型遵循 IEEE 754(相关编码约定见 onnx/onnx.in.proto 中raw_data的注释)。因此外部文件本质上就是raw_data的"搬出"形态,读取后直接回填即可。

六、源码级原理与安全设计

6.1 核心 API 一览

onnx/external_data_helper.py 是本机制的全部 Python 实现,关键函数包括:

  • load_external_data_for_model(model, base_dir)/load_external_data_for_tensor(tensor, base_dir):从外部文件装载数据并复位张量状态;
  • convert_model_to_external_data(...):内存内标记转换;
  • save_external_data(tensor, base_path):把raw_data写入外部文件,并在写入后通过set_external_data()回填offsetlength
  • set_external_data(tensor, location, offset, length, checksum, basepath):设置data_location = EXTERNAL并写入键值对;要求张量必须存在raw_data,否则抛ValueError
  • uses_external_data(tensor):判断张量data_location是否为EXTERNAL
  • remove_external_data_field(tensor, field_key):删除某条外部数据键值对;
  • convert_model_from_external_data(model):反向操作,把外部数据张量改回内嵌存储。

save_external_data中还有一个值得注意的细节:多张量共享同一文件时,新张量的offset必须落在"当前文件末尾到末尾 +_MAX_EXTERNAL_DATA_PADDING(64KB)"之间,超出该区间会抛出ValidationError,以避免覆盖已有数据或无界填充零字节(onnx/external_data_helper.py)。

6.2 针对恶意外部数据的三层安全防御

外部数据机制涉及文件系统路径与字节读写,仓库为此实现了三层纵深防御(注释见 onnx/external_data_helper.py):

  1. 属性白名单(CWE-915)ExternalDataInfo解析时只接受{"location", "offset", "length", "checksum", "basepath"}五个规范键,未知键会被告警并忽略,防止任意属性注入;
  2. 边界校验(CWE-400)offsetlength在解析阶段即强制为非负整数,非法值直接抛ValueError
  3. 文件大小校验(CWE-400)_validate_external_data_file_bounds()在读取前用fstat获取真实文件大小,确认offset不超过文件大小、length不超过可读字节数,从根上防止恶意构造的模型导致内存耗尽。

在 C++ 侧(onnx/checker.cc 与 1504-1687 行的open_external_data实现),加载还包含路径规范化与目录逃逸检查:外部数据路径必须能规范化为合法路径,且必须解析在模型目录之内;打开文件时会拒绝符号链接/重解析点、拒绝存在多个硬链接的文件,并通过 fd 与规范化路径的一致性检查抵御 TOCTOU 攻击。

七、实践注意事项

  • location 必须是相对路径convert_model_to_external_data对绝对路径直接抛ValueError;且location中的路径相对于模型文件所在目录解析,..向上目录组件在规范层面被禁止。
  • 外部数据文件需随模型一起分发:模型被移动时,需保持外部数据文件与模型的相对位置关系(或使用load_external_data_for_model重新指定数据目录)。
  • size_threshold 决定哪些张量外置:默认 1024 字节意味着小张量仍内嵌于模型文件,兼顾文件数量与加载性能;全量外置时设为 0。
  • 2GB 以上模型的校验:只能传模型路径,且外部数据必须在同一目录,无法对加载进内存的超大模型做 checker 校验。
  • 加载后张量状态复位load_external_data_for_model会把data_location复位为DEFAULT并清空external_data,因此加载后的模型再保存会重新内嵌数据;如需保持外部数据形态,应使用save_as_external_data=True重新保存。

外部数据机制是 ONNX 处理大模型的事实标准方案,理解其加载、转换、保存与校验的完整链路,以及TensorProto.data_location/external_data字段的精确语义,能帮助你在模型导出、跨平台分发与超大模型推理场景中避免大量踩坑。相关测试用例可进一步参考 tests/python/external_data_test.py 与 tests/python/serialization_test.py。

  • 人工智能
  • 深度学习
  • 机器学习

【免费下载链接】onnx

Open standard for machine learning interoperability

项目地址:https://gitcode.com/gh_mirrors/onn/onnx
点击查看免费下载
上一篇:koa-passport与Passport版本匹配清单:避免集成踩坑的关键步骤
下一篇:如何快速部署GPT-SoVITS语音克隆系统:终极实战指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/20 15:44:53

前端2秒生成500页矢量PDF:Rust+WASM实战与性能优化

1. 这个标题到底在说什么先把标题拆开看。“前端2秒生成500页矢量PDF”&#xff0c;核心信息有三层&#xff1a;第一&#xff0c;动作发生在前端&#xff0c;不是后端渲染完再传给浏览器&#xff1b;第二&#xff0c;产物是矢量PDF&#xff0c;不是截图拼出来的位图&#xff1b…

作者头像 李华
网站建设 2026/9/20 15:44:51

移动端智慧商城H5项目复盘:从技术选型到性能优化实战

简介&#xff1a;面向移动端开发学习者的一份 Vue2 电商实战资源&#xff0c;以智慧商城为完整业务场景&#xff0c;覆盖组件化开发、响应式布局、接口封装与状态管理等多个核心议题&#xff0c;适合有一定前端基础、希望提升工程化能力的读者。资源压缩包约四十点八九兆&#…

作者头像 李华
网站建设 2026/9/20 15:44:36

中文网络安全运营语料库:构建、清洗与开源打包实践

简介&#xff1a;中文网络安全运营领域开源语料库是一份面向网络安全研究人员、一线运营工程师及高校学生的轻量级语料包&#xff0c;内容兼顾基础概念与高级防护策略&#xff0c;涵盖案例复盘、安全事件报告及策略规划等场景&#xff0c;既能帮助新手建立安全运营框架&#xf…

作者头像 李华
网站建设 2026/9/20 15:44:31

安全隐患识别实战:从彩图手册到现场排查的完整闭环

简介&#xff1a;这份《安全隐患识别&#xff08;彩图&#xff09;》PDF手册&#xff0c;面向企业安全管理人员、一线作业人员及安全培训讲师&#xff0c;聚焦生产现场常见违规操作与风险点&#xff0c;通过彩图标注方式直观展示叉车维修未锁定、起重吊钩保险损坏、登高作业未系…

作者头像 李华
网站建设 2026/9/20 15:43:37

AI Agent与Agentic AI:原理拆解、应用洞察与落地实践

简介&#xff1a;这是一份题为《AI Agent与Agentic AI的原理和应用洞察与未来展望》的专题分享PPT&#xff0c;共221页&#xff0c;面向科研人员、工程师与AI技术爱好者。内容从Agent爆发背景与演进脉络讲起&#xff0c;系统拆解感知、认知/决策、行动模块等核心技术栈&#xf…

作者头像 李华
网站建设 2026/9/20 15:41:02

BrewUI评测:用图形界面拯救Homebrew命令行新手

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华