第二章 环境搭建与工具链准备:把地基打牢

说实话,我见过太多人在模型加速上栽跟头,最后发现是环境没配好。OpenCV 编译少了个模块,CUDA 版本对不上,TensorRT 死活装不上——这些坑我都踩过。这一章,咱们就把这些事一次性搞定。

环境搭建这事,说白了就是「选对版本、按对顺序、测对结果」。别嫌麻烦,后面所有加速技巧都依赖这套工具链。

2.1 OpenCV 编译:别用 pip 装的那个

很多人图省事,直接 pip install opencv-python。嗯,这个版本确实能用,但你要的 DNN 模块、TBB 并行、OpenMP 支持,它一个都没有。我个人的习惯是:生产环境必须源码编译。

为什么非要自己编译?

功能 pip 安装版 源码编译版
DNN 模块 基础支持 完整支持 + 加速后端
TBB ❌ 无 ✅ 多线程流水线
OpenMP ❌ 无 ✅ CPU 并行加速
CUDA 后端 ❌ 无 ✅ GPU 推理
自定义优化 ❌ 无 ✅ 指令集、量化

你看,差距不是一星半点。尤其是 DNN 模块,你要是不开 WITH_DNN,后面 YOLO 模型根本加载不了。

编译步骤(Ubuntu 20.04/22.04)

我直接给出一套我验证过的 CMake 配置。你照着来,基本不会出错。

# 安装依赖
sudo apt update
sudo apt install build-essential cmake git pkg-config
sudo apt install libjpeg-dev libpng-dev libtiff-dev
sudo apt install libavcodec-dev libavformat-dev libswscale-dev
sudo apt install libgtk2.0-dev libcanberra-gtk-module
sudo apt install libtbb-dev libopenblas-dev

# 下载 OpenCV 4.8.0 + contrib
git clone https://github.com/opencv/opencv.git -b 4.8.0
git clone https://github.com/opencv/opencv_contrib.git -b 4.8.0

cd opencv && mkdir build && cd build

cmake -D CMAKE_BUILD_TYPE=RELEASE \
      -D CMAKE_INSTALL_PREFIX=/usr/local \
      -D WITH_TBB=ON \
      -D WITH_OPENMP=ON \
      -D WITH_OPENCL=ON \
      -D WITH_CUDA=OFF \          # 先关掉,后面单独配
      -D BUILD_opencv_python3=ON \
      -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib/modules \
      -D BUILD_EXAMPLES=OFF ..

make -j$(nproc)
sudo make install
我的经验:第一次编译别开 CUDA。先把 CPU 版本跑通,确认 DNN 和 TBB 正常工作,再回头加 GPU 支持。否则两个问题混在一起,你根本不知道是编译错了还是代码写错了。

2.2 CUDA + cuDNN:GPU 加速的入场券

YOLO 推理要跑在 GPU 上,CUDA 和 cuDNN 是绕不开的。我遇到过有人装了 CUDA 11.8,结果 cuDNN 是 8.4 的,版本不匹配,推理直接崩。所以,版本一定要对齐。

版本对应关系

CUDA 版本 cuDNN 版本 推荐场景
11.8 8.6 / 8.7 TensorRT 8.5 以下
12.1 8.9 TensorRT 8.6+ / 最新 YOLO
12.4 9.0 最新生态,但兼容性需验证

我个人建议用 CUDA 12.1 + cuDNN 8.9。这个组合我测过 YOLOv8 和 YOLOv5,推理稳定,TensorRT 也能无缝对接。

安装要点

  1. 先装驱动:nvidia-smi 能看到显卡,驱动版本要支持你选的 CUDA。
  2. 再装 CUDA Toolkit:用 runfile 方式,别用 deb,路径可控。
  3. 最后装 cuDNN:把 .h 和 .so 文件复制到 CUDA 目录下。
# 验证 CUDA
nvcc --version

# 验证 cuDNN
cat /usr/local/cuda/include/cudnn_version.h | grep CUDNN_MAJOR -A 2
避坑:我曾经在服务器上同时装了 CUDA 11.8 和 12.1,结果 LD_LIBRARY_PATH 指向了旧版本,OpenCV 编译时死活找不到 cuDNN。后来我统一用 /usr/local/cuda 软链接指向目标版本,问题解决。

2.3 重新编译 OpenCV:这次带上 CUDA

CUDA 装好了,咱们回头重新编译 OpenCV。这次加上 WITH_CUDA=ON 和 cuDNN 支持。

cmake -D CMAKE_BUILD_TYPE=RELEASE \
      -D CMAKE_INSTALL_PREFIX=/usr/local \
      -D WITH_TBB=ON \
      -D WITH_OPENMP=ON \
      -D WITH_CUDA=ON \
      -D WITH_CUDNN=ON \
      -D OPENCV_DNN_CUDA=ON \
      -D CUDA_ARCH_BIN=8.6 \        # 根据你的显卡改,RTX 30系是8.6
      -D ENABLE_FAST_MATH=ON \
      -D CUDA_FAST_MATH=ON \
      -D BUILD_opencv_python3=ON \
      -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib/modules \
      ..

make -j$(nproc)
sudo make install

编译完记得验证一下:

python3 -c "import cv2; print(cv2.getBuildInformation())" | grep -i cuda

如果看到 CUDA: YES 和 cuDNN: YES,恭喜,环境已经就绪。

2.4 ONNX Runtime vs TensorRT:选哪个?

这个问题我经常被问到。我的回答是:看你的部署场景。

对比项 ONNX Runtime TensorRT
硬件支持 CPU / GPU / NPU NVIDIA GPU 专属
推理速度 较快 极快(FP16/INT8)
模型转换 直接加载 .onnx 需转 .engine / .trt
动态尺寸 原生支持 需配置优化策略
学习成本 低 中高
适用场景 快速原型、多平台 极致性能、量产部署

我的建议很直接:

  • 开发阶段、快速验证 → 用 ONNX Runtime。导出 .onnx 就能跑,省事。
  • 生产环境、追求极致 → 用 TensorRT。FP16 推理能快 2-3 倍,INT8 量化能到 4-5 倍。
  • 两者都装 → 不冲突。我自己的项目里,开发用 ONNX,上线切 TensorRT。

2.5 知识结构总览

下面这张图,把整个工具链的依赖关系画清楚了。你照着这个顺序搭,不会乱。

环境搭建与工具链依赖关系 系统层:Ubuntu 20.04/22.04 + NVIDIA 驱动 基础依赖:build-essential, cmake, git, libtbb-dev, libopenblas-dev GPU 加速层:CUDA 12.1 + cuDNN 8.9 nvcc --version 验证 | cuDNN 头文件与库文件复制 OpenCV 4.8.0(源码编译) WITH_TBB=ON | WITH_OPENMP=ON | WITH_CUDA=ON | WITH_CUDNN=ON OPENCV_DNN_CUDA=ON | CUDA_ARCH_BIN=8.6 推理引擎 ONNX Runtime TensorRT 8.6+ 应用层:YOLO 推理加速与性能调优 DNN 后端选择 | FP16/INT8 量化 | 多线程流水线 💡 建议顺序:系统驱动 → CUDA+cuDNN → OpenCV 编译(先 CPU 后 GPU)→ 推理引擎选型 每个环节装完都要验证,别一口气装完再 debug

2.6 验证清单:装完别急着跑

环境搭完,我建议你跑一遍这个验证清单。每一项都过,后面出问题能快速定位。

  1. 显卡驱动:nvidia-smi 显示 GPU 型号和驱动版本。
  2. CUDA:nvcc --version 输出版本号。
  3. cuDNN:cat /usr/local/cuda/include/cudnn_version.h 能看到版本宏。
  4. OpenCV 编译信息:cv2.getBuildInformation() 确认 CUDA、TBB、OpenMP 都是 YES。
  5. DNN 加载测试:用 cv2.dnn.readNet() 加载一个 .onnx 模型,不报错。
  6. GPU 推理测试:设置 net.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA),跑一次推理。

我的习惯:每次装完新环境,我都会写一个 env_check.py 脚本,把上面 6 项自动化。这样换机器、换版本时,跑一遍脚本就知道环境行不行。