ONNX Runtime GPU推理部署指南:Windows x64环境从配置到调优
发布时间:2026/9/30 10:01:00来源:尧图网络
简介onnxruntime-win-x64-gpu-1.18.0.zip 是面向 Windows x64 的 ONNX Runtime GPU 版推理库专为需要在 C 工程中部署深度模型的开发者准备。借助 NVIDIA CUDA 并行能力它能明显加速图像识别、语音处理、NLP 等计算密集型任务的推理过程同时兼容 PyTorch、TensorFlow 等框架导出的 ONNX 模型实现跨框架统一推理。压缩包共 35 个文件、约 201.61 MB包括 16 个头文件、4 个 DLL、4 个 LIB、4 个 PDB 调试符号以及 README、License、版本号等文档。include 目录含有完整 C API 声明lib 目录提供链接所需的导入库和运行库VERSION_NUMBER、GIT_COMMIT_ID 便于追溯构建版本LICENSE 与第三方声明则明确了合规信息。已有 849 人学习下载。include 与 lib 目录划分清晰方便 Visual Studio 等项目配置头文件索引和库链接VERSION_NUMBER、GIT_COMMIT_ID 及 README 又能帮助核对 CUDA/cuDNN 兼容版本降低环境适配与排错难度。配合 LICENSE 等合规文档可以直接集成到 C 工程中用于高性能 GPU 推理场景。1. onnxruntime-win-x64-gpu-1.18.0.zip 出现在桌面上时多半是你刚把 PyTorch 模型导出成 ONNX正愁 Windows 上的 GPU 推理怎么落地。这个 zip 不是模型也不是安装器而是 ONNX Runtime 在 Windows x64 NVIDIA GPU 平台的预编译推理引擎里面有运行时 dll、C/C 头文件、导入库和 CUDA provider 动态库。它解决部署阶段最烦的三件事不用从源码编译 ONNX Runtime、把推理从 CPU 挪到 GPU、让 C 程序直接链接一份本地动态库。适合两类人做 C 桌面端或服务端集成的工程师以及想绕开复杂 pip 环境、直接控制 dll 的 Python 用户。注意它只适配 x64ARM64 机器得另找对应包。2. 解压与前置环境CUDA、cuDNN、DLL 和 PATH 一个都不能少拿到 zip 之后的第一件事不是双击解压然后到处拷而是先把解压目录、运行库版本和系统 PATH 理清楚。这一层没弄明白后面所有代码都会在“找不到 dll”和“用不上 GPU”之间反复横跳。2.1 包内文件结构dll、lib、include 各管什么解压之后你会看到 include 和 lib 两个主目录部分版本会把 dll 平铺在根目录。include 下面是一堆头文件核心是 onnxruntime_c_api.h 和 onnxruntime_cxx_api.h它们只服务于编译期lib 目录是整个包的价值所在运行期真正需要的是下面这四个文件。文件作用部署时是否必须onnxruntime.dll核心运行时提供 C/C API 的实际实现必须onnxruntime_providers_cuda.dllCUDA 执行提供程序调用 GPU 算子必须GPU 场景onnxruntime_providers_shared.dllprovider 公共基础设施必须onnxruntime.libMSVC 链接器导入库仅编译期需要include/onnxruntime_cxx_api.hC API 头文件仅编译期需要这里最容易翻车的是只把 onnxruntime.dll 当作“整个运行时”发布安装包的时候漏了 provider 相关的两个 dll。程序在自己的机器上能跑一换到干净环境就只有 CPU。还有一个隐藏依赖onnxruntime.dll 自身依赖 VC 运行库缺了 vcruntime140.dll 和 msvcp140.dll程序会在启动瞬间报错而不是进入推理逻辑。所以部署清单里除了上面四个文件系统级的 VC redistributable 也必须带上。2.2 1.18.0 对应的 CUDA/cuDNN 版本先对表再动手1.18.0 这个版本号的预编译 GPU 包官方是按 CUDA 11.8 工具链构建的配套 cuDNN 8.x。你机器上如果只有 CUDA 12.x 的 runtime直接拿 1.18.0 的包来跑大概率是“dll 能加载但 provider 起不来”。我一般拿到包之后先做三件事看驱动版本、看 CUDA 版本、看 cuDNN 是否存在。组件推荐组合核对方式NVIDIA 驱动525 及以上nvidia-smi 第一行 Driver VersionCUDA Toolkit11.8nvcc --versioncuDNN8.x检查 cudnn64_8.dll 是否在 PATHVC 运行库14.30 及以上系统更新或安装 vc_redist.x64.exe驱动是向下兼容的你装了新驱动不代表不能用旧的 CUDA runtime。但 nvcc 没有装也没关系运行时只需要 cudart64_110.dll 和 cuDNN 的 dll 能被系统找到整套 CUDA Toolkit 安装下来一般都会带齐。验证命令就两条nvidia-smi nvcc --versionnvcc 不存在时不用慌继续检查 C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\ 下有没有对应版本目录把该目录的 bin 和 cuDNN 的 bin 都加进 PATH 即可。如果你已经用上了 CUDA 12.x建议直接换 1.19 之后的 onnxruntime 包别再跟 1.18.0 较劲跨大版本混跑是典型的“能加载但不工作”的玄学问题。2.3 把 DLL 目录加进 PATH两种做法与验证方法PATH 配置有两种方式。方式一是永久写入用户环境变量适合固定开发机和部署机方式二是在进程内临时指定适合嵌入到安装包或服务里不污染全局。:: 永久写入用户 PATH新开终端生效 setx PATH %PATH%;C:\ort\lib :: 当前终端临时生效 set PATHC:\ort\lib;%PATH%setx 有一个隐藏的坑它会展开当前 PATH 原值再写回如果 PATH 本身很长存在截断风险。所以我更推荐在系统设置里手动粘贴这一条而不是反复 setx。Windows 的 PATH 环境变量有长度上限喜欢把所有 dll 目录都堆在里面的人总有一天会遇到程序找不到根本不可能找不到的文件。Python 侧更推荐用进程内方式import os # Python 3.8 可用把 DLL 搜索路径指向 zip 解压目录 os.add_dll_directory(rC:\ort\lib)这个调用只对当前 Python 进程里的动态库加载生效不会影响其它程序也不会污染 PATH。配置完之后用where onnxruntime.dll验证能输出来自 C:\ort\lib 的路径说明加载器能找到它。注意别在同一个 PATH 里放两个不同版本的 onnxruntime 目录Windows 加载 dll 是按搜索顺序取第一个命中的版本混了之后报错信息会指向一些根本不在你代码里的符号排查成本极高。2.4 它和 pip 的 onnxruntime-gpu 是什么关系先澄清一个概念ONNX 文件只是模型的中间表示它本身不会算任何东西ONNX Runtime 才是那个把模型读进来、调度算子、真正执行推理的引擎。这个 zip 和 pip 的 onnxruntime-gpu 是同一个引擎的两种交付形态版本对应时行为完全等价。区别在于使用方式。pip 包安装到 site-packages由 Python 的依赖管理统一控制zip 包可以放在任意路径拷进安装包、塞进 Docker 镜像、配合 C 或 C# 程序使用都不受限。离线部署时我一般会刻意避开 pip 二次下载依赖直接把 zip 解压后的 lib 目录打成安装包的一部分这就是 zip 包最大的存在理由。还有一个常见误区是觉得文件名带 x64 就能通吃 64 位系统。ARM64 和 x64 的指令集完全不同Windows on ARM 上跑这个包会被加载器直接拒绝具体表现是 exe 启动报“试图加载格式不正确的程序”。在 ARM64 设备上做部署需要单独找 ARM64 版本的 onnxruntime 包不是改个文件名能解决的事。3. 用 Python 和 C 把这份 zip 跑起来两条接入路径前置环境就绪之后接入方式分两条线。Python 用户想快速验证模型能不能在 GPU 上跑C 用户关心的是链接和分发。两条线我都会给最小可运行代码以及代码跑完之后判断“真的用了 GPU”的方法。3.1 Python 侧让 session 优先加载本地 dll 的最小代码假设你已经 pip 安装了 onnxruntime-gpu 1.18.0只是想让运行时的 dll 从 zip 解压目录加载那核心是 os.add_dll_directory。它解决的是“dll 明明在机器上系统却找不到”的典型问题。import os import onnxruntime as ort # 让加载器优先从 zip 包解压目录找同名 dll os.add_dll_directory(rC:\ort\lib) session_options ort.SessionOptions() # 开全部图优化常量折叠、算子融合、冗余去除 session_options.graph_optimization_level ort.EnableGraphOptimizationLevel.ORT_ENABLE_ALL session ort.InferenceSession( model.onnx, sess_optionssession_options, providers[CUDAExecutionProvider, CPUExecutionProvider], ) print(session.get_providers())providers 参数是数组顺序就是优先级。CUDAExecutionProvider 排前面加载失败时 onnxruntime 会自动落到 CPUExecutionProvider所以这个顺序既是加速配置也是兜底机制。get_providers() 输出列表里第一个是 CUDAExecutionProvider说明 session 实际挂载成功。如果你的 pip 包和 zip 包版本不一致这里可能会加载到另外一份 dll行为会变得不可预期所以务必保持版本一致。Windows 7 就别折腾了1.18.0 已经在系统支持上放弃老平台浪费时间。3.2 C 侧链接 onnxruntime.lib 的最小工程C 集成才是这个 zip 包的主场。最小工程包含三个部分头文件、导入库、运行时 dll。下面是一个能跑通的最小示例。#include onnxruntime/core/session/onnxruntime_cxx_api.h #include cstdio int main() { Ort::Env env(ORT_LOGGING_LEVEL_WARNING, ort-gpu-demo); Ort::SessionOptions opt; opt.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_ALL); // 第一个参数是 device_id默认 0多卡时显式传第几张 Ort::ThrowOnError(OrtSessionOptionsAppendExecutionProvider_CUDA( static_castOrtSessionOptions*(opt), 0)); Ort::Session session(env, model.onnx, opt); auto input_info session.GetInputNameAllocated(0, Ort::Allocator::GetWithDefault()); std::printf(input: %s\n, input_info.get()); return 0; }CMake 配置如下cmake_minimum_required(VERSION 3.20) project(ort_demo CXX) set(ORT_HOME C:/ort) add_executable(ort_demo main.cpp) target_include_directories(ort_demo PRIVATE ${ORT_HOME}/include) target_link_directories(ort_demo PRIVATE ${ORT_HOME}/lib) target_link_libraries(ort_demo PRIVATE onnxruntime)这里链接的 onnxruntime 对应 onnxruntime.lib编译期用导入库就够了运行时会去搜索 onnxruntime.dll。有三个方式让程序找到 dll拷到 exe 同目录、PATH 加 lib 目录、或者在代码里用绝对路径加载。注意 Debug 和 Release 别混用CMake 默认如果是 Debug 生成但 onnxruntime.lib 是 Release 编译的链接阶段会报一些关于 _ITERATOR_DEBUG_LEVEL 不匹配的莫名错误把生成配置切成 Release 就安静了。头文件里如果暴露了 C 版本的 AppendExecutionProvider_CUDA也可以直接用但 C API 版本更保守跨小版本兼容性更好。3.3 三个输出确认 GPU provider 真正生效很多人代码写完看到不报错就以为在跑 GPU其实经常是“安全降级到 CPU”。我习惯检查三个输出全部满足才算真的生效。import onnxruntime as ort print(available:, ort.get_available_providers()) # [CPUExecutionProvider, CUDAExecutionProvider] 表示 provider dll 可加载 sess ort.InferenceSession( model.onnx, providers[CUDAExecutionProvider, CPUExecutionProvider], ) print(active:, sess.get_providers()[0]) # active: CUDAExecutionProvider 表示当前 session 用的是 CUDA第一个输出是 get_available_providers()它告诉你引擎编译时带了哪些 provider如果 CUDAExecutionProvider 根本没出现说明 provider dll 依赖的 CUDA 库缺失问题出在环境而不是代码。第二个输出是 get_providers()[0]告诉你这个 session 实际选中了谁。第三个是行为确认打开任务管理器的“GPU 引擎”列跑推理时能看到 3D 或 Compute 引擎利用率跳动或者用 profiler 看每次 run 被哪个 provider 接管。session_options.enable_profiling True # run 之后生成 onnxruntime_profile_*.json这个 profiler 输出的 json 文件里会记录每个算子在哪类设备上执行看到 CUDA 相关的 kernel 名字才算盖章确认。前两个输出是软件层面第三个是事实层面我一般三个都过一遍。如果 available 列表里没有 CUDA优先回去查 cuDNN 的 dll 是否在 PATH而不是怀疑代码。3.4 保留 CPU 回退别让 CUDA 崩掉整个服务在服务端部署时依赖自动降级有个隐患CUDA 能加载但显存分配失败时session 创建阶段会直接抛异常进程可能跟着挂掉。自动回退只在“provider 加载失败”时生效不会帮你处理“加载成功但资源不足”的情况。providers [CUDAExecutionProvider, CPUExecutionProvider] try: session ort.InferenceSession(model.onnx, providersproviders) except Exception as exc: print(CUDA init failed:, exc) session ort.InferenceSession(model.onnx, providers[CPUExecutionProvider])这块的真正价值在于它把“模型能不能用 GPU”变成显式决策。生产环境我一般把 provider 列表做成配置项模型加载失败时明确报错而不是悄悄用没硬件加速的 CPU 扛着否则线上延迟异常时你根本不知道模型在用什么设备跑。4. GPU 推理调优从“能跑”到“跑满”的几个必调参数session 能创建、GPU provider 能挂载只是起步。实际部署时如何让 GPU 利用率上去、显存不爆、延迟稳定这才是 onnxruntime 和 onnx 这类推理框架真正拉开差距的地方。下面四个参数组是我每次部署都会过一遍的。4.1 SessionOptions图优化和并行执行该开哪档SessionOptions 控制的是整个会话的行为第一优先级是图优化级别。默认级别不差但做 GPU 推理时我一般直接开到 ORT_ENABLE_ALL它会做常量折叠、算子融合和冗余消除对推理延迟的影响是实打实的。选项默认建议说明graph_optimization_levelORT_ENABLE_BASICORT_ENABLE_ALL收益明显风险很小execution_modeORT_SEQUENTIAL小模型用 SEQUENTIAL并行执行不适合小模型intra_op_num_threads物理核数保持默认控制单算子内并行度inter_op_num_threads1保持默认并行执行多个图节点ExecutionMode 有两个值ORT_SEQUENTIAL 和 ORT_PARALLEL。并行模式听着更快实际上只适合图中存在大量可并行分支的情况。一个 20 MB 以内的模型并行调度的开销可能大于收益延迟反而变差。我一般是先跑 SEQUENTIAL再用 profiler 看图中是否有明显的空档期确有必要才切 PARALLEL。动态 shape 场景下ORT_ENABLE_ALL 偶尔会把某些分支优化成错误的等价结构表现是输出误差变大或偶发崩溃。遇到这类诡异行为先用 BASIC 级别跑一遍对照如果 BASIC 正常而 ALL 异常这个版本的图优化和你的模型结构有不兼容别硬上。4.2 CUDA provider 的参数device_id、arena 策略和显存上限创建 InferenceSession 时providers 参数除了传字符串还能传二元组第二项是给该 provider 的参数字典。CUDA provider 值得调的参数主要是下面三个cuda_options { device_id: 0, # 多卡时对应 nvidia-smi 里的编号 arena_extend_strategy: kSameAsRequested, # 减少显存预占 gpu_mem_limit: 4 * 1024 * 1024 * 1024, # 4 GB单位是字节 } sess ort.InferenceSession( model.onnx, sess_optionssession_options, providers[(CUDAExecutionProvider, cuda_options), CPUExecutionProvider], )参数作用使用建议device_id选择第几张卡多卡机器必须显式指定arena_extend_strategy控制显存扩展策略显存紧张时用 kSameAsRequestedgpu_mem_limit限制 arena 最大占用按显存总量的一半以上设置cudnn_conv_algo_search卷积算法搜索策略默认 HEURISTIC需要极致性能再开 EXHAUSTIVE显存管理是 GPU 部署的大头问题。ONNX Runtime 的 CUDA provider 会维护一个显存 arena默认策略倾向于预占较大空间以避免反复分配这在单模型场景没问题但多模型共存或与其它显存占用冲突时就容易爆。kSameAsRequested 会尽量按请求大小扩展减少预占代价是频繁的小块分配会带来少量延迟毛刺。gpu_mem_limit 是硬上限单位是字节别把整卡显存全设进去给 CUDA context 和驱动留点余量。4.3 延迟和吞吐验证warmup 不能省调参之后如何判断有没有效果我习惯写一个 20 行以内的基准脚本重点是 warmup 不能省。CUDA 的 context 初始化、kernel 算法选择都发生在第一次 run直接计时会得到一个比真实延迟大几个数量级的数字。import time import numpy as np import onnxruntime as ort sess ort.InferenceSession( model.onnx, providers[CUDAExecutionProvider, CPUExecutionProvider], ) input_meta sess.get_inputs()[0] shape [d if isinstance(d, int) else 1 for d in input_meta.shape] x np.random.rand(*shape).astype(np.float32) io {input_meta.name: x} # 前 5 次用于 CUDA context 初始化和算法选择不能计入 for _ in range(5): sess.run(None, io) times [] for _ in range(50): t0 time.perf_counter() sess.run(None, io) times.append((time.perf_counter() - t0) * 1000) print(avg %.2f ms, p95 %.2f ms % (np.mean(times), np.percentile(times, 95)))p95 比平均延迟更能代表线上真实体验因为 GPU 推理的延迟分布偶尔会被显存带宽争用拉出长尾。跑完这个脚本如果 GPU 比 CPU 还慢先别急着怀疑驱动看看模型输入是否太小。单张图片几十毫秒的计算量CPU 可能已经够快GPU 反而把数据拷贝的耗时显出来了——小模型用 GPU 不是玄学是真的不划算。4.4 混合精度和图优化什么时候值得开图优化已经由 ORT_ENABLE_ALL 自动处理了大部分手动能介入的下一步是 FP16。ONNX Runtime 没有直接提供一个“一键半精度”的 API常见做法是用 onnxconverter_common 先把模型转成 FP16 再加载。from onnxconverter_common import float16 model_fp16 float16.convert_float_to_float16(model)这不是没有代价的。FP16 的动态范围只有 FP32 的零头激活值分布在极端范围时精度会明显劣化。我转换之后一定会跑一次全量验证集比较 FP16 和 FP32 的输出误差平均绝对误差在 1e-2 以下才敢上生产。那些包含大数值跨度归一化层的模型FP16 经常会产出 NaN这类模型就别碰半精度了。5. 避坑 / 常见问题 / 排查Windows 上容易翻车的 5 个点这部分是从零到一跑通这个包最容易摔跤的地方。每一条我都按“现象、原因、解决”的顺序写多数是环境问题而不是代码问题。5.1 现象程序启动就报找不到 onnxruntime.dll或报 api-ms-win-crt 系列 dll 缺失原因分两层。第一层是 PATH 或进程加载路径里没有包含 lib 目录加载器按系统搜索顺序找不到 dll第二层是系统缺少 VC 运行库最典型的就是 vcruntime140.dll 和 msvcp140.dll。那些 api-ms-win 开头的报错多数是 Windows 系统补丁和运行库没装齐不是 onnxruntime 本身的问题。解决先把 lib 目录加进 PATHPython 侧用 os.add_dll_directory 更干净。然后安装对应版本的 Visual C Redistributable x64 包装完重启程序。还有一个容易被忽视的点解压路径别带中文或特殊符号某些工具链对非 ASCII 路径处理有历史遗留问题换个纯英文路径能省去很多奇怪错。5.2 现象get_providers() 列表里只有 CPUExecutionProvider代码跑完了但根本没用到 GPU原因onnxruntime_providers_cuda.dll 没有被成功加载。最常见的是 CUDA/cuDNN 版本和 1.18.0 不匹配官方预编译 GPU 包基于 CUDA 11.8 构建需要配套 cuDNN 8.x。另一个常见原因是部署时只拷了 onnxruntime.dllprovider 的两个 dll 没带全。解决先看 available 列表如果 CUDAExecutionProvider 压根不出现说明是环境问题。用 nvcc --version 核对 CUDA再去%CUDA_PATH%\bin检查 cudart64_110.dll去 cuDNN 安装目录检查 cudnn64_8.dll全部齐了再加进 PATH。这里有个血泪经验不要试图把 CUDA 12 的 dll 改名成 11.8 的文件名来骗过加载器跨大版本混跑大概率是加载成功但 kernel 执行错误这种错最难排查。想用 CUDA 12 就直接换 1.19 之后的包把 1.18.0 留给 CUDA 11.8 环境。5.3 现象显存明明还有空闲创建 session 或第一次 run 时却报 CUDA out of memory原因CUDA provider 的显存 arena 会预占和扩展默认策略下它看到的可用显存包括整卡容量而其它进程占用的显存、WDDM 模式的虚拟显存预留在 nvidia-smi 里不一定直观可见。你的“空闲”和 CUDA 看到的“可分配”不是一回事。解决给显存上锁。把 arena_extend_strategy 改成 kSameAsRequested再用 gpu_mem_limit 设一个合理的显存上限。多模型共存时把每个 session 的 gpu_mem_limit 设成总显存的一半左右让 arena 不会吃掉所有余量。Electron 或浏览器宿主还会占一部分图形显存这块在 nvidia-smi 里也看不见但 CN 分配时能感知到所以上限别卡太满。5.4 现象动态 shape 的模型第一次推理要 3 秒后面才恢复几十毫秒偶尔第一帧直接超时原因CUDA EP 面对动态维度时需要重新选择甚至重新构建 kernel。第一次遇到某个 shape会触发算法搜索和内核编译这是 GPU 推理框架的共性行为不是 onnxruntime 独有的毛病。某些图优化在动态 shape 下还会退化成保守路径导致性能断崖。解决产品层面把动态轴固定下来最常见的是把 batch size 固定成 1 或固定成推理服务支持的最大值导出 ONNX 时就写死。如果必须支持动态 batch提前用典型 shape 做 warmup让 kernel 缓存命中再给推理入口设置超时不要在不确定时长的地方无限等待。另外可以对照 ORT_ENABLE_BASIC 和 ORT_ENABLE_ALL 分别跑一遍动态场景下过激的图优化有时候是负优化。5.5 现象笔记本双显卡或服务器多卡程序只跑 0 号卡或干脆只看到 Intel 核显原因没显式传 device_id。Windows 双显卡机器上CUDA 默认会选择性能最好的独显但某些驱动和机型的组合下CUDA 看到的设备编号和 nvidia-smi 显示的不一样服务器多卡场景设备编号与 PCIe 拓扑相关不是简单的物理位置 0、1、2。解决先运行 nvidia-smi -L 列出所有 GPU再在 provider 参数里显式指定 device_id。另一种方式是环境变量 CUDA_VISIBLE_DEVICES1只暴露第二张卡给 CUDA 运行时但注意设置之后 onnxruntime 看到的编号就变成了 0。这两个方案选一个用就行同时用容易把自己绕晕。笔记本上如果发现 CUDA 看不到独显先去 Windows 图形设置里把程序分配到 NVIDIA 处理器再回来看 provider 列表。6. 进阶把 CPU/GPU 切换和基准测试固化成一个可复用脚本部署迭代到后期反复手写 benchmark 和 provider 配置容易疲劳也容易漏掉 warmup。我习惯维护一个小工具函数换机器、换驱动、换模型时都先跑它把结果留档。6.1 一个够用的 provider 基准函数def bench(model_path, providers, repeat50): import time import numpy as np import onnxruntime as ort sess ort.InferenceSession(model_path, providersproviders) meta sess.get_inputs()[0] shape [d if isinstance(d, int) else 1 for d in meta.shape] io {meta.name: np.random.rand(*shape).astype(np.float32)} for _ in range(5): # warmup sess.run(None, io) ts [] for _ in range(repeat): t0 time.perf_counter() sess.run(None, io) ts.append((time.perf_counter() - t0) * 1000) return np.mean(ts), np.percentile(ts, 95) print(cpu:, bench(model.onnx, [CPUExecutionProvider])) print(gpu:, bench(model.onnx, [CUDAExecutionProvider, CPUExecutionProvider]))这个函数的核心不在于代码量而在于输出口径一致。平均延迟看趋势p95 看稳定性warmup 次数固定这样不同机器、不同驱动版本之间的对比才有意义。每次跑完把结果记到文件里驱动更新之后再跑一次数字一对比就知道性能有没有倒退。6.2 判断配置合不合格的三个读数跑完基准我看三个读数。第一个是 p95 与 avg 的差距差距超过 30% 说明存在长尾优先怀疑显存碎片和动态 shape第二个是 GPU 利用率用 nvidia-smi 或任务管理器看单位时间内的利用率持续低于 50% 且延迟没优势说明模型太小或数据拷贝占了主导第三个是第一次 run 和 warmup 后的差距差距过大说明这次启动在做 kernel 编译线上环境需要提前预热。这三件事做完这套 onnxruntime-win-x64-gpu 方案到底适合不适合你的业务基本就有结论了。如果 GPU 收益明显把 provider 配置和基准脚本一起收进项目的部署脚本如果没收益也留下记录了至少知道问题不在引擎而在模型规模。我自己的习惯是每次拿到新机器都先跑一遍这个脚本把数据归档免得半年后回来说不清为什么当初选了某个配置。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网