ONNX Runtime Model Package 消费端集成:executor_info[“ort“]、变体选择算法与 OrtModelPackageApi C 接口
2026/9/13 15:39:06 网站建设 项目流程

ONNX Runtime Model Package 消费端集成:executor_info["ort"]、变体选择算法与 OrtModelPackageApi C 接口

【免费下载链接】onnxruntimeONNX Runtime: cross-platform, high performance ML inferencing and training accelerator项目地址: https://gitcode.com/GitHub_Trending/on/onnxruntime

ONNX Runtime 的 model package 消费端集成层负责把独立的model_package库与 ORT 的会话运行时连接起来:加载模型包、根据运行时可用的执行提供者(EP)在变体(variant)中选出最优匹配,并为选中的变体创建OrtSession。读完本文,你可以掌握executor_info["ort"]负载的完整 JSON schema、VariantSelector的评分选择算法、OrtModelPackageApi_CreateSession的默认/进阶两条路径的语义差异,并能基于实验性 C API 完成"打开包 → 选择变体 → 创建会话"的完整调用链。

定位:model_package 库之上的 ORT 胶水层

onnxruntime/core/session/model_package/目录实现的是 ONNX Runtime 作为消费者对独立model_package库的胶水(glue)层:加载包、针对运行时的执行提供者选择变体,并为选中的变体创建OrtSession

包格式、manifest.json/component.json的 schema、共享资产(shared assets)规则、以及 C 语言编写/检查 API 全部位于 model_package/ 目录中,且该库不依赖 ORT 本身——ORT 以静态库(static archive)形式链接它,方向是单向的。这个目录在库之上只增加了三样东西

  1. executor_info["ort"]负载 schema(这是 ORT 在变体中拥有的专属槽位);
  2. 变体选择算法:查询每个 EP 工厂,从中挑出得分最高的变体;
  3. 实验性的OrtModelPackageApi_*C 函数:封装上述库并暴露会话创建能力。它们在 onnxruntime_experimental_c_api.inc 中注册,通过OrtApi::GetExperimentalFunction按名解析。

核心文件与职责

该集成层由三个 C++ 文件对加一个 C 入口文件构成:

文件职责
model_package_context.h/.ccmodel_package库的 C 信息树翻译成 ORT 内部 C++ 结构(ModelPackageInfoComponentInfoVariantInfoVariantModelInfo);解析executor_info["ort"]负载。持有包级的ModelPackageContext与组件级的ModelPackageComponentContext(内含选中变体与 provider 列表)。
model_package_options.h/.ccModelPackageOptions在调用OrtModelPackageApi_CreateModelPackageOptionsFromSessionOptions_SinceV28的时刻,从OrtSessionOptions快照当前 EP 意图(工厂、设备、EP 名列表),驱动变体选择与 provider 构建。
model_package_variant_selector.h/.ccVariantSelector::SelectVariant依据 EP 列表从组件中挑选最佳变体,内部使用OrtEpFactory::ValidateCompiledModelCompatibilityInfo回调。
model_package_api.ccC 入口点本体,位于namespace OrtExperimentalApis

从 model_package_context.cc 的构造函数可以看到胶水层的工作方式:ModelPackageContext通过::ModelPackage_Open打开包,并把库句柄以类型擦除(void*)方式保存在上下文中、直到上下文析构才调用ModelPackage_Close,从而后续的路径解析无需重复打开/解析。随后它遍历ModelPackage_Info返回的组件/变体树,把 C POD 结构逐字段拷贝为 ORT 内部 C++ 结构,并通过ModelVariantInfo_FindExecutorInfo(variant, "ort")取出 ORT 专属槽位进行解析。

executor_info["ort"]schema

executor_info["ort"]槽位是一个 JSON 对象。所有字段都是可选的,但实际使用中model_file是创建会话的必要条件:

{ "model_file": "model.onnx", "session_options": { "session.intra_op_thread_count": "4", "session.model_external_initializers_file_folder_path": "weights" }, "provider_options": { "device_id": "0" } }
字段类型是否必需说明
model_filestring是(对会话而言)variant 内模型文件的路径。通过ModelPackage_ResolveStringRef解析,以 variant 目录为锚点。接受相对路径、绝对路径或..段(仅限 installed 布局),以及sha256:<hex>[/sub/path]形式的共享资产引用。
session_optionsobjectstring -> string映射。当调用方在CreateSession中传入session_options == NULL时,被合并到一个全新的OrtSessionOptions之上。取值为路径的 key(见IsModelPackagePathSessionOption,如session.model_external_initializers_file_folder_pathep.context_file_path)在解析期就按与model_file相同的规则完成解析。这些路径类 key 在进阶路径下同样生效——前提是调用方自己没有设置它们(见下文)。
provider_optionsobjectstring -> string映射。在默认路径下合并进 variant 的 EP provider options;当调用方自带OrtSessionOptions被忽略

内联 vs 外部形式

该槽位遵循标准executor_info形态,取值有两种:

  • 字符串:指向一个 JSON 文件的路径,文件内容就是上面的对象体(常见做法是在model.onnx旁边放一个ort_info.json);
  • 对象:对象体内联在component.json/manifest.json中。

内联形式让包保持单文件;外部形式(更常见)则让 variant 目录自我描述,并且在executor_infoschema 演进时无需重写 manifest。executor_info下的 key 是执行器命名空间名"ort"),而不是 EP 名——其他消费者各自用自己的命名空间 key,因此同一个 variant 可以并排携带多个消费者的负载。

源码中的解析细节

从 model_package_context.cc 的解析逻辑可以确认几个文档没有展开的实现约束:

  • executor_info["ort"]必须是 JSON 对象,否则直接抛异常;model_file必须是字符串,其值通过ModelPackage_ResolveStringRef解析(must_exist=false,路径在CreateSession时才真正需要存在);
  • session_optionsprovider_options必须是对象,且每个值都必须是字符串,违反会报错;
  • IsModelPackagePathSessionOption当前认定的"路径类" session option key 有三个:session.model_external_initializers_file_folder_pathep.context_file_pathep.context_source_model_path。这些 key 的非空值在解析期即被ModelPackage_ResolveStringRef解析为具体路径,因此 variant 可以在 manifest 中直接写sha256:<hex>或相对路径来引用共享资产里的权重目录。

变体选择(Variant Selection)

EP 意图快照

ModelPackageOptions(env, session_options)捕获的是EP 意图:会话选项上注册的有序执行提供者列表,及其关联的OrtEpDevice/OrtHardwareDevice/ 元数据。从 model_package_options.cc 的ResolveEpSelection可以看到快照的三种来源分支:

  1. 会话选项上有 provider 工厂:逐个调用factory->CreateProvider构建 provider 列表,再从中提取VariantSelectionEpInfo(EP 名、工厂指针、设备列表、元数据);
  2. 未显式指定 EP 但启用了 EP 选择策略(policy):通过ProviderPolicyContext::SelectEpsForModelPackage得到带排序的候选 EP 列表(例如 [CUDA, WebGPU, CPU]);
  3. 既无 EP 也无策略:回退为 CPU EP 参与变体选择。

选择算法

VariantSelector::SelectVariant(component, ep_infos, &selected)遍历组件的变体并挑出最佳匹配:

  1. 只取捕获列表中的第一个 EP。策略可能返回多个 EP 的排序列表;需要指定 EP 的调用方应把它放在第一位(对整个 EP 列表做排序目前是 TODO)。源码在 model_package_variant_selector.cc 中对此有明确注释,并会在捕获到多个 EP 时打一条 INFO 日志说明只使用第一个。
  2. 对每个 variant,要求variant.ep == ep_info.ep_name(EP 名精确匹配);
  3. 若 variant 声明了device"cpu"/"gpu"/"npu"),要求它与该 EP 的某个OrtHardwareDevice条目匹配(MatchesDeviceOrtHardwareDeviceType枚举比对,且大小写不敏感);
  4. 两者都通过后,以variant.compatibility_string调用OrtEpFactory::ValidateCompiledModelCompatibilityInfo。EP 返回一个OrtCompiledModelCompatibility枚举,映射为得分:
枚举得分
EP_SUPPORTED_OPTIMAL100
EP_SUPPORTED_PREFER_RECOMPILATION50
EP_NOT_APPLICABLE(或 EP 过旧 / 未实现该 ABI)0
EP_UNSUPPORTED直接拒绝(源码中映射为 -100,不会入选)
  1. 选取得分最高的匹配 variant。得分相同时,manifest 声明顺序在前者胜出(源码用严格>比较保证平局时保留先出现者)。

若没有任何 variant 匹配,SelectComponent会以错误信息"No suitable model variant found for the configured execution providers."失败——这一文案可直接在 model_package_context.cc 的ResolveVariantImpl中找到。

关于兼容性回调的两个源码级细节值得注意:

  • compatibility_string为空、EP 工厂为nullptr、工厂的ort_version_supported < 23ValidateCompiledModelCompatibilityInfonullptr时,回调被视为不适用,直接给出EP_NOT_APPLICABLE(得分 0);
  • ORT 不解析compatibility_string。该串的格式由 EP 自己拥有,EP 可以在单个字符串内部编码多个子目标(SoC id、ISA 标志等);ORT 只是把它原样回传(round-trip)给 EP 的回调。源码注释还提到一条尚未接线的未来回退链:若 EP 实现了SelectBestCompiledModelCandidate则由 EP 从候选列表中挑选,否则再落到当前的逐 variant 验证方式。

会话创建契约(Session Creation Contract)

入口为OrtModelPackageApi_CreateSession_SinceV28(env, component_ctx, session_options, &session)。此时component_ctx已经知道哪个 variant 赢得了选择、以及应当使用哪个 provider 列表。行为分两条路径:

  • session_options == NULL(默认路径)。ORT 从全新的OrtSessionOptions出发,把 variant 在executor_info["ort"]中的session_options/provider_options合并到其上,manifest 中声明的 EP 会被构建并注册。绝大多数调用方要走这条路径。
  • session_options != NULL(进阶路径)。ORT 原样使用调用方提供的OrtSessionOptions,manifest 里的session_optionsprovider_options不再合并——唯一例外是路径类 session option(IsModelPackagePathSessionOption):对于调用方没有设置的 key,会从 variant 中携带过来,保证一个依赖 external-initializers 目录的模型仍然能加载。当你需要自定义的 EP 配置、且这些配置无法用字符串 option 表达时(共享 CUDA 流、共享 QNN EP 上下文、自定义分配器等),应走这条路径。注意:之前传给CreateModelPackageOptionsFromSessionOptions的那个OrtSessionOptions只驱动变体选择 / EP 发现,不会在这里被悄悄重新应用。

variant 通过在session_options中把session.model_external_initializers_file_folder_path设置为某个目录(相对、绝对或sha256:<hex>共享资产)来让 ORT 找到外部初始化的权重。该值在解析期完成解析,并覆盖模型自身所在目录,因此模型文件可以引用存放在包旁边(或由多个包共享)的权重。

一个源码层面的补充:由于 provider 在注册进会话时会被"消费"(move),ModelPackageComponentContext::RebuildProviderListForSession会在每次会话创建调用时重建 provider 列表;若选中的 EP 是CPUExecutionProvider或没有设备信息,则跳过构建(CPU 是内建 EP,无需注册 provider)。

C API 表面

模型包 API 通过 ONNX Runtime 的实验性 C API机制暴露。每个函数都作为独立条目注册在 onnxruntime_experimental_c_api.inc 中,前缀为OrtModelPackageApi_,版本后缀为_SinceV28。调用方通过OrtApi::GetExperimentalFunction按名查找,直接查找,或经由由onnxruntime_experimental_c_api.h生成的Ort::Experimental::*类型化 C++ 访问器查找。三个不透明句柄类型(OrtModelPackageOptionsOrtModelPackageContextOrtModelPackageComponentContext)在onnxruntime_experimental_c_api.h顶部前向声明。

注册的条目:

函数说明
CreateModelPackageOptionsFromSessionOptions快照 EP 意图。
ReleaseModelPackageOptions释放选项句柄。
CreateModelPackageContext解析 manifest,创建包上下文。
ReleaseModelPackageContext释放包上下文。
ModelPackage_GetSchemaVersion查询 schema 版本。
ModelPackage_GetComponentCount/ModelPackage_GetComponentNames检查组件。
ModelPackage_GetVariantCount/ModelPackage_GetVariantNames/ModelPackage_GetVariantEpName检查组件下的 variant。
SelectComponent解析出最佳匹配 variant,产出组件上下文。
ReleaseModelPackageComponentContext释放组件上下文。
ModelPackageComponent_GetSelectedVariantName/ModelPackageComponent_GetSelectedVariantFolderPath查询选中 variant 的名字与目录。
CreateSession为选中 variant 创建会话。

另外,从 onnxruntime_experimental_c_api.inc 的注册清单还能看到OrtModelPackageApi_ModelPackage_ResolveStringRef条目——它把库的路径解析能力(sha256:URI、相对/绝对路径规则)直接暴露给调用方,供需要自行解析包内引用时使用。

实验性函数不属于稳定 ABI。在提升到稳定OrtApi之前,函数名、签名和行为都可能在版本之间变化。调用方应当对每次查找做 null 检查。

典型调用流程

#include "onnxruntime_c_api.h" #include "onnxruntime_experimental_c_api.h" const OrtApi* ort = OrtGetApiBase()->GetApi(ORT_API_VERSION); auto fn_create_opts = Ort::Experimental::Get_OrtModelPackageApi_CreateModelPackageOptionsFromSessionOptions_SinceV28_Fn(ort); auto fn_release_opts = Ort::Experimental::Get_OrtModelPackageApi_ReleaseModelPackageOptions_SinceV28_Fn(ort); auto fn_create_ctx = Ort::Experimental::Get_OrtModelPackageApi_CreateModelPackageContext_SinceV28_Fn(ort); auto fn_release_ctx = Ort::Experimental::Get_OrtModelPackageApi_ReleaseModelPackageContext_SinceV28_Fn(ort); auto fn_select = Ort::Experimental::Get_OrtModelPackageApi_SelectComponent_SinceV28_Fn(ort); auto fn_release_comp = Ort::Experimental::Get_OrtModelPackageApi_ReleaseModelPackageComponentContext_SinceV28_Fn(ort); auto fn_create_session = Ort::Experimental::Get_OrtModelPackageApi_CreateSession_SinceV28_Fn(ort); OrtSessionOptions* so = nullptr; ort->CreateSessionOptions(&so); ort->SessionOptionsAppendExecutionProvider(so, "CUDAExecutionProvider", nullptr, nullptr, 0); OrtModelPackageOptions* mp_opts = nullptr; fn_create_opts(env, so, &mp_opts); OrtModelPackageContext* ctx = nullptr; fn_create_ctx(ORT_TSTR("/path/to/pkg"), &ctx); OrtModelPackageComponentContext* comp_ctx = nullptr; fn_select(ctx, "decoder", mp_opts, &comp_ctx); OrtSession* session = nullptr; fn_create_session(env, comp_ctx, nullptr, &session); ort->ReleaseSession(session); fn_release_comp(comp_ctx); fn_release_ctx(ctx); fn_release_opts(mp_opts); ort->ReleaseSessionOptions(so);

指针生命周期约定:API 返回的所有const char*/const ORTCHAR_T*/ 数组指针都由产生它们的上下文所有,在该上下文被释放之前保持有效。从源码实现看,上下文内部为 C API 专门维护了指针缓存(如component_name_ptrs_cache_session_option_key_ptrs_cache_等),把std::stringc_str()固化下来,使得返回值不会因内部缓存刷新而悬空,其有效期与上下文一致。

延伸阅读

  • model_package/README.md:包格式、manifest/component schema、共享资产、路径解析规则、C 编写 API,以及executor_info扩展点的完整定义;
  • docs/design/Experimental_C_API.md:承载这些条目的实验性 C API 机制的设计与生命周期规则;
  • onnxruntime_experimental_c_api.inc:OrtModelPackageApi_*条目的权威清单;
  • onnxruntime/core/session/model_package_api.cc:C 入口点的实现(OrtExperimentalApis命名空间)。

【免费下载链接】onnxruntimeONNX Runtime: cross-platform, high performance ML inferencing and training accelerator项目地址: https://gitcode.com/GitHub_Trending/on/onnxruntime

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询