ONNX Runtime EP 权重共享上下文生成:ep_weight_sharing_ctx_gen 工具与 Python 编译 API 实战 ONNX Runtime EP 权重共享上下文生成ep_weight_sharing_ctx_gen 工具与 Python 编译 API 实战【免费下载链接】onnxruntimeONNX Runtime: cross-platform, high performance ML inferencing and training accelerator项目地址: https://gitcode.com/GitHub_Trending/on/onnxruntimeONNX Runtime 允许多个 EPContext如 QNN、TensorRT、OpenVINO、VitisAI 或自定义 Plugin EP 生成的编译产物之间共享权重等 GPU/NPU 侧资源从而在多模型场景中显著降低显存/内存占用。本文以onnxruntime/test/ep_weight_sharing_ctx_gen/README.md为核心完整梳理其配套的ep_weight_sharing_ctx_gen命令行工具含全部选项、Plugin EP JSON 配置与源码实现细节并重点讲解当前官方推荐的基于公开 Python APIModelCompiler完成权重共享模型编译的完整流程帮助你在边缘端多模型部署中正确生成并加载共享权重的编译模型。1. EPContext 权重共享与工具定位1.1 权重共享解决什么问题对于基于编译的 EPcompile based EPONNX Runtime 会把子图卸载给后端如 QNN HTP、TensorRT并将编译产物context binary与 ONNX 模型一起保存为*_ctx.onnx格式的 EPContext 模型。当部署场景中同时存在多个结构相关或权重相关的模型例如同一个大模型被切分为多个部分时如果每个模型各自独立加载一份权重会造成显存/内存的重复占用。ONNX Runtime 通过ep.share_ep_contexts会话配置项让多个会话按顺序共享同一份 EP 上下文资源例如权重前面的会话创建共享上下文最后一个会话通过ep.stop_share_ep_contexts标记共享结束随后生成的 context binary 会包含前面所有模型的图。ONNX Runtime 为此提供了ep_weight_sharing_ctx_gen工具来自动化整个流程。注意重要该文档开头明确标注——ep_weight_sharing_ctx_gen工具已弃用deprecated官方现在推荐使用 ONNX Runtime 公开 Python API 完成带资源权重共享的模型编译文档末尾给出了完整的示例脚本。因此本文第 46 节介绍该工具的完整用法仍存在于当前仓库、便于理解底层行为与构建方式第 7 节给出当前推荐做法。1.2 工具在仓库中的位置与构建条件工具源码位于 onnxruntime/test/ep_weight_sharing_ctx_gen/ 目录包含以下文件main.cc程序入口负责创建 Env/SessionOptions、选择 EP、按顺序创建 Session 并做 spill/fill buffer 后处理command_args_parser.cc 与 command_args_parser.h命令行解析-e/-p/-v/-i/-C/-h与 Plugin EP JSON 配置解析test_configuration.hPluginEpConfig、MachineConfig、RunConfig、TestConfig等配置结构体定义example_plugin_ep_config.jsonPlugin EP JSON 配置示例。构建条件在 cmake/onnxruntime_unittests.cmake 中定义只有当构建开启onnxruntime_USE_QNN、onnxruntime_USE_TENSORRT、onnxruntime_USE_OPENVINO或onnxruntime_USE_VITISAI中任意一项时才会编译ep_weight_sharing_ctx_gen可执行目标并链接onnxruntime_common、onnxruntime等库。这意味着该工具仅随带编译型 EP 的构建一起产出。2. 命令格式与完整选项说明工具的基本调用形式为引自原文档模型路径以英文逗号分隔、作为选项后的单一参数传入ep_weight_sharing_ctx_gen [options...] model1_path,model2_path # 示例使用 QNN EP为两个模型生成共享权重的上下文模型 ./ep_weight_sharing_ctx_gen -e qnn \ -i soc_model|60 htp_graph_finalization_optimization_mode|3 \ -C ep.context_node_name_prefix|_part1 \ ./model1.onnx,./model2.onnx2.1 选项总览选项含义默认值-e [qnn\|tensorrt\|openvino\|vitisai]指定编译型 EPcompile based providerqnn-p plugin_ep_config_json_file指定 Plugin EP 的 JSON 配置文件优先级高于-e和-i无-v输出 verbose 日志否则仅 ERROR 级别关闭-C key1\|value1 key2\|value2指定会话配置项session configuration entries键值以\|分隔、条目以空格分隔无-i key1\|value1 key2\|value2指定 EP 特定的运行时选项provider options无-h显示帮助—关于-C文档明确给出三条约束合法的键值需参考onnxruntime_session_options_config_keys.h工具会强制ep.context_enable为1、ep.context_embed_mode为0不允许通过-C修改ep.context_file_path。这些约束在 main.cc 中有对应实现遍历用户传入的会话配置项时若ep.context_enable不为1或ep.context_embed_mode不为0会打印错误并跳过该项遇到ep.context_file_path则提示不支持指定生成的 ONNX context 缓存文件名并跳过。2.2-i运行时选项以 QNN 为例-i用于传递 EP 特定的运行时选项当前工具中实际生效的是 QNN 后端选项原文档列出的完整清单键说明默认值backend_typeQNN 后端类型如cpu、htp与backend_path互斥未设置backend_pathQNN 后端库路径如/folderpath/libQnnHtp.so、/winfolderpath/QnnHtp.dll与backend_type互斥未设置vtcm_mbQNN VTCM 大小MB0不设置htp_graph_finalization_optimization_modeQNN 图 finalization 优化模式可选0/1/2/30soc_modelSoC 型号编号具体取值参考 QNN SDK 文档0unknownhtp_arch最低 HTP 架构驱动会使用该架构兼容的算子如0/68/69/73/750noneenable_htp_fp16_precision对 float32 模型启用 HTP_FP16 精度推理仅对 HTP 后端的 float32 模型生效1FP16 精度offload_graph_io_quantization将图输入量化/输出反量化卸载到另一个 EP通常是 CPU EP1由 CPU EP 处理enable_htp_spill_fill_buffer启用 HTP spill/fill buffer用于生成 QNN context binary 时未设置示例-i vtcm_mb|8 htp_arch|73。从源码结构看command_args_parser.cc 对-i的键值做了白名单校验与取值校验htp_graph_finalization_optimization_mode只接受0~3enable_htp_fp16_precision、offload_graph_io_quantization、enable_htp_spill_fill_buffer只接受0/1。此外二进制-h帮助文本command_args_parser.cc中还额外支持并文档化了extended_udmaHTP 扩展 UDMA 模式0禁用/1启用默认0这一点是 README 正文未覆盖的补充信息。2.3 解析规则细节模型路径ParsePathscommand_args_parser.cc按英文逗号切分未提供任何路径时报错ERROR: Did not specify model paths会话配置项-CParseSessionConfigs要求每个 token 必须含|分隔符且键、值非空重复键会解析失败Plugin EP 配置-pParsePluginEpConfig用nlohmann::json解析JSON 解析异常时会打印一份合法配置示例帮助排错。3. Plugin EP 的 JSON 配置-p当使用自定义 Plugin EP动态加载的 EP 库时通过-p指向一个 JSON 配置文件其优先级高于-e与-i。配置字段定义见 test_configuration.h字段必填说明ep_library_registration_name是EP 库注册名ep_library_path是EP 库文件路径如example_plugin_ep.dllselected_ep_name与selected_ep_device_indices二选一按 EP 名称选择该 EP 的所有设备selected_ep_device_indices与selected_ep_name二选一按设备索引env.GetEpDevices()返回列表中的下标选择设备default_ep_options否传递给 EP 的默认键值对选项两种典型配置引自原文档{ ep_library_registration_name: example_plugin_ep, ep_library_path: example_plugin_ep.dll, selected_ep_name: example_plugin_ep, default_ep_options: { key: value } }{ ep_library_registration_name: example_plugin_ep, ep_library_path: example_plugin_ep.dll, selected_ep_device_indices: [ 0 ], default_ep_options: { key: value } }校验与执行逻辑可从源码确认selected_ep_name与selected_ep_device_indices必须恰好设置一个must specify exactly one of ...见 command_args_parser.cc设备索引越界会报错并终止一个设备都未选中时报ERROR: No EP devices were selectedmain.cc 中RegisterPluginEpLibrary调用env.RegisterExecutionProviderLibrary注册 EP 库并用std::unique_ptr的自定义 deleter 保证 RAII 风格的自动反注册随后SetPluginEpSessionOptions通过env.GetEpDevices()拿到设备列表按名称EpName() selected_ep_name过滤或按下标筛选最终调用session_options.AppendExecutionProvider_V2(env, selected_ep_devices, config.default_ep_options)完成绑定。仓库内也附带了配置示例文件 example_plugin_ep_config.json 可直接参考。4. 源码级工作流程工具内部做了什么理解了 main.cc 的主流程就能明白权重共享上下文是如何一步步生成的日志级别-v对应ORT_LOGGING_LEVEL_VERBOSE否则ORT_LOGGING_LEVEL_ERRORmain.cc强制的会话配置main.cckOrtSessionOptionEpContextEnable 1启用 EPContext 缓存kOrtSessionOptionEpContextEmbedMode 0使用非嵌入non-embed模式即编译产物以独立文件形式输出这也是权重共享所必需的模式kOrtSessionOptionShareEpContexts 1开启 EP 上下文共享这是权重共享的核心开关按顺序创建会话main.cc对model1,model2,...依次创建Ort::Session。关键细节是——在创建最后一个模型会话之前先追加kOrtSessionOptionStopShareEpContexts 1。源码注释说明The context binary file generated later includes all graphs from previous models即最后一个模型对应的 context binary 会包含前面所有模型的图从而在共享同一份权重的情况下承载全部计算图spill/fill buffer 的 max_size 对齐main.cc仅当-i中显式传入enable_htp_spill_fill_buffer1时工具会对生成的各*_ctx.onnx做后处理输出文件命名规则是把原模型名在最后一个.之前插入_ctx如model.onnx→model_ctx.onnxGetEpContextInfoFromLastContextModel解析最后一个ctx 模型中op_type EPContext且main_context 1的节点读取其max_size属性UpdateEpContextModel将前面所有 ctx 模型中主上下文节点的max_size对齐为该值并重写文件。目的是让推理端可以按任意顺序加载这批 ctx 模型来创建会话否则 spill/fill buffer 尺寸不一致可能导致问题。5. 使用示例# QNN指定 SoC 与优化模式并通过 -C 设置 EPContext 节点名前缀使多部分模型的节点名可区分 ./ep_weight_sharing_ctx_gen -e qnn \ -i soc_model|60 htp_graph_finalization_optimization_mode|3 \ -C ep.context_node_name_prefix|_part1 \ ./model1.onnx,./model2.onnx # 使用 Plugin EP-p 优先于 -e/-i ./ep_weight_sharing_ctx_gen -p ./example_plugin_ep_config.json ./model1.onnx,./model2.onnx-C ep.context_node_name_prefix|_part1的作用是为生成的 EPContext 节点添加统一前缀便于在多模型/多部分场景下区分各上下文节点。6. 推荐做法用 Python API 编译带权重共享的模型文档明确说明目前推荐使用 ONNX Runtime 公开 Python API 完成资源例如weight共享的模型编译。以下示例展示如何用示例 Plugin EP 编译两个模型引自原文档可复制运行import onnxruntime import os def main(): ep_name example_ep ep_lib_path example_plugin_ep.dll onnxruntime.register_execution_provider_library(ep_name, os.path.realpath(ep_lib_path)) # Find one or more EP devices that correspond to the EP of interest. # In this example, we pick the first one. ep_device next((d for d in onnxruntime.get_ep_devices() if d.ep_name ep_name), None) # These are the names/paths to the input and output models. input_models [model_0.onnx, model_1.onnx] output_models [model_0_ctx.onnx, model_1_ctx.onnx] num_models len(input_models) session_options onnxruntime.SessionOptions() provider_options {} # Empty for this example # Set option that tells EP to share resources (e.g., weights) across sessions. session_options.add_session_config_entry(ep.share_ep_contexts, 1) session_options.add_provider_for_devices([ep_device], provider_options) # Compile individual models for i in range(len(input_models)): if i num_models - 1: # Tell EP that this is the last compiling session that will be sharing resources. session_options.add_session_config_entry(ep.stop_share_ep_contexts, 1) model_compiler onnxruntime.ModelCompiler( session_options, input_models[i], embed_compiled_data_into_modelFalse, ) model_compiler.compile_to_file(output_models[i]) onnxruntime.unregister_execution_provider_library(ep_name)关键点逐一对照工具的实现与第 4 节源码行为一一对应register_execution_provider_library(ep_name, path)对应工具中的env.RegisterExecutionProviderLibrary用于加载 Plugin EP 库onnxruntime.get_ep_devices()对应env.GetEpDevices()用于按ep_name找到目标 EP 设备示例取第一个匹配设备实际可按需挑选多个session_options.add_provider_for_devices([ep_device], provider_options)对应AppendExecutionProvider_V2把指定设备与 provider options 绑定到会话ep.share_ep_contexts 1是共享开关等价于工具中的kOrtSessionOptionShareEpContexts最后一个模型编译前追加ep.stop_share_ep_contexts 1通知 EP这是共享的最后一个编译会话与工具中在最后一个会话前追加kOrtSessionOptionStopShareEpContexts的行为一致ModelCompiler(session_options, input_model, embed_compiled_data_into_modelFalse)embed_compiled_data_into_modelFalse对应工具强制的 non-embed 模式ep.context_embed_mode 0编译数据以独立文件输出随后compile_to_file(output)落盘最后unregister_execution_provider_library(ep_name)反注册对应工具中 RAII 自动反注册逻辑。ModelCompiler的 Python 绑定实现位于 onnxruntime/python/onnxruntime_pybind_model_compiler.cc可进一步查阅其参数与错误处理细节。7. 实践要点小结优先使用 Python APIep_weight_sharing_ctx_gen已标记弃用新流程请采用ModelCompilerep.share_ep_contexts/ep.stop_share_ep_contexts的公开 API 方案工具源码仍适合用来理解底层行为强制 non-embed、最后一个会话停止共享、spill/fill max_size 对齐等共享顺序有讲究多个模型必须按同一SessionOptions逐个编译只有最后一个才设置ep.stop_share_ep_contexts最后一个模型的 context binary 会包含此前所有模型的图QNN 选项中backend_type/backend_path互斥htp_graph_finalization_optimization_mode只接受0~3布尔类选项只接受0/1非法值会直接报错终止Plugin EP 配置中selected_ep_name与selected_ep_device_indices恰好二选一且索引不得越界若启用 QNN 的enable_htp_spill_fill_buffer工具会对生成的*_ctx.onnx做max_size对齐使推理端可按任意顺序加载这些模型创建会话。配套参考文件工具 README、主流程实现、命令行解析、Plugin EP 配置示例、构建定义。【免费下载链接】onnxruntimeONNX Runtime: cross-platform, high performance ML inferencing and training accelerator项目地址: https://gitcode.com/GitHub_Trending/on/onnxruntime创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考