ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

NVIDIA驱动到MMCV:CUDA/PyTorch五层兼容与50系源码编译

2026/10/1 18:52:32 拓冰建站 浏览量
NVIDIA驱动到MMCV:CUDA/PyTorch五层兼容与50系源码编译 上周帮朋友收拾一台新配的工作站,卡了整整一天。机器上是一张 50 系显卡,系统 Ubuntu 22.04,需求很朴素:把一个基于 MMDetection 的检测项目跑起来。结果从下午折腾到深夜,报错一路从nvcc fatal: Unsupported gpu architecture滚到undefined reference to c10::cuda,中间还夹着一次gzip: stdin: invalid compressed>python -c import torch; print(torch.cuda.get_arch_list())如果输出里包含你的显卡对应的算力值(比如 40 系是sm_89,50 系是sm_120),说明这份 wheel 是原生支持的;如果不包含,程序运行时可能会走 PTX 即时编译(JIT)这条路——能用,但第一次跑会非常慢,而且某些自定义算子直接就会报 no kernel image is available for execution on the device。我在一台 30 系的机器上遇到过一次:wheel 里带的是sm_80,而 3060 是sm_86,推理结果一直不对,查了很久才发现是 JIT 编译出来的 kernel 和 cuDNN 的算法选择对不上。所以我现在的习惯是,装完先打印算力列表,再跑一个最小前向,两分钟能省掉一整天。2. 驱动版本这张表,比任何教程都值得先看一眼2.1 驱动版本决定 CUDA 上限,而不是反过来这是最容易搞反的一层关系。你先装了一个 CUDA 12.8 的 Toolkit,然后发现驱动是 525 分支,跑程序报CUDA driver version is insufficient for CUDA runtime version——因为驱动 525 最高只支持 CUDA 12.0。反过来的顺序才是对的:先看驱动支持到哪个 CUDA,再决定装哪一版 Toolkit 和哪个 cu 后缀的 PyTorch。驱动分支支持的最高 CUDA说明470.x11.4长期支持分支,Ubuntu 仓库里常见,老项目仍在用515.x11.7对应 CUDA 11.7 时代的常用组合525.x12.0Ada 架构(40 系)的起步推荐535.x12.2稳定性口碑不错,生产环境常见550.x12.4覆盖面广,兼容性较均衡560.x12.6570.x12.850 系显卡的最低门槛575.x12.9较新的分支这里要补充一个很多人不知道的规则:从 CUDA 11 开始,NVIDIA 引入了minor version compatibility(次版本兼容)。意思是,同一个大版本内(比如 12.x),用较新小版本编译出来的程序,在只满足该大版本最低驱动要求的机器上,理论上也能跑。这条规则解释了一个常见现象——驱动 525 的机器上,cu126的 PyTorch 有时候居然能跑起来。但我不建议依赖它,原因有三个:第一,新架构的 kernel 在旧驱动上依然跑不了,这条规则救不了你;第二,cuDNN、TensorRT 这些库不走这条兼容路径;第三,一旦出错,报错信息会非常难懂,排查成本远高于直接升级驱动。所以我会把它当成救命用的手段,而不是常规方案。还有一个很实际的问题:有人问驱动版本装到 550 了,但 PyTorch 官方还没发布 CUDA 13 对应的 wheel 怎么办。答案是不用管。驱动向下兼容,toolkit 版本只是编译期的事,PyTorch wheel 里自带运行时,选一个 cu128 或 cu129 的包在支持 CUDA 13 的驱动上照样跑。反过来才不行——驱动老、wheel 新,那是真跑不起来。2.2 apt、runfile、NVIDIA App 三种安装路径的选择逻辑Ubuntu 下装驱动,主流就三条路,适用场景完全不同。apt 源安装最省事,也是我最推荐的起步方式。先扫一遍可用版本:sudo apt update sudo ubuntu-drivers devices输出里会列出推荐版本,然后sudo apt install nvidia-driver-550即可。它的优势在于走 DKMS 机制,内核升级之后驱动模块会自动重新编译,不需要你手动重装。缺点是可选的版本受仓库限制,新卡刚上市的时候可能没有对应的分支。装完重启,nvidia-smi能出表格就说明成了。runfile 安装适合需要精确控制版本、或者仓库里没有你要的分支的场景。流程长一些,而且有几个必做步骤:先禁用开源驱动 nouveau,否则会和 NVIDIA 的模块抢设备节点;然后切到文本模式执行安装器;安装时建议加上--no-opengl-files之类的参数避开和系统图形栈的冲突。我一般只在特定版本刚发布、仓库还没跟上时用这条路,因为内核升级后需要重新跑一遍安装器,长期维护成本更高。Windows 侧用 NVIDIA App 下载驱动,有个小问题经常被问到:下载的安装包到底落在哪。按我的经验,一般在C:\ProgramData\NVIDIA Corporation\下面按哈希命名的子目录里,不同版本的具体路径略有差别,而且这个目录默认是隐藏的,需要在文件资源管理器里打开显示隐藏项目才看得到。安装失败的时候,最常见的三个原因是:杀毒软件在解压阶段拦截了文件、上一个驱动版本残留没清干净、以及下载本身不完整(浏览器中断后留下一个残缺的包)。这种情况我通常会用专门的卸载工具在安全模式下彻底清一遍再重装,比反复点重试有效得多。2.3 装完黑屏、循环登录、nvidia-smi 失效的排查顺序驱动装完之后出问题,基本集中在这三种现象上,排查顺序建议固定下来,不要东试一下西试一下。第一步,确认 nouveau 是否真的被禁用了。检查/etc/modprobe.d/下有没有对应的黑名单配置,然后lsmod | grep nouveau,如果还有输出,说明禁用没生效,这时候不管你怎么重装驱动都没用。第二步,看内核日志。dmesg | grep -i nvidia能告诉你模块加载到哪一步失败的。常见的是编译失败(缺少内核头文件,装个linux-headers-$(uname -r)就能解决)和版本不匹配。第三步,检查 Secure Boot 状态。开了 Secure Boot 的机器,未签名的内核模块会被拒绝加载,表现为驱动装好了但nvidia-smi一直报错。用mokutil --sb-state看一眼,要么在 BIOS 里关掉,要么在首次安装时按提示设置签名密码。第四步,如果nvidia-smi报Failed to initialize NVML: Driver/library version mismatch,意思是内核模块的版本和用户态的库版本不一致。这通常发生在驱动自动升级之后没重启的情况,重启一次基本能解决;如果重启也不行,说明用户态库没更新干净,需要重新装一遍。提示:排查驱动问题的时候,尽量一次只改一个变量。我见过太多人同时换了驱动、CUDA 和 PyTorch,结果问题解决了也不知道是哪一步起的作用,下次遇到还是不会。3. CUDA Toolkit:系统级装和 conda 装不是一回事3.1 conda 里的 cudatoolkit 到底装了什么很多人学环境配置的第一条命令就是conda install cudatoolkit11.7 cudnn8.5,然后在自己的 conda 环境里跑得好好的,就以为CUDA 装好了。这个认知在跑纯 PyTorch 代码时没问题,但只要涉及源码编译就会翻车。原因是:conda频道里的cudatoolkit只包含运行时库,不包含nvcc编译器。它本质上是把 CUDA 的.so文件塞进环境目录,让 Python 进程能找到。你可以在环境里ls $CONDA_PREFIX/lib | grep libcudart,能看到库文件;但nvcc --version一定是找不到命令的。所以判断标准很简单:如果你的项目只需要跑推理和训练,conda 装法又快又干净;只要你需要编译任何带 CUDA 算子扩展的库(MMCV、Deformable DETR 的自定义算子、各种检测库的 C 扩展),就必须装一份系统级的完整 Toolkit。这两种方式可以共存,互不干扰——conda 环境里的运行时优先,系统 Toolkit 只在编译时被nvcc调用。顺带说一个常见误区:有人担心conda 环境里装的是 CUDA 11.7,系统装的是 12.4,会不会冲突。实际上运行时用的是 wheel 或 conda 包里自带的那一份,系统 Toolkit 版本不会直接影响它。真正会让程序崩的是驱动版本不够,这一点前面已经说过了。3.2 runfile 安装的完整流程与gzip: stdin: invalid compressed data的根因系统级 CUDA 我固定用 runfile 方式,因为可以精确控制安装路径,也方便多版本共存。标准流程是:# 下载后先校验完整性,官网页面会给出 MD5 md5sum cuda_12.8.0_570.86.10_linux.run # 只安装 Toolkit,不重复安装驱动(-toolkit 关键) sudo sh cuda_12.8.0_570.86.10_linux.run --toolkit --silent --override # 指定安装目录,便于多版本管理 sudo sh cuda_12.8.0_570.86.10_linux.run --toolkit --installpath/usr/local/cuda-12.8然后配置环境变量。我现在的做法是用ld.so.conf.d而不是往.bashrc里堆LD_LIBRARY_PATH,因为后者在多个环境之间切换时很容易互相污染:echo /usr/local/cuda-12.8/lib64 | sudo tee /etc/ld.so.conf.d/cuda-12.8.conf sudo ldconfig接下来重点说说那个gzip: stdin: invalid compressed>tar -xvf cudnn-linux-x86_64-9.x.x.x_cuda12-archive.tar.xz这个坑的原理值得多讲一句:tar的-z、-j、-J分别对应 gzip、bzip2、xz 三种压缩格式,传错了就会在管道里出现gzip 读到了非 gzip 数据的情况,报错信息千奇百怪,但本质就是格式不匹配。养成不加压缩参数的习惯,能省掉一大类莫名其妙的报错。3.3 多版本共存与切换:软链接才是关键一个真实的痛点:你手上同时有跑老项目的机器需求和跑新模型的需求,一个要 CUDA 11.8,一个要 12.8。这时候不要卸载重装,直接装到不同目录共存就行。/usr/local/下会出现cuda-11.8和cuda-12.8两个目录,而/usr/local/cuda是一个软链接,指向当前默认的那一个。切换的时候改软链接即可:sudo rm -rf /usr/local/cuda sudo ln -s /usr/local/cuda-11.8 /usr/local/cuda nvcc -Vnvcc -V会同时打印出两个版本号,格式是编译器版本(CUDA 版本),看到它们一致就说明切换成功了。另一种做法是用update-alternatives管理,适合需要频繁切换的场景,配置一次之后用sudo update-alternatives --config cuda一条命令切换。还有一种更省事的方案,就是不给全局挂 Toolkit,而是在需要编译的项目里临时指定环境变量:export CUDA_HOME/usr/local/cuda-12.8 export PATH$CUDA_HOME/bin:$PATH export LD_LIBRARY_PATH$CUDA_HOME/lib64:$LD_LIBRARY_PATH这个写法只影响当前终端会话,和全局默认版本互不干扰,特别适合平时用 12.8,偶尔要编译一个老项目的场景。4. cuDNN 不是装上就行,放置位置错了照样报错4.1 tar 包和 deb 包两种装法及各自适用场景cuDNN 的发行形式有三种:tar.xz归档、本地 deb 包、在线 deb 包。选择逻辑很简单。在线 deb 包最省心,一条命令搞定,以后还能通过apt upgrade更新。缺点是它会把 cuDNN 装到系统默认的 CUDA 路径,如果你是多版本共存的环境,往后切换的时候容易搞混。本地 deb 包适合不想额外加源、又想省事的情况。tar.xz 归档是我最常用的,因为它的放置位置完全由你决定,想放哪个 CUDA 目录就放哪个,多版本环境下特别好管理。缺点是需要手动拷文件,步骤不能少。下载页面上会有针对不同 CUDA 大版本的包,注意一定要选和你 Toolkit 大版本匹配的那一个,for CUDA 12.x的包放到 CUDA 11.8 的目录里,运行时会直接报符号找不到。4.2 手把手放置头文件和库文件解压之后,归档目录里是标准的include和lib两个子目录。放置的时候不要覆盖整个目录,只拷文件:tar -xvf cudnn-linux-x86_64-9.x.x.x_cuda12-archive.tar.xz cd cudnn-linux-x86_64-9.x.x.x_cuda12-archive # 头文件 sudo cp include/cudnn*.h /usr/local/cuda-12.8/include/ # 库文件 sudo cp lib/libcudnn* /usr/local/cuda-12.8/lib64/ # 补权限,这一步漏了必然报cannot open shared object file sudo chmod ar /usr/local/cuda-12.8/include/cudnn*.h sudo chmod ar /usr/local/cuda-12.8/lib64/libcudnn*这里有个从 cuDNN 8 开始出现的坑:库文件不再只有一个libcudnn.so,而是拆成了libcudnn_ops.so、libcudnn_cnn.so、libcudnn_adv.so、libcudnn_engines_precompiled.so等一堆。cuDNN 9 之后拆分得更细。所以拷贝的时候用通配符libcudnn*,别只拷libcudnn.so*,否则编译能过、一运行就报某个 engine 库找不到。4.3 怎么确认 cuDNN 真的被找到了放完文件,验证有三个层次,建议一个一个来。第一层,确认头文件里的版本号:grep CUDNN_MAJOR /usr/local/cuda-12.8/include/cudnn_version.h -A 2第二层,确认动态链接器能找到库:ldconfig -p | grep libcudnn这里要强调一下ldconfig。往lib64里拷完文件之后,必须跑一次sudo ldconfig,否则系统的库缓存还是旧的,程序依旧找不到新拷进去的库。这个动作我漏过不止一次,表现是明明文件在那儿,就是报找不到,非常容易怀疑人生。第三层,也是最直接的,让 PyTorch 自己报数:import torch print(CUDA available:, torch.cuda.is_available()) print(CUDA version:, torch.version.cuda) print(cuDNN version:, torch.backends.cudnn.version()) print(GPU:, torch.cuda.get_device_name(0))torch.backends.cudnn.version()打印出数字就说明一切都通了。如果这里打印的是 None,而前面torch.cuda.is_available()是 True,说明 PyTorch 用的是它 wheel 里自带的 cuDNN 而不是你系统装的——这在 pip 安装的场景下很正常,不算错误,因为 PyTorch 自己带的那份肯定是配得上的。5. PyTorch 安装:官网那行命令到底在选什么5.1 拆解 pip 命令里那串 index-urlPyTorch 官网给出的安装命令,长这个样子:pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu128很多人是复制粘贴党,从来不关心里面的cu128是什么。但一旦环境出问题,这几个字符就是关键。--index-url的意思是把 pip 的包索引用这个地址替换掉默认源,而不是追加。这个地址里放的是一批官方预编译好的 wheel,每个 wheel 都绑定了特定的 CUDA 版本和 Python 版本。cu128就表示这个 wheel 内置的是 CUDA 12.8 的运行时。安装完成之后,如果你的环境里有一堆nvidia-*-cu12开头的包,说明走的就是这条路。这是 PyTorch 从 2.0 之后采用的策略:把 CUDA 运行时作为普通 Python 依赖打包进来,好处是你不需要在系统里装任何 CUDA 就能跑 GPU 推理。需要区分的是另一个参数--extra-index-url,它是追加索引,容易出问题:同一个包在主源和附加源里都有时,pip 可能选到你不想要的那个版本。我建议除了极特殊的情况,统一用--index-url,别混着来。5.2 该选 cu118、cu126 还是 cu128选择的依据是两个变量的交集:显卡算力和驱动版本。我把常见组合列成表,照着选就行。显卡架构建议的 wheel 后缀最低驱动备注Turing(20 系)cu118 / cu121450.x / 525.xcu118 覆盖面最广,兼容性最稳Ampere(30 系)cu121 / cu124525.x3060 是 8.6,注意算力列表Ada(40 系,含 4060 Ti)cu124 / cu126 / cu128525.x8.9,主流 wheel 都覆盖Hopper(H100)cu124 / cu126525.x数据中心卡,建议跟官方推荐版本Blackwell(50 系)cu128 起570.x旧版本 Toolkit 不认 sm_120具体到 4060 Ti 这种卡,它是 Ada 架构、算力 8.9,cu118的包就能跑,但我更推荐cu124或cu126,理由是:新一点的轮子在大批量卷积和对 attention 的优化上通常会好一些;而且配 550 及以上分支的驱动时,整体匹配度更高,不容易出现某些库走 fallback 路径的情况。还要提一个反直觉的结论:如果你完全不需要源码编译,系统里的 CUDA Toolkit 装哪个版本其实无所谓。因为运行时用的是 wheel 自带的那一份。真正被 Toolkit 版本卡住的,只有 MMCV 这种需要现场编译的场景。5.3 conda 与 pip 装 PyTorch 的取舍conda频道里也能装 PyTorch,写法是conda install pytorch pytorch-cuda12.4 -c pytorch -c nvidia。我不太推荐在纯 PyTorch 场景下用,理由有两个。一是依赖解析太慢,有时候一个新环境要算好几分钟,而且它会连带把 MKL、各种数值库的版本一起调整,有时候会意外降级你环境里其他包。二是那个pytorch-cuda参数和 conda 自带的cudatoolkit名字很像,但作用完全不同,新手极容易搞混——前者是挑 wheel 的 CUDA 版本,后者是往环境里放运行时库。我的习惯是:conda 只用来管 Python 版本和虚拟环境,pip 用来装 PyTorch 和生态里的所有包。这样环境干净,版本关系也一目了然。装之前记得确认 conda 环境里的 pip 是它自己的那一个,不然可能装到 base 环境去了,检查方法:which pip # 应该输出 .../miniconda3/envs/你的环境名/bin/pip5.4 装完必须跑的验证代码装完别急着跑项目,先花两分钟做一遍完整验证。我固定跑这三段:# 第 1 段:基础可用性 import torch print(torch:, torch.__version__) print(built with cuda:, torch.version.cuda) print(cuda available:, torch.cuda.is_available()) print(device count:, torch.cuda.device_count()) # 第 2 段:真实算一遍,排除能检测到但跑不了的情况 x torch.randn(4096, 4096, devicecuda) y torch.randn(4096, 4096, devicecuda) z x y torch.cuda.synchronize() print(matmul ok:, z.shape, z.dtype) # 第 3 段:走一遍卷积,验证 cuDNN 真的在参与 conv torch.nn.Conv2d(64, 128, 3, padding1).cuda() inp torch.randn(8, 64, 128, 128, devicecuda) out conv(inp) torch.cuda.synchronize() print(conv ok:, out.shape) print(cudnn version:, torch.backends.cudnn.version())第 2 段和第 3 段的必要性在于:torch.cuda.is_available()只是问驱动能不能看到卡,它不验证 kernel 能不能真正执行。.cuda()调用能成功但前向崩掉的情况我遇到过,原因就是 wheel 里没带对应算力的 kernel。6. MMCV:torch 2.7 之后的安装路线6.1 mmcv、mmcv-lite、mmengine 三者的分工从 MMCV 2.x 开始,这套库被拆成了三个包,职责划分很清楚,但刚接触的人很容易装错。mmengine是运行时框架,提供训练循环、注册器、配置系统这些与算子无关的基础设施。它不涉及编译,mim install mmengine直接装就行。mmcv是完整版,包含需要编译的 CUDA 和 C 扩展,比如可变形卷积、各种 IoU 的 GPU 实现、NMS 等。你要跑检测、分割模型,基本都是这个。mmcv-lite是精简版,只有 Python 部分,不含任何编译扩展。如果你的项目只是调用配置系统、加载图像、做数据预处理,完全不碰自定义算子,装它最省事——不会遇到任何编译问题。判断该装哪个的方法很简单:打开项目代码,搜一下有没有from mmcv.ops import。有就装完整版,没有就装 lite 版。6.2 为什么 50 系显卡必须源码编译OpenMMLab 的预编译 wheel 索引是按cu{版本}/torch{版本}的维度组织的,路径形如.../mmcv/dist/cu121/torch2.1/index.html。从这个结构能看出问题所在:它需要为每一个 CUDA 版本和 PyTorch 版本的组合单独编译一次,组合数量是爆炸式增长的。结果就是,预编译索引的更新速度长期落后于 PyTorch 的发布节奏。我最近几次在 torch 2.5 以上的环境里装 mmcv,官方索引里都没有现成的包,只能源码编译。到了 50 系显卡这里更是双重打击:不仅 torch 版本对不上,算力目标sm_120也要求 CUDA 12.8 以上,而索引里的组合大多停留在更早的 CUDA 版本。所以结论很明确:torch 2.7 及以上、或者使用 50 系显卡的环境,直接用源码编译,不要再花时间找预编译包了。找包花的时间比编译多得多。6.3 源码编译的完整命令与关键环境变量我按顺序把可复制的步骤写出来。假设你已经有一个可用的 CUDA 12.8 Toolkit 和匹配的驱动。# 1. 建一个干净的环境,Python 版本别太新,3.10 是最稳的 conda create -n mmcv27 python3.10 -y conda activate mmcv27 # 2. 装 torch,50 系必须 cu128 pip install torch2.7.0 torchvision0.22.0 --index-url https://download.pytorch.org/whl/cu128 # 3. 装构建工具和 mmengine pip install -U openmim ninja mim install mmengine # 4. 拉源码,分支和你要用的版本对齐 git clone https://github.com/open-mmlab/mmcv.git -b v2.2.0 cd mmcv pip install -r requirements/runtime.txt # 5. 开始编译,这几个环境变量是关键 export CUDA_HOME/usr/local/cuda-12.8 export PATH$CUDA_HOME/bin:$PATH export TORCH_CUDA_ARCH_LIST12.0 export MAX_JOBS4 MMCV_WITH_OPS1 pip install -e . -v --no-build-isolation这里逐个解释关键变量的作用,这些是文档里一句带过、但出错就卡死的地方。CUDA_HOME必须指向完整的 Toolkit 目录,编译脚本靠它找nvcc和头文件。找不到就会报cuda_runtime.h: No such file or directory。TORCH_CUDA_ARCH_LIST指定要编译哪些算力目标。这一项不设的后果是编译极慢,因为默认会为一大堆算力值各编译一遍。50 系就写12.0,40 系写8.9,多张不同架构的卡可以写8.6;8.9。这个值和显卡不匹配的典型报错是nvcc fatal: Unsupported gpu architecture compute_120,出现它就说明你的 Toolkit 太老了。MAX_JOBS控制并行编译的进程数。这个变量的重要性很多人低估了:编译 CUDA 扩展极其吃内存,每增加一个并行任务,内存占用基本线性增加。MAX_JOBS4大致需要十几 GB 内存,小内存机器上被 OOM Killer 杀掉编译进程是家常便饭,表现是编译到某个 .cu 文件突然中断、没有任何明确报错。机器内存小于 32GB 的话,我建议直接设成 2。--no-build-isolation必须加。pip 默认会为构建过程创建一个隔离的临时环境,那个环境里没有 torch,于是报ModuleNotFoundError: No module named torch。加上这个参数就是让构建过程直接用当前环境的依赖。MMCV_WITH_OPS1是打开扩展编译的开关。漏了它,pip install会顺利成功,但你import mmcv.ops的时候才发现模块不存在,白编译一场。6.4 编译报错的高频原因对照编译 MMCV 的报错种类不算多,我整理了一个对照表,按报错信息直接查。报错信息片段根因处理方式ModuleNotFoundError: No module named torch构建隔离环境里没有 torch加--no-build-isolationcuda_runtime.h: No such fileCUDA_HOME没设或指错指向完整 Toolkit 目录并加入 PATHnvcc fatal: Unsupported gpu architectureToolkit 版本低于显卡算力要求升级 Toolkit(50 系需 12.8)编译到某个文件突然中断,无明确错误内存不足被系统杀掉调小MAX_JOBSninja: command not found缺并行构建工具pip install ninjaunsupported GNU versiongcc 版本超出 CUDA 支持范围换用较低版本 gcc,如 gcc-11undefined reference to c10::cuda::...头文件缺失或 torch 版本不匹配补全 include,或换 mmcv 分支编译成功但import mmcv.ops报错忘了开MMCV_WITH_OPS1重新编译这张表里我特意把最后一条列出来了,因为它的欺骗性最强:整个编译过程一切正常,没有任何红色报错,装完之后才发现核心模块根本不存在。判断方法也简单,编译结束时留意输出里有没有出现Building wheel for mmcv和一堆.cu文件的编译日志,如果只是几秒钟就结束了,那基本可以确定没在编译算子的部分。Windows 上编译还有一层额外麻烦:需要 Visual Studio 的 MSVC 工具链,而且版本要和 CUDA Toolkit 支持的列表对上。安装 CUDA Toolkit 时如果弹出no supported version of Visual Studio was found,说明本机的 VS 版本不在支持列表里,这时候在自定义安装里取消勾选 Visual Studio Integration 组件即可,不影响 Toolkit 本身的安装。不过说实话,我现在的建议是:Windows 上别硬刚编译,直接上 WSL2。在 WSL 里装 CUDA 有一条重要的注意事项——不要在 WSL 里安装 Linux 版显卡驱动,Windows 主机上的驱动会自动映射到 WSL 内部,WSL 里只需要装 Toolkit 就行,装错了反而会把映射覆盖掉,导致 GPU 不可用。再补一个常见场景。有人在 Ubuntu 22.04 上跑 CARLA 0.9.15,同时也要跑 PyTorch 训练,担心驱动版本要装两遍。实际上 CARLA 用的是自己预编译好的渲染引擎,它依赖的是系统的图形驱动和 Vulkan/OpenGL 支持,并不要求你装 CUDA Toolkit。所以两边的需求是可以合并的:挑一个能满足 CARLA 启动要求、同时又能覆盖你要用的 PyTorch wheel 的驱动版本,一次装好即可。我一般直接上 550 及以上的分支,CARLA 和 PyTorch 都能兼顾。7. 一套可复用的环境自检脚本与组合速查7.1 十分钟跑完的自检脚本环境配完之后,我固定跑一遍下面这个脚本,它把前面提到的所有检查项串起来了。存成check_env.sh,以后换机器直接拷过去用。#!/usr/bin/env bash echo 1. 驱动与显卡 nvidia-smi --query-gpuname,driver_version,compute_cap --formatcsv echo 2. 系统 Toolkit nvcc -V 2/dev/null || echo 未检测到 nvcc(只跑 wheel 的话可以没有) readlink -f /usr/local/cuda echo 3. cuDNN 头文件 grep -m1 CUDNN_MAJOR /usr/local/cuda/include/cudnn_version.h 2/dev/null \ || echo 系统路径下未找到 cuDNN 头文件 echo 4. 动态链接情况 ldconfig -p | grep -E libcudnn|libcudart | head -5 echo 5. PyTorch python - PY import torch print(torch:, torch.__version__) print(built cuda:, torch.version.cuda) print(available:, torch.cuda.is_available()) if torch.cuda.is_available(): print(gpu:, torch.cuda.get_device_name(0)) print(compute cap:, torch.cuda.get_device_capability(0)) print(arch list:, torch.cuda.get_arch_list()) print(cudnn:, torch.backends.cudnn.version()) x torch.randn(2048, 2048, devicecuda) print(matmul:, (x x).shape) PY几个输出项的含义值得解释清楚。nvidia-smi带--query-gpu参数能直接输出显卡名、驱动版本和算力等级,比你打开表格自己找快得多。readlink -f /usr/local/cuda会解析出软链接最终指向哪个版本目录,一眼就能看出当前默认 Toolkit 是哪个。arch list那一行前面说过了,是最有价值的检查项。compute_cap这个查询字段在不同驱动版本上支持情况不一致,老驱动上可能报错,这种情况直接用torch.cuda.get_device_capability(0)也行,它返回一个元组,比如(8, 9)就是 8.9。7.2 常见组合速查与场景对照把前面零散的信息汇总成两张表,配环境的时候直接对照。表一:从显卡出发反推整套配置你的显卡算力建议驱动建议 PyTorch wheelMMCV 装法RTX 20 系7.5535cu118优先找预编译包RTX 30 系8.6535cu121 / cu124预编译包或源码编译RTX 40 系(含 4060 Ti)8.9550cu124 / cu126torch 2.5 以上建议源码编译RTX 50 系12.0570cu128必须源码编译A100 / H1008.0 / 9.0550cu124 / cu126看 PyTorch 版本决定表二:从报错现象反查该动哪一层现象最可能出问题的层优先排查方向torch.cuda.is_available()为 False驱动驱动版本、Secure Boot、nouveauCUDA driver version is insufficient驱动 / wheel 后缀驱动是否支持 wheel 的 CUDA 版本no kernel image is availablewheel 的算力覆盖打印 arch list,考虑源码编译libcudnn.so not foundcuDNN库文件位置和ldconfignvcc fatal: Unsupported gpu architectureToolkit升级到支持该算力的版本编译中途无声中断内存调小MAX_JOBS编译成功但mmcv.ops不存在编译开关检查MMCV_WITH_OPS1gzip: stdin: invalid compressed data安装包校验 MD5,检查解压参数最后再说一下版本查询这件事,因为被问得最多。想查系统装了哪些 CUDA 版本,看/usr/local/下有几个cuda-*目录,配合nvcc -V确认当前默认的那个。想查 cuDNN 版本,看cudnn_version.h里的CUDNN_MAJOR/MINOR/PATCHLEVEL三个宏,或者直接python -c import torch; print(torch.backends.cudnn.version())。想知道驱动支持到哪个 CUDA,只看nvidia-smi右上角那一行就够了,注意那是能力上限,不是已安装版本。我个人在这些年的实际操作中最大的体会是:配环境这件事,顺序比版本更重要。先确认显卡型号和算力,再确认驱动能支持到哪个 CUDA,然后才去选 PyTorch 的 wheel 后缀,最后才考虑 MMCV 是装预编译还是编译源码。每一步都有明确的依据,不靠猜。反过来,如果上来就复制一堆安装命令挨个跑,那么每次报错你都会在五个层之间来回猜,浪费的时间远超一开始花十分钟做规划的成本。还有个小技巧分享给经常换机器的同学:把check_env.sh和一份自己验证过的版本组合记在一个笔记文件里,换机器的时候先跑脚本、再对照笔记,整套环境通常半小时内能搞定。这比每次重新搜教程可靠得多,因为你自己验证过的那套组合,才是真正跑得通的组合。