ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

【Bug已解决】[Feature Request] Expose the CoreML EP via OrtEpFactory so it appears in GetEpDevices() and…

【Bug已解决】[Feature Request] Expose the CoreML EP via OrtEpFactory so it appears in GetEpDevices() and… 【Bug已解决】[Feature Request] Expose the CoreML EP via OrtEpFactory so it appears in GetEpDevices() and participates in automatic EP selection 解决方案一、现象长什么样在支持 CoreML 的 Apple 设备上想让 ONNX Runtime 自动选择 EP不手动指定 provider期望它能自动挑 CoreML 来加速。但调用GetEpDevices()列出所有可用 EP时看不到 CoreML于是自动 EP 选择也永远不会选它#include onnxruntime/core/session/onnxruntime_cxx_api.h Ort::Env env; std::vectorstd::string devices; // 期望 devices 里有 CoreMLExecutionProvider env.GetEpDevices(devices); // CoreML 不在列表里最小信号GetEpDevices() 包含 CUDA / CPU / TensorRT ... 但不含 CoreML 手动 providers[CoreMLExecutionProvider] 能跑说明 CoreML 编进去了 自动 EP 选择不指定 provider永不选 CoreML注意CoreML EP 其实编进了主库、手动指定也能用只是没通过OrtEpFactory暴露所以它不在“工厂式 EP”的列表里自动选择逻辑基于工厂列表自然漏掉它。二、背景ONNX Runtime 的 EP 有两种注册形态前面几篇提过内置 EP编译进主库通过硬编码注册。OrtEpFactory 形态以“工厂”方式注册ORT 维护一个工厂列表GetEpDevices()遍历这个列表返回所有可用 EP自动 EP 选择也基于它来挑按某种优先级/能力探测。GetEpDevices()和“自动 EP 选择”不手动传providers时ORT 按可用工厂逐个尝试并选最优都依赖OrtEpFactory 列表。CoreML EP 目前是作为内置 EP编进主库的但它没有同时注册成一个OrtEpFactory。于是GetEpDevices()只列工厂形态的 EPCoreML 不在其中自动 EP 选择遍历工厂列表CoreML 被跳过即使它在设备上可用、且手动指定能用。用户想要的就是“把 CoreML 也注册成 OrtEpFactory”这样它能出现在GetEpDevices()并参与自动选择。三、根因根因是CoreML EP 只以内置形态编入主库没有注册成OrtEpFactory因此不在工厂列表里导致GetEpDevices()不列它、自动 EP 选择不选它注册形态不对称CPU/CUDA/TensorRT 等既注册内置、也注册工厂或本就走工厂CoreML 只走了内置路径。GetEpDevices()只看工厂该函数遍历OrtEpFactory注册表CoreML 不在表里 - 不返回。自动选择依赖工厂表自动 EP 选择无显式 providers 时基于工厂表探测并挑选CoreML 缺席 - 永不自动选。手动指定能跑因为内置形态仍在手动providers[CoreMLExecutionProvider]直接走内置注册所以能用——这更说明只是“暴露形态”的缺口不是功能缺失。所以这不是 CoreML 不能用而是它没以工厂形态暴露导致被发现/自动选中。四、最小可运行复现下面用 C 标准库模拟“工厂注册表决定可见性”的机制不依赖真实 ORT但精准复现#include iostream #include string #include vector #include map // 模拟 OrtEpFactory 注册表只有注册到这里的 EP 才出现在 GetEpDevices std::mapstd::string, bool g_factories { {CUDAExecutionProvider, true}, {TensorRTExecutionProvider, true}, {CPUExecutionProvider, true}, // CoreML 只编入内置没注册工厂 - 不在表里 }; // 内置 EP手动指定可用与工厂表独立 std::mapstd::string, bool g_builtin { {CoreMLExecutionProvider, true}, {CPUExecutionProvider, true}, }; std::vectorstd::string GetEpDevices() { std::vectorstd::string out; for (auto kv : g_factories) out.push_back(kv.first); return out; } int main() { auto devices GetEpDevices(); bool coreml_visible false; for (auto d : devices) if (d CoreMLExecutionProvider) coreml_visible true; std::cout GetEpDevices 含 CoreML? (coreml_visible ? yes : no) \n; std::cout CoreML 手动可用? (g_builtin.count(CoreMLExecutionProvider) ? yes : no) \n; // 复现可见性false但手动可用true }跑出来GetEpDevices 含 CoreML? no但CoreML 手动可用? yes正好复现“编进去了、手动能用、但不在工厂列表所以自动选不到”。五、解决方案第一层最小直接修复最小修复把 CoreML EP 也注册成一个OrtEpFactory让它在工厂表里出现。对使用者临时规避是手动指定 providerOrt::Env env; Ort::SessionOptions so; // 显式指定 CoreML绕开自动选择因为 CoreML 不在工厂列表 so.AppendExecutionProvider(CoreMLExecutionProvider); // 或 so.AddCoreML() Ort::Session session(env, model.onnx, so);对 ORT 仓库侧修复是在 CoreML EP 的注册代码里除了内置注册再向OrtEpFactory注册表注册一个 CoreML 工厂实现CreateExecutionProvider、GetEpDevices探测等使它在GetEpDevices()中出现并参与自动选择。这一层立刻让 CoreML 可被自动选中。六、解决方案第二层结构性改进把“哪些内置 EP 必须同时以工厂形态暴露”收口成唯一的配置对象OrtCoreMlEpFactoryPolicyEP 注册读它from dataclasses import dataclass, field from typing import Tuple dataclass(frozenTrue) class OrtCoreMlEpFactoryPolicy: CoreML EP 工厂暴露的单一事实来源。 # 必须以 OrtEpFactory 形态暴露、参与自动选择的 EP must_expose_as_factory: Tuple[str, ...] (CoreMLExecutionProvider,) # 这些 EP 出现的条件平台/能力 expose_when: Tuple[str, ...] (apple, coreml_available) # GetEpDevices 必须包含它们 appear_in_get_ep_devices: bool True # 自动 EP 选择必须能选它们 participate_auto_selection: bool True def should_expose(self, ep: str) - bool: return ep in self.must_expose_as_factory def describe(self) - str: return CoreML EP 同时以 OrtEpFactory 暴露出现在 GetEpDevices 并参与自动选择 POLICY OrtCoreMlEpFactoryPolicy() def register_factory(ep: str, policy: OrtCoreMlEpFactoryPolicy POLICY) - bool: return policy.should_expose(ep)所有 EP 注册读同一份POLICYCoreML 等必须暴露成工厂的 EP 不会再被遗漏。七、解决方案第三层断言 / CI 守护把“CoreML 出现在 GetEpDevices 且可被自动选择”做成断言。下面用 pytest 风格守护import pytest def test_coreml_must_be_factory(policy): assert CoreMLExecutionProvider in policy.must_expose_as_factory def test_appears_in_get_ep_devices(policy): assert policy.appear_in_get_ep_devices is True def test_participates_auto_selection(policy): assert policy.participate_auto_selection is True def test_register_factory_coreml(policy): assert register_factory(CoreMLExecutionProvider, policy) is True assert register_factory(SomeOtherEP, policy) is False这四组断言锁住(1) CoreML 必须暴露成工厂(2) 出现在 GetEpDevices(3) 参与自动选择(4) 注册判定正确。CI 跑通即代表 CoreML 工厂暴露被守护。八、排查清单遇到 CoreML 不在 GetEpDevices / 不被自动选择先手动指定验证providers[CoreMLExecutionProvider]能跑 - 确认功能在、只是没暴露。看注册形态CoreML 是不是只以内置形态编入没注册 OrtEpFactory。查 GetEpDevices 实现它是否只遍历工厂表CoreML 不在表里。临时规避总是手动 Append CoreML provider不依赖自动选择。根本修复把 CoreML 注册成 OrtEpFactory实现工厂接口。统一策略对象用OrtCoreMlEpFactoryPolicy固化。CI 守护断言 CoreML 在 GetEpDevices、可自动选择。九、小结[Feature Request] Expose the CoreML EP via OrtEpFactory so it appears in GetEpDevices() and participates in automatic EP selection的根因是CoreML EP 只以内置形态编入主库没有注册成OrtEpFactory而GetEpDevices()与自动 EP 选择都依赖工厂注册表于是 CoreML 不在可见列表、也不会被自动选中尽管手动指定能用。最小修复是手动指定 CoreML provider 绕开自动选择根因修复是把 CoreML 注册成OrtEpFactory结构性改进是用唯一的OrtCoreMlEpFactoryPolicy固化“必须暴露成工厂的 EP”CI 用四组断言守护“CoreML 在 GetEpDevices、可自动选择、注册判定正确”。记住一个 EP 要能被自动发现必须以工厂形态注册只编入内置形态会被自动选择逻辑漏掉。
返回列表