简介:这份资源面向希望在Windows 10平台上完成YOLOv5目标检测模型TensorRT加速部署的开发者与初学者,重点解决环境搭建繁琐、依赖版本难以匹配的问题。资源以PDF文档形式整理了CUDA 10.2、cuDNN 7.6.5、VS2019、OpenCV 3.4.0、Anaconda3、CMake 3.19.4、TensorRT 7.0.0.11及YOLOv5-V4.0等全部软件与依赖库的下载信息,并附有百度网盘链接与提取码,下载后可直接使用。压缩包共1个文件,为1个PDF,整体约169KB,体积轻便,便于快速查阅与保存。文档内容围绕Win10系统下的部署流程展开,涵盖各依赖库的作用说明、环境配置思路以及TensorRT构建优化引擎的关键环节,可帮助读者理清从源码编译到推理加速的完整链路。目前已有3492人学习,适合需要快速获取配套软件环境、减少版本兼容性排查时间的YOLOv5实战学习者参考使用。
1. 从 PyTorch 到 TensorRT:为什么 Win10 上这套 YOLOv5 部署包值得拆一遍
训练完一个 YOLOv5 模型,detect.py跑出来 30 FPS,一上产线工控机就掉到 8 FPS,这种落差做过边缘部署的人都遇到过。PyTorch 推理时大量算子没有针对具体 GPU 做融合,卷积、BN、激活各走各的 kernel,显存来回读写,延迟自然下不来。TensorRT 干的事就是把这些算子做层融合、精度校准、kernel 自动调优,同一块显卡上推理速度翻两三倍是常态。
但 TensorRT 部署的麻烦从来不在原理,而在环境。CUDA 10.2、cuDNN 7.6.5、TensorRT 7.0.0.11、VS2019、OpenCV 3.4.0、CMake 3.19.4,这几个版本之间是强绑定的,错一个就是几小时的编译报错。这份资源把 Win10 下 YOLOv5-V4.0 转 TensorRT 所需的全部软件和依赖库打包好了,下载解压就能对上版本,省掉的正是这段最耗人的环境对齐时间。适合手上有 N 卡、要在 Windows 上做 YOLOv5 加速推理的开发者,尤其是被版本冲突卡过的人。
2. 环境版本对齐:CUDA 10.2 到 TensorRT 7 的依赖链怎么锁死
2.1 为什么这套版本组合不能随便换
TensorRT 7.0.0.11 官方只认 CUDA 10.2 和 cuDNN 7.6.x,这是硬约束。你换成 CUDA 11,TensorRT 7 的nvinfer.dll直接加载失败;cuDNN 升到 8,cudnn64_7.dll找不到,编译期就断。VS2019 这边,TensorRT 7 的 Windows 包只提供 MSVC 2017/2019 的 lib,用 VS2022 打开工程会提示工具集不匹配。
OpenCV 3.4.0 是这套包里比较老的一环,但 YOLOv5 的 C++ 推理代码里用到的cv::Mat和dnn模块接口在 3.4 和 4.x 之间没有破坏性变更,所以 3.4.0 够用,且它和 CUDA 10.2 的兼容性经过验证。CMake 3.19.4 负责生成 VS2019 的.sln,版本太低会不认 VS2019 的 generator。
| 组件 | 版本 | 作用 | 绑定关系 |
|---|---|---|---|
| CUDA Toolkit | 10.2 | GPU 计算平台 | TensorRT 7 强制要求 |
| cuDNN | 7.6.5 | 深度神经网络加速库 | 对应 CUDA 10.2 |
| TensorRT | 7.0.0.11 | 推理优化器与运行时 | 依赖 CUDA 10.2 + cuDNN 7.6.5 |
| VS2019 | 16.x | C++ 编译与调试 | 提供 MSVC 工具集 |
| OpenCV | 3.4.0 | 图像预处理与后处理 | 与 CUDA 10.2 兼容 |
| CMake | 3.19.4 | 构建系统 | 生成 VS2019 工程 |
| Anaconda3 | 任意较新版 | Python 环境管理 | 跑 PyTorch 导出 ONNX |
2.2 安装顺序与路径规范
安装顺序错了,后面全是坑。正确顺序是:显卡驱动 → CUDA 10.2 → cuDNN 7.6.5 → TensorRT 7.0.0.11 → VS2019 → OpenCV 3.4.0 → CMake → Anaconda3。
CUDA 安装时选自定义,取消 Visual Studio Integration 那一项(因为 VS2019 还没装),装完再手动补。cuDNN 解压后把bin、include、lib三个目录的文件分别拷进 CUDA 安装目录对应文件夹。TensorRT 同理,解压后把lib下的 dll 拷到C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.2\bin,lib 文件拷到lib\x64。
# 验证 CUDA 安装 nvcc --version # 应输出:Cuda compilation tools, release 10.2, V10.2.89 # 验证 cuDNN(查看 CUDA 目录下是否存在) dir "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.2\bin\cudnn64_7.dll" # 验证 TensorRT dir "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.2\bin\nvinfer.dll"这三条命令是环境是否装对的第一道关卡。nvcc --version输出 10.2 说明 CUDA 本体没问题;cudnn64_7.dll存在说明 cuDNN 拷贝到位;nvinfer.dll存在说明 TensorRT 运行时库已就位。任何一条失败,后面编译必然翻车,先回头补。
环境变量也要检查:CUDA_PATH应指向C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.2,Path里要有%CUDA_PATH%\bin和%CUDA_PATH%\lib\x64。TensorRT 的 lib 路径如果没加进Path,运行时会出现nvinfer.dll找不到的弹窗。
3. YOLOv5 转 ONNX 再转 TensorRT:模型导出与 engine 生成
3.1 从 PyTorch 权重导出 ONNX
TensorRT 不直接吃.pt文件,中间要过一道 ONNX。YOLOv5-V4.0 的仓库里自带models/export.py,但直接跑默认参数导出的 ONNX 在 TensorRT 7 上解析会报错,因为 TensorRT 7 对动态 shape 的支持有限,需要固定 batch 和输入尺寸。
# export_onnx.py import torch from models.experimental import attempt_load # 加载 YOLOv5 权重,map_location 确保在 CPU 上加载避免显存占用 model = attempt_load('yolov5s.pt', map_location=torch.device('cpu')) model.eval() # 构造固定尺寸输入:batch=1, 3通道, 640x640 dummy_input = torch.randn(1, 3, 640, 640) # 导出 ONNX,opset_version=11 是 TensorRT 7 能稳定解析的版本 torch.onnx.export( model, dummy_input, 'yolov5s.onnx', opset_version=11, input_names=['images'], output_names=['output'], dynamic_axes=None # 固定 shape,不用动态轴 ) print('ONNX export done.')opset_version=11是关键参数,TensorRT 7 对 opset 12 以上的某些算子支持不完整,用 11 最稳。dynamic_axes=None表示不做动态 batch,如果产线需要变 batch,得在 TensorRT 构建 engine 时用 optimization profile 单独配,不能靠 ONNX 的动态轴。input_names和output_names要和后面 C++ 推理代码里的绑定名称一致,否则getBindingIndex返回 -1。
导出后用onnxsim简化一下图结构,去掉冗余的 Identity 和 Constant 节点,TensorRT 解析会更快:
pip install onnx-simplifier python -m onnxsim yolov5s.onnx yolov5s_sim.onnx3.2 用 trtexec 生成 engine 并验证
TensorRT 包里自带trtexec.exe,在bin目录下。它是验证 ONNX 能否被 TensorRT 正确解析的最快工具,不用写一行 C++。
# 进入 TensorRT 的 bin 目录 cd "C:\TensorRT-7.0.0.11\bin" # 用 trtexec 把 ONNX 转成 engine trtexec.exe --onnx=yolov5s_sim.onnx --saveEngine=yolov5s.engine --fp16 --workspace=2048 # 参数说明: # --onnx 输入 ONNX 模型路径 # --saveEngine 输出 engine 文件路径 # --fp16 启用 FP16 精度,速度提升明显,精度损失通常可接受 # --workspace 显存工作空间上限,单位 MB,2048 够 YOLOv5s 用跑完会输出每层的耗时和总推理时间。如果报Unsupported operation或Could not parse,说明 ONNX 里有 TensorRT 7 不认的算子,常见的是Resize的 coordinate_transformation_mode 参数,需要在导出时改成align_corners=False对应的模式。
engine 文件是跟 GPU 架构绑定的,在 2080Ti 上生成的 engine 拿到 1080Ti 上跑不了,必须重新生成。这是 TensorRT 的硬特性,不是 bug。产线部署时要么在目标机器上现场生成,要么确保生成和运行的 GPU 型号一致。
3.3 VS2019 编译 C++ 推理工程
拿到 engine 后,用 VS2019 打开 TensorRT 自带的sampleOnnxMNIST或 YOLOv5 的 C++ 推理工程,配置项目属性。需要改的地方集中在三处:
- VC++ 目录 → 包含目录:加入 CUDA 的
include、TensorRT 的include、OpenCV 的include - VC++ 目录 → 库目录:加入 CUDA 的
lib\x64、TensorRT 的lib、OpenCV 的lib - 链接器 → 输入 → 附加依赖项:加入
nvinfer.lib、nvinfer_plugin.lib、nvonnxparser.lib、cudart.lib、opencv_world340.lib
// 推理核心片段:加载 engine 并创建执行上下文 #include <NvInfer.h> #include <NvOnnxParser.h> // 创建 logger,TensorRT 所有日志都走这个接口 class Logger : public nvinfer1::ILogger { void log(Severity severity, const char* msg) noexcept override { if (severity != Severity::kINFO) std::cout << msg << std::endl; } } gLogger; // 从文件读取 engine 并反序列化 std::ifstream engineFile("yolov5s.engine", std::ios::binary); engineFile.seekg(0, std::ios::end); size_t size = engineFile.tellg(); engineFile.seekg(0, std::ios::beg); std::vector<char> buffer(size); engineFile.read(buffer.data(), size); nvinfer1::IRuntime* runtime = nvinfer1::createInferRuntime(gLogger); nvinfer1::ICudaEngine* engine = runtime->deserializeCudaEngine(buffer.data(), size, nullptr); nvinfer1::IExecutionContext* context = engine->createExecutionContext();deserializeCudaEngine把 engine 文件加载成可执行的 CUDA 引擎,createExecutionContext创建推理上下文。一个 engine 可以创建多个 context 做并发推理,但每个 context 占一份显存。Logger里过滤掉kINFO级别日志,否则 TensorRT 会刷屏。
推理时的显存分配用cudaMalloc给输入输出各开一块,context->enqueue异步执行,cudaMemcpyAsync做主机和设备间拷贝。YOLOv5 的输出是三个尺度的特征图,后处理需要做 decode 和 NMS,这部分在 CPU 上做还是 GPU 上做,直接影响端到端延迟。
4. 部署避坑:从 dll 缺失到 engine 不匹配的排查记录
4.1 现象:编译通过但运行时报 nvinfer.dll 找不到
原因:TensorRT 的 dll 没有拷到 CUDA 的 bin 目录,或者Path环境变量里没有 TensorRT 的 lib 路径。VS2019 编译时链接的是.lib导入库,运行时才去加载.dll,两者路径不一致就报错。
解决:把TensorRT\lib下的所有 dll 拷到C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.2\bin,重启命令行让Path生效。或者直接在系统环境变量Path里追加 TensorRT 的 lib 路径。
4.2 现象:trtexec 解析 ONNX 报 Unsupported operation: Resize
原因:YOLOv5 的export.py默认导出的 ONNX 里,上采样用的Resize节点带了coordinate_transformation_mode="half_pixel",TensorRT 7 只认asymmetric和align_corners。
解决:在导出脚本里把torch.onnx.export的opset_version设为 11,并在模型定义里把nn.Upsample的align_corners显式设为False。如果还报错,用onnxsim简化后再试,简化过程会重写部分节点属性。
4.3 现象:engine 在开发机上正常,拷到工控机上反序列化失败
原因:engine 文件绑定了生成时的 GPU 架构和 TensorRT 版本。开发机是 RTX 2080(图灵架构),工控机是 GTX 1050Ti(帕斯卡架构),SM 版本不同,engine 里的 kernel 无法执行。
解决:在工控机上重新跑trtexec生成 engine。如果工控机没有完整的 TensorRT 环境,至少要把trtexec.exe和依赖的 dll 拷过去,用--saveEngine现场生成。
4.4 现象:FP16 模式下检测框偏移,mAP 掉点
原因:FP16 精度下,YOLOv5 的 decode 部分涉及大量小数值运算,半精度浮点的表示范围不够,导致框坐标回归偏差。
解决:把 decode 和 NMS 部分留在 FP32 做,只对 backbone 和 neck 做 FP16 量化。在 TensorRT 里可以通过setLayerPrecision对特定层强制 FP32,或者在导出 ONNX 时把 decode 部分单独拆出来用 CPU 实现。
4.5 现象:VS2019 编译报 MSB8020 工具集不匹配
原因:工程文件是用 VS2017 的工具集创建的,本机只装了 VS2019 的 v142 工具集。
解决:右键项目 → 属性 → 常规 → 平台工具集,改成Visual Studio 2019 (v142)。如果下拉框里没有,说明 VS2019 安装时没勾 C++ 桌面开发工作负载,用 Visual Studio Installer 补上。
5. 进阶技巧:用 Python 脚本批量生成 engine 并做多模型对比
环境跑通之后,真正提效的是把重复劳动脚本化。我一般会写一个 Python 脚本,遍历models目录下所有.onnx文件,自动调trtexec生成 engine,并记录每个模型的推理耗时和显存占用,方便选型。
# build_engines.py import subprocess import os import time TRTEXEC = r"C:\TensorRT-7.0.0.11\bin\trtexec.exe" ONNX_DIR = "./onnx_models" ENGINE_DIR = "./engines" os.makedirs(ENGINE_DIR, exist_ok=True) # 遍历所有 onnx 文件,逐个生成 engine for onnx_file in os.listdir(ONNX_DIR): if not onnx_file.endswith(".onnx"): continue name = os.path.splitext(onnx_file)[0] onnx_path = os.path.join(ONNX_DIR, onnx_file) engine_path = os.path.join(ENGINE_DIR, f"{name}.engine") # 跳过已生成的 engine,避免重复耗时 if os.path.exists(engine_path): print(f"skip {name}, engine exists") continue cmd = [ TRTEXEC, f"--onnx={onnx_path}", f"--saveEngine={engine_path}", "--fp16", "--workspace=2048", "--iterations=100", # 跑100次取平均,减少抖动 "--avgRuns=10" # 前10次作为预热不计入 ] print(f"building {name} ...") start = time.time() result = subprocess.run(cmd, capture_output=True, text=True) elapsed = time.time() - start if result.returncode != 0: print(f"FAILED {name}: {result.stderr[-500:]}") else: print(f"OK {name}, build time {elapsed:.1f}s")--iterations=100和--avgRuns=10是让 trtexec 跑够次数取稳定值,单次跑受 GPU 调度影响波动大。subprocess.run捕获 stderr,失败时只打印最后 500 字符,避免日志刷屏。这个脚本在换模型做对比时特别省事,扔一批 ONNX 进去,出来就是一组 engine 和耗时数据。
验证 engine 是否真的加速了,不能只看 trtexec 的输出,要在实际推理代码里用std::chrono打点。我习惯在enqueue前后各记一次时间,跑 100 帧取平均,和 PyTorch 的time.time()结果对比。同一张 1080Ti 上,YOLOv5s 640 分辨率,PyTorch FP32 大约 25ms,TensorRT FP16 能压到 8ms 左右,差距主要来自层融合和 FP16 的吞吐优势。
还有一个容易忽略的点:engine 文件不要提交到 Git。它跟 GPU 绑定,换机器就失效,而且动辄几十上百 MB。正确做法是把 ONNX 和生成脚本一起管理,engine 在部署时现场生成。从那以后我每次换部署机器,第一件事就是重新跑一遍build_engines.py,确认 engine 是在目标 GPU 上生成的,再往下做性能测试。希望帮到你。
本文还有配套的精品资源,点击获取