登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  科技周边 >  人工智能

ONNX Runtime 怎样选择 CPU 与 CUDA provider

来源:17golang原创

时间:2026-10-24 20:25:58 246浏览 收藏

ONNX Runtime 选择 CPU 还是 CUDA,关键不在于“机器有没有显卡”,而在于安装包是否提供对应 provider、会话的 provider 顺序怎样写,以及 CUDA/cuDNN 运行库是否匹配。CPU-only 部署使用 onnxruntime;NVIDIA 推理通常使用 onnxruntime-gpu,并显式写成 CUDA 优先、CPU 回退。

官方地址:https://onnxruntime.ai/。本文只讨论 Python 的 CPUExecutionProvider、CUDAExecutionProvider 和 InferenceSession 配置,示例输出是读者运行后应观察的形态,不把静态代码图或推导结果当作本机实测。

简单选择规则:没有 NVIDIA CUDA 运行环境就固定 CPU;有匹配的 CUDA/cuDNN 和 GPU 包就把 CUDA 放在 providers 首位,并保留 CPU 作为明确的回退项。不要只凭显卡型号猜 provider 一定可用。

先把 provider 选择拆成硬件、安装包和优先级

Execution Provider 可以理解为 ONNX Runtime 执行算子的一组后端能力。CPU provider 是默认的通用路径,CUDA provider 面向 NVIDIA CUDA 设备。调用方真正要做的是同时回答三个问题:部署目标是什么、Python 装了哪个包、当某个算子不由首选后端执行时是否允许回退。

部署条件安装方向会话写法
没有 CUDA 依赖或希望环境最简单onnxruntime["CPUExecutionProvider"]
NVIDIA GPU 且 CUDA/cuDNN 与包匹配onnxruntime-gpu["CUDAExecutionProvider", "CPUExecutionProvider"]
同一程序需要可控地切换按部署镜像分别安装启动时根据能力选择列表

这里的顺序是参数语义,不是装饰:列表前面的 provider 优先级更高。CUDA 能执行的节点优先交给 CUDA;没有合适 CUDA kernel 的节点才有机会交给后面的 CPU provider。若你只传 CUDA,环境或模型不满足条件时,初始化错误通常会比显式回退更早暴露。

ONNX Runtime CPU 与 CUDA provider 的安装包、硬件和优先级关系说明图
图1:provider 选择关系说明图,展示硬件目标、安装包和优先级的边界,不是运行截图。

用 get_available_providers 判断当前安装能提供什么

部署脚本先读取已安装版本注册的 provider,比直接读取操作系统里的显卡信息更接近 ONNX Runtime 自己的能力视角。最小检查代码如下:

import onnxruntime as ort

# 这个列表反映当前安装包注册的执行后端,不等于模型已经跑过
available = ort.get_available_providers()
print("available providers:", available)

# CUDA 只有在列表中出现时才进入 CUDA 优先策略
if "CUDAExecutionProvider" in available:
    providers = ["CUDAExecutionProvider", "CPUExecutionProvider"]
else:
    # 没有 CUDA 能力时保持显式 CPU 路径,避免依赖隐式默认值
    providers = ["CPUExecutionProvider"]

print("selected providers:", providers)

这个判断只能说明 provider 已注册,不能替代会话初始化和实际模型推理。列表中有 CUDA 并不代表每个模型节点、每个输入形状或每次部署的动态库都没有问题;它只是把“当前安装能看到哪些后端”这件事从猜测变成了可记录的配置输入。

显式设置 CUDA 优先、CPU 回退

在推理会话里把顺序写出来,调用方的策略才稳定。下面的函数把“优先 GPU、允许 CPU 接住不适配节点”封装成一个小接口:

from pathlib import Path
import onnxruntime as ort

def create_session(model_path: str) -> ort.InferenceSession:
    # 先检查注册能力,再决定会话列表;不要把 GPU 当成必然条件
    available = set(ort.get_available_providers())
    if "CUDAExecutionProvider" in available:
        providers = ["CUDAExecutionProvider", "CPUExecutionProvider"]
    elif "CPUExecutionProvider" in available:
        providers = ["CPUExecutionProvider"]
    else:
        raise RuntimeError("当前 ONNX Runtime 没有可用的 CPU/CUDA provider")

    # providers 的前后顺序表达优先级,前者不可用的节点才考虑后者
    return ort.InferenceSession(Path(model_path), providers=providers)

session = create_session("model.onnx")
print(session.get_providers())  # 输出会话登记的 provider 顺序

get_available_providers() 是能力发现,session.get_providers() 是会话登记结果,两者用途不同。若项目要求“必须使用 CUDA”,可以把缺少 CUDA 的分支改成启动失败;若项目需要在 CPU 机器上也能工作,保留上述回退分支更符合调用方体验。

只需要 CPU 时直接固定 CPU provider

批处理、轻量服务或没有 NVIDIA 依赖的镜像,不必为了“代码看起来通用”保留 CUDA 选择。固定 CPU 有三个好处:部署包更小,启动不需要查找 CUDA 动态库,性能问题也更容易和线程数、模型结构区分。

import onnxruntime as ort

# CPU-only 镜像使用明确列表,避免宿主机残留 provider 改变行为
session = ort.InferenceSession(
    "model.onnx",
    providers=["CPUExecutionProvider"],
)

# 用模型输入名构造最小调用;真实输入需按模型的 dtype 和 shape 准备
input_name = session.get_inputs()[0].name
print("provider order:", session.get_providers())
print("input name:", input_name)

不要把 get_device() 的结果直接当作 provider 选择器,也不要只因为代码运行在带 GPU 的宿主机就换成 GPU 包。provider 选择属于部署契约,应当随镜像、依赖锁定文件和启动配置一起管理。

遇到 CUDA 初始化失败先查版本契约

如果 CUDA provider 注册失败或会话初始化报动态库错误,优先检查安装包、CUDA 和 cuDNN 的组合。官方文档当前说明:GPU 包需要 CUDA 与 cuDNN;CUDA 11.x、12.x、13.x 对应的 ONNX Runtime 构建要求不同,cuDNN 8.x 与 9.x 也不能混用。具体小版本要以目标 ONNX Runtime 版本的兼容表为准。

排查顺序可以压缩成四项:

  1. 确认当前环境安装的是 onnxruntime 还是 onnxruntime-gpu,避免两个包同时存在造成导入和依赖判断混乱。
  2. 记录 ort.__version__ 与 ort.get_available_providers(),先确认包本身暴露了什么。
  3. 对照官方 CUDA EP 兼容表检查 CUDA 和 cuDNN 主版本,以及 Linux 的 LD_LIBRARY_PATH 或 Windows 的 PATH。
  4. 明确产品策略:必须 GPU 就让初始化失败可见;允许降级就使用 CUDA 优先、CPU 回退,并记录最终会话 provider。
ONNX Runtime CUDA provider 的能力发现、CUDA与cuDNN依赖和会话回退结构图
图2:CUDA provider 依赖边界结构图,说明兼容关系与回退判断,不是实测输出。

官方安装与兼容说明可复制查看:https://onnxruntime.ai/docs/install/;Python API:https://onnxruntime.ai/docs/api/python/api_summary.html;CUDA provider:https://onnxruntime.ai/docs/execution-providers/CUDA-ExecutionProvider.html。这些页面会随版本更新,不能把某次安装经验固化成所有版本的规则。

把选择规则收敛成一张部署清单

最后可以按这张清单落地:CPU-only 镜像安装 onnxruntime 并固定 CPU;NVIDIA 镜像安装与 CUDA/cuDNN 匹配的 onnxruntime-gpu,把 CUDA 放在 provider 首位;启动时记录可用列表和会话列表;必须 GPU 的服务拒绝静默降级,允许混合执行的服务才保留 CPU 回退。

为什么机器有显卡却没有 CUDAExecutionProvider?

显卡存在不等于当前 Python 包注册了 CUDA provider。先看安装包、CUDA/cuDNN 动态库和版本兼容关系,再看 provider 列表。

providers 只写 CUDA 可以吗?

可以,但这表示你接受 CUDA 必须可用且相关节点必须能由它处理。需要稳定降级时,把 CPUExecutionProvider 放在后面更清楚。

CPU provider 是不是只能在没有 GPU 时使用?

不是。它可以作为 CUDA 不支持节点的回退后端,也可以在 CPU-only 部署中作为唯一后端;是否启用取决于会话列表和应用策略。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>