章节摘要:Execution Provider 是 ORT 与硬件之间的插件层。本章覆盖 EP 接口、CUDA/TensorRT/DML 选型与 Custom Op 扩展。
第2章分区把图切成子图,第3章回答三个问题:子图最终由谁执行、按什么优先级、硬件能力不够时怎么办。EP(Execution Provider)是 ORT 的硬件抽象层——每个 EP 声明自己能跑哪些算子、如何分配设备内存、如何把子图编译成原生执行计划。理解 EP,就是理解"同一份 ONNX 在 CPU、CUDA、TensorRT、DirectML 上行为不同的根本原因"。
本章三节:3.1 讲 EP 接口契约与 providers 优先级;3.2 讲三种主力 EP(CUDA、TensorRT、DirectML)的选型与配置;3.3 讲标准算子覆盖不了时如何用 Custom Op 扩展。三节合起来覆盖日常部署 90% 的 EP 相关操作。
| EP | 平台 | 特性 | 适用 |
|---|---|---|---|
| CPU (MLAS) | 全平台 | 兜底、无额外依赖 | 开发、回退 |
| CUDA | NVIDIA | cuDNN/cuBLAS,节点级接管 | GPU 通用推理 |
| TensorRT | NVIDIA | 子图编译、层融合 | 极致延迟 |
| DirectML | Windows | DX12,无需 CUDA | Windows 桌面/笔记本 |
| CoreML | Apple | ANE/GPU | iOS/macOS |
| OpenVINO | Intel | CPU/iGPU/VPU | Intel 平台 |
选型铁律:先确认目标平台与 ORT build,再谈配置。CPU 版 wheel 里根本没有 CUDA/TRT/DML EP,配置了也会静默回退到 CPU——这类问题用 get_providers() 一分钟就能暴露。
| 节 | 主题 | 核心问题 | 关键产出 |
|---|---|---|---|
| 3.1 | EP 接口与优先级策略 | 配置了 EP 为何没生效 | get_providers 验证流程 |
| 3.2 | CUDA/TensorRT/DML 选型 | 三种 EP 何时用哪个 | 平台选型矩阵 |
| 3.3 | 自定义算子扩展 | 标准算子覆盖不了怎么办 | Custom Op 注册链路 |
不要凭喜好选 EP,按平台与约束逐层收窄。决策顺序:先定平台(Linux GPU / Windows 桌面 / 边缘 ARM / 浏览器),再定延迟预算(能否接受秒级首启),最后看环境成本(能否装 CUDA/TensorRT)。每一步都在缩小选项:
| 平台 | 首选 EP | 次选 | 兜底 |
|---|---|---|---|
| Linux NVIDIA 服务器 | TensorRT | CUDA | CPU |
| Linux AMD 服务器 | ROCm | CPU | — |
| Windows 桌面/笔记本 | DirectML | CPU | — |
| Jetson / 边缘 ARM | CUDA | CPU | — |
| iOS / macOS | CoreML | CPU | — |
| 浏览器 | WebAssembly | CPU | — |
选定后按本节骨架配置 providers 顺序与专有选项,跑一次 get_providers() 验证,再进入 3.2 的精细调优。
EP 不是独立的:CUDA EP 依赖 CUDA/cuDNN 版本,TensorRT EP 依赖 TensorRT 库版本,三者与 onnxruntime-gpu 的版本必须落在官方兼容矩阵内。版本不匹配的表现很隐蔽——不是报错,而是 EP 静默不激活或某个算子回退 CPU。排查 EP 问题时,把三个版本号一并收集:
| 组件 | 关注点 | 失败形态 |
|---|---|---|
| onnxruntime-gpu | 与 CUDA 大版本配套 | EP 不激活 |
| CUDA / cuDNN | 驱动与库路径 | 启动时链接错误 |
| TensorRT | 与 ORT 支持版本对齐 | TRT EP 缺能力 |
| Python wheel | cpu/gpu 是否混装 | providers 列表异常 |
# 收集版本信息,用于对齐兼容矩阵 python -c "import onnxruntime; print(onnxruntime.__version__)" python -c "import onnxruntime as ort; print(ort.get_device())"
get_providers() 的静默回退trt_engine_cache_enable 后重启进程,对比第二次创建耗时