ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Ubuntu 18.04 上 CUDA 10.2 + cuDNN 8 + TensorRT 6.0 环境搭建与避坑指南

Ubuntu 18.04 上 CUDA 10.2 + cuDNN 8 + TensorRT 6.0 环境搭建与避坑指南

1. 为什么这套"老版本三件套"至今还有人折腾

先把结论摆在前面:CUDA 10.2 + cuDNN 8 + TensorRT 6.0 这套组合,放在今天看确实不算新,但它并没有彻底退出历史舞台。我最近就碰到一个很典型的场景——某实验室的一台工控机,显卡是 Tesla P4,系统锁死在 Ubuntu 18.04,配套的推理服务又依赖 TensorRT 6.0 的某个算子实现。你没法随便升级,因为一升级整条链路全崩。这种"被版本锁死"的情况在工业部署、边缘设备、老项目维护里非常常见。

所以这篇东西不是写给追新的人看的,而是写给那些手里有一台 Ubuntu 18.04、一块老卡、一个跑不动的推理服务的人。整套流程的核心难点其实不在"装",而在"配"——CUDA、cuDNN、TensorRT 三者之间有严格的版本对应关系,装错一个版本,后面全是玄学报错。我会把每一步的意图、版本选择的逻辑、以及我实际踩过的坑都摊开讲。

先明确这套组合的定位:

组件版本作用关键约束
CUDA10.2GPU 通用计算平台决定驱动最低版本
cuDNN8.x深度神经网络加速库必须匹配 CUDA 10.2
TensorRT6.0推理优化引擎必须匹配 CUDA 10.2 + cuDNN 8

这三者的关系可以这样理解:CUDA 是地基,cuDNN 是承重墙,TensorRT 是精装修。地基没打好,后面全白搭。而 Ubuntu 18.04 自带的 GCC 7.5 和这套 CUDA 10.2 是兼容的,这也是为什么很多人宁愿守着 18.04 不升级——新系统默认 GCC 版本太高,反而要额外降级,徒增麻烦。

提示:如果你只是想在 Ubuntu 18.04 上跑一个普通的 PyTorch 训练任务,其实没必要上 TensorRT。TensorRT 的价值在推理阶段,尤其是需要低延迟、高吞吐的生产环境。别为了"装而装"。

2. 装之前必须搞清楚的版本对应与驱动底线

2.1 驱动版本决定了你能不能装 CUDA 10.2

很多人一上来就apt install cuda,结果装完nvidia-smi报错,或者 CUDA 跑不起来。根因几乎都是驱动版本不匹配。CUDA 10.2 要求 NVIDIA 驱动版本不低于440.33。你可以先用一条命令确认当前状态:

nvidia-smi

看右上角的Driver Version。如果低于 440,要么升级驱动,要么直接装 CUDA 时勾选自带驱动(但自带驱动往往偏旧,不推荐)。我的习惯是先把驱动单独装好,再装 CUDA,这样出问题好定位。

驱动安装有两条路:一是用 Ubuntu 的apt源里的nvidia-driver-440,二是用官方.run文件。前者省心,后者可控。对于 Ubuntu 18.04,我更推荐走 apt:

sudo apt update sudo apt install nvidia-driver-440 sudo reboot

重启后再nvidia-smi,能看到显卡信息和驱动版本就说明驱动 OK 了。

2.2 为什么 cuDNN 一定要选 8.x 而不是 7.x

这里有个容易混淆的点。CUDA 10.2 其实同时支持 cuDNN 7.6.x 和 cuDNN 8.x,但TensorRT 6.0 明确要求 cuDNN 8。如果你先装了 cuDNN 7,再装 TensorRT 6.0,编译或运行时会报找不到cudnn*_v8符号的错误。所以顺序上,cuDNN 必须选 8.x 版本,且要选对应 CUDA 10.2 的构建。

cuDNN 8 对应 CUDA 10.2 的包名一般长这样:cudnn-10.2-linux-x64-v8.0.x.xx.tgz。下载下来是个压缩包,里面是头文件和库文件,需要手动拷贝到 CUDA 目录。这一步没有安装脚本,纯手工,所以路径千万别搞错。

2.3 TensorRT 6.0 的包结构要提前看懂

TensorRT 6.0 的 tar 包解压后通常包含这几个目录:bin、include、lib、data、python。其中lib里既有运行时库也有开发库,python目录里是 Python 绑定。很多人装完发现import tensorrt失败,就是因为没处理python目录里的 wheel 包。这个后面会细讲。

版本对应关系我整理成一张表,装之前对着核一遍:

组件推荐版本校验方式
NVIDIA 驱动>= 440.33nvidia-smi
CUDA10.2nvcc --version
cuDNN8.0.xcat /usr/local/cuda/include/cudnn_version.h
TensorRT6.0.x`dpkg -l

3. CUDA 10.2 的安装:runfile 与 deb 的取舍

3.1 两种安装方式的真实差异

CUDA 10.2 官方提供两种安装包:.run(runfile)和.deb(本地仓库)。我两种都用过,说下实际感受。

.deb方式的好处是走系统包管理,卸载干净,apt remove就能清掉。坏处是它会自动帮你处理依赖,有时候会顺带升级一些系统库,在锁死环境的机器上可能引发连锁反应。.run方式的好处是可控,你可以选择不装驱动、不装 samples,只装 toolkit。坏处是卸载麻烦,得手动删目录。

对于 Ubuntu 18.04 这种老系统,我一般推荐.run方式,因为可控性更重要。但如果你对系统环境不熟,.deb更稳妥。

3.2 runfile 安装的完整操作与关键选项

下载cuda_10.2.89_440.33.01_linux.run之后,先给它执行权限:

chmod +x cuda_10.2.89_440.33.01_linux.run sudo ./cuda_10.2.89_440.33.01_linux.run

进入安装界面后,有几个选项必须注意:

  • Driver:如果你已经单独装好了 440 驱动,这里取消勾选,否则会覆盖你现有的驱动,可能把图形界面搞崩。
  • CUDA Toolkit 10.2:勾选。
  • CUDA Samples:可选,建议勾上,后面验证用得上。
  • CUDA Toolkit 10.2 的安装路径:默认/usr/local/cuda-10.2,别改。

安装完成后,需要配置环境变量。编辑~/.bashrc:

export PATH=/usr/local/cuda-10.2/bin:$PATH export LD_LIBRARY_PATH=/usr/local/cuda-10.2/lib64:$LD_LIBRARY_PATH

然后source ~/.bashrc,用nvcc --version验证。如果输出Cuda compilation tools, release 10.2,说明 CUDA 装好了。

3.3 一个容易被忽略的软链接问题

/usr/local/cuda这个软链接默认会指向你最后安装的 CUDA 版本。如果你机器上之前装过别的 CUDA,这个链接可能指向旧版本,导致编译时找错头文件。装完 CUDA 10.2 后,手动确认一下:

ls -l /usr/local/cuda

如果指向的不是cuda-10.2,就重建:

sudo rm /usr/local/cuda sudo ln -s /usr/local/cuda-10.2 /usr/local/cuda

这个坑我在一台装过 CUDA 9 的机器上踩过,编译 TensorRT 示例时一直报头文件版本冲突,查了半天才发现是软链接指错了。

4. cuDNN 8 的手工部署与版本校验

4.1 拷贝文件时的路径陷阱

cuDNN 8 的 tar 包解压后是cuda目录,里面有include和lib64。标准做法是把它们拷到 CUDA 安装目录:

tar -xzvf cudnn-10.2-linux-x64-v8.0.5.39.tgz sudo cp cuda/include/cudnn*.h /usr/local/cuda-10.2/include sudo cp cuda/lib64/libcudnn* /usr/local/cuda-10.2/lib64 sudo chmod a+r /usr/local/cuda-10.2/include/cudnn*.h sudo chmod a+r /usr/local/cuda-10.2/lib64/libcudnn*

这里有个细节:cuDNN 8 的头文件从cudnn.h变成了cudnn_version.h和cudnn.h两个。如果你只拷了cudnn.h,编译时可能找不到版本宏。所以拷贝时用通配符cudnn*.h最保险。

4.2 验证 cuDNN 是否真正生效

拷完之后别急着往下走,先验证。最直接的方法是看版本宏:

cat /usr/local/cuda-10.2/include/cudnn_version.h | grep CUDNN_MAJOR -A 2

正常应该输出CUDNN_MAJOR 8、CUDNN_MINOR 0之类。如果这个文件不存在,说明你拷的是 cuDNN 7 的包,回去重新下。

另一个验证方式是编译 CUDA samples 里的mnistCUDNN,但这个比较耗时。我一般用头文件校验就够了,快且准。

注意:cuDNN 的库文件权限一定要设成可读,否则非 root 用户跑程序时会报cannot open shared object file。这个错误信息很有迷惑性,看起来像路径问题,其实是权限问题。

5. TensorRT 6.0 的落地:库、头文件与 Python 绑定

5.1 tar 包解压后的目录该怎么用

TensorRT 6.0 的 tar 包解压后,我建议先放到一个固定位置,比如/opt/TensorRT-6.0.1.5。然后配置环境变量:

export LD_LIBRARY_PATH=/opt/TensorRT-6.0.1.5/lib:$LD_LIBRARY_PATH export PATH=/opt/TensorRT-6.0.1.5/bin:$PATH

注意这里不需要把头文件和库拷到 CUDA 目录,TensorRT 是独立的一套。很多人习惯性地往 CUDA 目录里拷,反而造成版本混乱。

5.2 Python 绑定的安装有个大坑

TensorRT 6.0 的python目录里有对应 Python 版本的 wheel 包,比如tensorrt-6.0.1.5-cp36-none-linux_x86_64.whl。Ubuntu 18.04 默认 Python 是 3.6,所以直接:

cd /opt/TensorRT-6.0.1.5/python pip3 install tensorrt-6.0.1.5-cp36-none-linux_x86_64.whl

但这里有个坑:这个 wheel 包只装了tensorrt模块,uff和graphsurgeon是分开的。如果你要用 TensorRT 的 Python API 做模型转换,还得装另外两个:

pip3 install uff-0.6.9-py2.py3-none-any.whl pip3 install graphsurgeon-0.4.5-py2.py3-none-any.whl

这三个包版本要对应,装错一个,import tensorrt时可能报ImportError。我见过有人只装了 tensorrt,然后跑示例脚本时一直报No module named uff,查了半天。

5.3 用 sample_mnist 做端到端验证

TensorRT 自带sample_mnist示例,是验证整套环境是否打通的最好方式。进入samples/python/mnist目录,先下载 MNIST 数据,然后跑:

python3 sample.py

如果能看到推理结果输出,说明 CUDA、cuDNN、TensorRT 三者已经协同工作。如果报错,根据错误信息定位:

报错信息可能原因排查方向
libcudnn.so.8 not foundcuDNN 未正确安装检查 lib64 目录和 LD_LIBRARY_PATH
undefined symbol: cudnn...cuDNN 版本不匹配确认是 8.x 而非 7.x
No module named tensorrtPython 绑定未装检查 wheel 包是否装对 Python 版本
CUDA driver version is insufficient驱动版本过低升级到 440+

6. 那些文档里不会写的踩坑记录

6.1 装完 CUDA 后图形界面进不去

这个坑我踩过两次。原因是.run安装时勾选了 Driver,把系统自带的 nouveau 驱动和 NVIDIA 驱动搞冲突了。解决办法是进恢复模式,卸载重装驱动,然后重装 CUDA 时不勾选 Driver。如果你已经进不去图形界面,可以按 Ctrl+Alt+F2 进 tty,用命令行处理。

预防措施很简单:装 CUDA 前先确认nvidia-smi能正常输出,装的时候坚决不勾 Driver。

6.2 TensorRT 示例编译时找不到 NvInfer.h

TensorRT 的头文件在include目录,编译时需要显式指定。如果你用 CMake,要在CMakeLists.txt里加:

include_directories(/opt/TensorRT-6.0.1.5/include) link_directories(/opt/TensorRT-6.0.1.5/lib)

如果直接 g++ 编译,加-I和-L参数。这个错误很常见,但解决起来就是一行配置的事。

6.3 多版本 CUDA 共存时的环境变量污染

有些机器上同时装了 CUDA 10.0 和 10.2,LD_LIBRARY_PATH里如果两个路径都有,运行时可能加载到错误版本的库。我的做法是环境变量里只保留当前要用的版本,其他版本用的时候再临时切换。可以写个小脚本:

#!/bin/bash export CUDA_HOME=/usr/local/cuda-10.2 export PATH=$CUDA_HOME/bin:$PATH export LD_LIBRARY_PATH=$CUDA_HOME/lib64:$LD_LIBRARY_PATH

用的时候source一下,干净利落。

6.4 磁盘空间不足导致的静默失败

CUDA 10.2 完整安装大概占 3-4 GB,cuDNN 和 TensorRT 加起来 1 GB 左右。如果/usr/local所在分区空间不够,安装过程可能中途失败但不报明显错误。装之前用df -h看一眼,留出至少 10 GB 余量。这个坑比较隐蔽,因为失败后nvcc --version可能还能输出,但实际库文件不全。

7. 环境验证清单与日常维护建议

7.1 一套命令跑完所有验证

装完之后,我习惯用下面这组命令做一次全面体检:

# 驱动 nvidia-smi # CUDA nvcc --version # cuDNN cat /usr/local/cuda-10.2/include/cudnn_version.h | grep CUDNN_MAJOR -A 2 # TensorRT python3 -c "import tensorrt; print(tensorrt.__version__)" # 综合 python3 -c "import tensorrt as trt; print(trt.Logger(trt.Logger.WARNING))"

最后一条如果没报错,说明 TensorRT 的 Python 环境完全可用。

7.2 版本锁定后的维护策略

这套环境一旦跑通,我的建议是不要轻易动。具体做法:

  • 把~/.bashrc里的环境变量备份一份,重装系统时直接恢复。
  • 把 CUDA、cuDNN、TensorRT 的安装包留在本地,别删,以后重装省得重新下载。
  • 如果要用 Docker,把整套环境打成镜像,比在宿主机上反复折腾靠谱得多。

TensorRT 6.0 的 Docker 镜像官方也有提供,但如果你需要定制,自己写 Dockerfile 更灵活。基础镜像选nvidia/cuda:10.2-cudnn8-devel-ubuntu18.04,然后在里面装 TensorRT,这样版本对应关系天然就是对的。

7.3 关于是否值得升级的个人看法

经常有人问,这套老环境要不要升级到 CUDA 11 + TensorRT 8。我的看法是:如果现有服务稳定运行,没有性能瓶颈,就别升。升级意味着重新验证所有算子、重新测试精度、重新压测性能,成本远高于收益。只有当新版本带来你确实需要的特性(比如新的量化方式、新的算子支持),才值得动。

我在一台边缘设备上守着 CUDA 10.2 跑了两年多,期间只打过一次安全补丁,稳定性比追新强得多。老版本不是技术债,在特定场景下它是经过验证的可靠资产。

最后分享一个实用小技巧:如果你不确定某个 TensorRT 版本支持哪些算子,可以直接看lib目录下的libnvinfer.so符号表,用nm -D过滤一下,比翻文档快。这个习惯帮我省了不少查文档的时间。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进