写这篇记录之前,我先说个实际现象:群里隔三差五就有人截图报错,要么是torch.cuda.is_available()返回False,要么是编译某个算子时提示libcudnn.so: cannot open shared object file。这些问题翻来覆去,根儿都出在同一个地方——PyTorch和CUDA、cuDNN、显卡驱动之间的版本关系没捋顺。
PyTorch本身只是一个深度学习框架,它要跑在GPU上,就绕不开CUDA这个并行计算平台,也绕不开cuDNN这个深度神经网络加速库。很多新手容易把它们当成三个独立的东西分别安装,装上之后发现彼此对不上,折腾半天也不知道哪里出了问题。这篇记录我按自己实际排查的顺序来写,把三者之间的关系讲清楚,再把安装、验证、排错的过程完整走一遍。无论你是刚接触PyTorch,还是已经跑过几个模型但被环境问题折磨过,这篇都值得看完。
1. 先搞清楚你真正需要的是什么:CUDA、cuDNN、PyTorch三者的关系
1.1 三个名词到底在说什么
先说CUDA。CUDA是显卡厂商推出的通用并行计算架构,它不只是安装在系统里的一个软件,而是从硬件架构到软件栈的一整套体系。显卡硬件支持CUDA,驱动负责和系统交互,CUDA Toolkit则提供开发库、编译器(比如nvcc)、运行时库和调试工具。
再说cuDNN。cuDNN是基于CUDA的深度神经网络加速库,专门优化卷积、池化、归一化、RNN这些深度学习常用算子。PyTorch在GPU上跑卷积神经网络时,底层大量调用cuDNN的算子实现。没有cuDNN,很多模型也能跑,但速度会明显变慢,某些算子甚至没有可用的高效实现。
最后是PyTorch。PyTorch官方发布的安装包,会自带一套它编译好的CUDA运行时和cuDNN动态库。这句话是理解后面所有问题的关键:你安装PyTorch时选的那个CUDA版本,决定的是PyTorch内部使用的运行时库版本,而不是你系统里CUDA Toolkit的版本。
1.2 运行时CUDA和编译时CUDA的区别
这一条是大多数环境冲突的根源。
PyTorch在官网上给安装命令时,会标注cu118、cu121这样的标识,这个标识表示PyTorch是基于哪个CUDA版本编译的。比如cu118就是基于CUDA 11.8编译出来的二进制包。这个包内部带了CUDA运行时库(libcudart)和cuDNN库(libcudnn),PyTorch运行时优先使用自己打包的这套库,而不是去系统目录里找。
这就是为什么很多人不装CUDA Toolkit,也能正常使用GPU版本的PyTorch——因为PyTorch的wheel包已经把那套运行库打包进来了。
那什么时候需要系统级的CUDA Toolkit?当你需要自己编译CUDA扩展算子、安装需要源码编译的第三方库,或者使用特定版本的nvcc编译器时,才需要系统里有一个完整可用的CUDA Toolkit。日常训练推理,根本用不着手动装一个单独的CUDA Toolkit。
1.3 驱动、工具包、运行库三者版本怎么配套
显卡驱动、CUDA Toolkit、PyTorch自带运行库,这三者的版本关系可以这样理解:
- 显卡驱动:负责最底层硬件交互,它有一个最高支持的CUDA版本。驱动版本过低,高版本CUDA就没办法跑。
- CUDA Toolkit:如果你自己装了,它提供编译和运行环境,版本可以比驱动支持的CUDA版本低,但不能更高。
- PyTorch自带运行库:随PyTorch下载,手写Python代码时它负责运行时工作,通常不感知系统CUDA Toolkit。
最省心的做法是:先看显卡驱动支持的CUDA版本上限,再选择一个不超过这个上限的PyTorch CUDA版本。驱动支持的CUDA版本可以通过nvidia-smi右上角看到,PyTorch版本在官网查对应关系。
提示:驱动向下兼容很好,高版本驱动可以跑低版本CUDA程序,但低版本驱动跑不了高版本CUDA程序。所以驱动尽量保持较新版本,给后面留出余地。
2. 动手前先收集这几条关键信息
2.1 检查显卡驱动状态
不管你重装多少次PyTorch,第一步永远是查驱动。很多报错查到最后,其实是驱动掉了或者版本太老。
在终端里输入:
nvidia-smi正常情况下会输出显卡型号、驱动版本、显存使用量。注意右上角的“CUDA Version”这一项,它表示当前驱动最高能支持到哪个CUDA版本。比如说显示CUDA Version: 12.4,那你的环境理论上最多支持CUDA 12.4及以下的程序,装一个要求CUDA 12.6的PyTorch版本就有风险。
如果nvidia-smi提示找不到命令,先不要急着装CUDA Toolkit,先确认驱动是否安装成功。在Linux系统上可以查看:
ls /proc/driver/nvidia/version能看到版本号说明驱动模块加载了。如果这里也什么都没有,那就是驱动没装好,需要先把显卡驱动搞定,PyTorch环境才能继续。
2.2 确定PyTorch想要的CUDA版本
打开PyTorch官网首页,安装命令里会有明确的CUDA版本选择。不同版本的PyTorch对应的CUDA版本是固定的,选择时要看两个约束:一是你自己的驱动是否能支持,二是和你项目里的其他依赖是否兼容。
比较稳定常见的几个搭配:
| PyTorch版本 | 可选CUDA版本示例 |
|---|---|
| PyTorch 1.13 | cu116 / cu117 |
| PyTorch 2.0 - 2.1 | cu117 / cu118 |
| PyTorch 2.2 - 2.3 | cu118 / cu121 |
| PyTorch 2.4 及以上 | cu118 / cu121 / cu124 |
我自己的判断标准是:不盲目追求最新CUDA版本,选一个稳定、生态支持多、踩坑少的组合。目前CUDA 11.8的生态非常成熟,第三方库几乎全覆盖;CUDA 12.1也不错,支持新架构。新驱动就用高一点的版本,老驱动就老老实实留在11.8。
2.3 查询现有环境的Python与包管理工具
PyTorch对Python版本有要求,很老的Python跑不了新版本PyTorch。安装前先确认:
python --version如果你用的是conda环境,顺便看一眼当前环境和包管理工具信息:
conda env list一个环境一套Python版本,不要一个环境里混着用系统Python和conda Python。我自己遇到过一次很隐蔽的问题:终端里python指向的是系统Python,但pip指向了conda环境里的pip,结果包装到了不同环境里,import torch怎么都是No module named。最后用which python和which pip查了一下,才发现路径对不上。
3. 安装实操:从conda到pip,我建议的路径和理由
3.1 为什么推荐先选conda包
PyTorch的安装方式主要两种:conda和pip。如果条件允许,我更推荐先用conda安装PyTorch。
原因在于conda会自动处理CUDA相关依赖。你在conda里安装pytorch、pytorch-cuda这几个包时,conda会连带把配套的CUDA运行时库、cuDNN装到同一个环境里。在conda环境里运行PyTorch,不需要额外手动配置系统级CUDA。
安装命令一般长这样:
conda install pytorch torchvision torchaudio pytorch-cuda=12.1 -c pytorch -c nvidia这里的pytorch-cuda=12.1就是指定conda环境的CUDA支持版本。装完以后,import torch和torch.cuda.is_available()大概率不会有问题,因为conda把依赖关系都解析好了。
3.2 pip安装时需要手动补的依赖
如果你用pip安装PyTorch,情况稍微复杂一点。以CUDA 11.8为例,官方给出的pip安装命令是:
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118pip安装的torch wheel包同样内置了运行时CUDA库,所以日常用没问题。但是如果你后续要装带CUDA扩展的第三方库,比如某些需要编译的算子库,那系统里最好有对应的CUDA Toolkit。
装CUDA Toolkit时注意一件事:不要覆盖驱动。CUDA Toolkit安装时如果选了“Install NVIDIA Driver”,它可能会尝试安装一个自带驱动,这个驱动通常比你现在用的驱动旧,搞不好就把驱动版本降级了。正确做法是只安装Toolkit,不选驱动。
# Ubuntu系统示例(具体参数因版本而异) wget https://developer.download.nvidia.com/compute/cuda/11.8.0/local_installers/cuda_11.8.0_520.61.05_linux.run sudo sh cuda_11.8.0_520.61.05_linux.run --toolkit --silent --override装完后把路径写进~/.bashrc:
export PATH=/usr/local/cuda-11.8/bin:$PATH export LD_LIBRARY_PATH=/usr/local/cuda-11.8/lib64:$LD_LIBRARY_PATH3.3 版本锁定与后续升级建议
装完以后,建议把关键包的版本锁定住,防止后续某个依赖被意外升级导致环境损坏。
pip freeze | grep -E "torch|numpy|nvidia"或者用conda导出环境:
conda env export > environment.yml以后换机器或者重建环境时,直接基于这个文件恢复。PyTorch升级时要特别小心:别直接pip install -U torch,因为这会顺手升级很多依赖,可能把numpy、cuda相关的包冲突出来。正规做法是创建一个新conda环境,在新环境里安装新版本PyTorch,测试通过后再切换。
4. 安装完成后的验证清单
4.1 验证GPU可用性
装完第一件事,跑这几行:
import torch print(torch.__version__) print(torch.version.cuda) print(torch.cuda.is_available()) print(torch.cuda.get_device_name(0))逐行解释一下:
torch.__version__:看PyTorch版本。torch.version.cuda:看PyTorch编译时对应的CUDA版本。torch.cuda.is_available():返回True代表GPU可用,False就是环境有问题。torch.cuda.get_device_name(0):看GPU型号是否正确识别。
这个验证是最基础的,先把前几项跑通,再往下走。手动验证可以再加一行:
x = torch.randn(3, 3).cuda() print(x)能正常输出矩阵,说明张量已经能放到GPU上运算,基础链路没问题。接下来再跑一个真正的卷积计算,验证cuDNN是否在正常工作:
import torch.nn as nn conv = nn.Conv2d(3, 16, kernel_size=3, padding=1).cuda() data = torch.randn(8, 3, 32, 32).cuda() out = conv(data) print(out.shape)如果这个能跑通,说明cuDNN的卷积算子调用正常。此时在代码里加上torch.backends.cudnn.benchmark = True,还可以让cuDNN自动搜索最优卷积算法,小输入可能不明显,大模型训练时速度提升很明显。
4.2 验证cuDNN版本
PyTorch内置的cuDNN版本和系统里单独装的那个cuDNN是有区别的。若要查看PyTorch内置的cuDNN版本:
print(torch.backends.cudnn.version())这个输出通常是一串数字,比如8700表示cuDNN 8.7.0。如果提示False或0,说明cuDNN没有被正确加载,或者当前设备不支持。此时卷积计算可能退回自定义实现,速度会变慢很多。
如果系统里你自己装了cuDNN,可以用这个命令看系统版本:
cat /usr/local/cuda/include/cudnn_version.h | grep CUDNN_MAJOR -A 2大多数情况下,PyTorch优先使用自己打包的cuDNN,系统里的版本影响不大,只有在编译第三方库时才需要关注两者是否匹配。
4.3 验证多卡和内存分配
多卡用户需要额外验证:
print(torch.cuda.device_count()) print(torch.cuda.current_device())device_count()返回可用GPU数量,如果这里返回0但明明有显卡,先回去查驱动。显存信息用:
nvidia-smi可以看到每张卡的内存占用。我遇到过一种情况:程序退出后显存没有完全释放,nvidia-smi显示还有几个G被占用,这时候torch.cuda.get_device_name(0)依然正常,但新程序可能因显存不足报错。排查时先看有没有残留的Python进程:
ps aux | grep python有的话kill掉,显存就释放了。张量使用的显存还可以通过torch.cuda.memory_allocated()查看,调试显存泄漏很有用。
5. 常见报错与排查记录
5.1 明明装了CUDA却说不可用
这个报错场景太常见了。torch.cuda.is_available()返回False,但nvidia-smi明明有显卡。
排查第一步:先看你安装的PyTorch是什么版本。如果你的PyTorch是CPU版本(pip list | grep torch里显示torch而不是torch相关GPU包),那不管驱动多新都不可能用上GPU。重新安装GPU版本即可。
第二步:看驱动是否支持你选择的CUDA版本。PyTorch 2.4的cu121需要驱动支持CUDA 12.1,如果nvidia-smi显示驱动只支持到11.4,那就需要升级驱动,或者换低CUDA版本的PyTorch。
第三步:检查是不是conda环境里混用了包。有时候conda里安装了CPU版的torch,又用pip安装了GPU版,两个版本互相干扰,import torch时导入了CPU版本。用python -c "import torch; print(torch.__file__)"查看实际导入路径,确定它来自哪个环境。
5.2 编译期报错libcudnn.so找不到
自己编译和CUDA相关的第三方库时,经常遇到:
error while loading shared libraries: libcudnn.so.8: cannot open shared object file: No such file or directory这个报错说明动态链接库路径没配置好。在编译和运行前,先确认系统里的cuDNN库文件实际位置:
find /usr/local -name "libcudnn.so*"找到后把所在目录加入LD_LIBRARY_PATH:
export LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH这里有个细节值得注意:libcudnn.so后面通常带版本号,比如libcudnn.so.8.0.5。编译时有时需要libcudnn.so这个不带版本号的链接文件。如果只装了runtime包,可能没有这个链接文件,需要安装dev版本,或者手动创建软链接:
sudo ln -s /usr/local/cuda/lib64/libcudnn.so.8 /usr/local/cuda/lib64/libcudnn.so还有种情况是Python启动时找不到库,说明环境变量没生效。要么重启终端,要么在代码里手动指定:
import os os.environ['LD_LIBRARY_PATH'] = '/usr/local/cuda/lib64:' + os.environ.get('LD_LIBRARY_PATH', '')5.3 nvcc -V和nvidia-smi显示的版本不一致
很多人会以为nvcc --version显示的CUDA版本必须和nvidia-smi一致,其实不是。
nvcc -V显示的是系统里CUDA Toolkit的版本;nvidia-smi右上角显示的是驱动最高支持的CUDA版本。两者不一致很正常,只要Toolkit版本不高于驱动版本就好。比如驱动显示CUDA 12.4,工具包是11.8,没问题;反过来工具包12.1,驱动只支持12.0,那就有麻烦了。
这个理解很重要,因为很多教程里会让人装“对应的CUDA”,实际上对PyTorch用户来说,驱动版本足够高就行,工具包版本反而没那么关键。千万别因为看到两个版本不一致,就把驱动或者工具包卸载重装,那样白白浪费时间。
5.4 和系统自带库冲突
Linux系统里遇到比较多的问题是OpenMP库冲突。
报错长这个样子:
libgomp.so.1: cannot allocate memory in static TLS block这个问题的根源是PyTorch自带的OpenMP库和系统或conda里的另一个OpenMP库冲突。网上很多建议让卸载conda里的libgomp包改名,但更稳妥的办法是尝试用系统OpenMP覆盖PyTorch自带的:
export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libgomp.so.1或者使用OMP_NUM_THREADS=1临时规避某些场景下的崩溃。这个坑在不同Linux发行版上表现不一样,处理时要有针对性,不要一上来就重装。
5.5 问题速查表
| 现象 | 可能原因 | 处理办法 |
|---|---|---|
| torch.cuda.is_available()返回False | 装了CPU版PyTorch | 重新安装GPU版 |
| torch.cuda.is_available()返回False且nvidia-smi正常 | 驱动版本不支持对应CUDA版本 | 升级驱动或降低CUDA版本 |
| import torch报错No module named | Python和pip路径不一致 | 统一使用同一环境下的Python和pip |
| 编译时报libcudnn缺失 | LD_LIBRARY_PATH未配置或未装cuDNN | 设置动态库路径/安装cuDNN dev包 |
| nvcc -V和nvidia-smi版本不一致 | ToolKit版本与驱动版本不同 | 无需处理,ToolKit不低于驱动版本即可 |
| 显存一直不清空 | 存在残留进程 | ps查Python进程后kill |
| 启动时libgomp报错 | OpenMP库冲突 | LD_PRELOAD指定系统libgomp或调整线程数 |
| 训练刚开始就OOM | 显存分配不均或数据批量太大 | 调小batch size,或清理缓存torch.cuda.empty_cache() |
最后说一点个人体会。很多人一遇到PyTorch环境问题就想着全部卸载重装,其实绝大多数问题都能通过查版本对应关系解决。我把排查顺序固定成了这样:先看驱动支持上限,再选PyTorch的CUDA版本,最后才考虑CUDA Toolkit装不装、装哪个版本。按这个顺序来,我在新机器上配置环境基本一次过。另外建议每次配置环境都随手把nvidia-smi输出、torch.__version__、torch.version.cuda这三条信息保存成一个文本文件,以后排查问题直接对照,能省非常多时间。