
1. 驱动、Toolkit、cuDNN、框架四层责任先划清把 Ubuntu 上的 CUDA 环境装崩八成不是因为命令敲错而是因为一开始就没搞清这几层东西谁管谁。我见过太多人拿着nvidia-smi右上角那行CUDA Version: 12.4就以为自己已经装好了 CUDA 12.4然后nvcc -V一敲发现命令不存在接着开始怀疑人生。先把这四个东西的职责说透显卡驱动Driver内核模块 用户态库负责让操作系统能跟 GPU 说话。它决定了你这台机器最多能跑哪个版本的 CUDA 运行时。CUDA Toolkit编译器nvcc、头文件、静态/动态库、profiler、数学库cuBLAS、cuFFT、cuSPARSE 等。这是你写 CUDA 代码、编译 CUDA 项目时真正要用的一整套工具。cuDNN在 CUDA 之上的一层深度神经网络专用库做卷积、池化、RNN、Attention 等算子的高度优化实现。它不做编译只提供头文件和.so。深度学习框架PyTorch / TensorFlow调 cuDNN 和 cuBLAS 的上层应用。有意思的是pip 装的 PyTorch 会自带一份 CUDA runtime它跟你系统里/usr/local/cuda那套可以不是同一个版本。一个特别容易误导人的点是nvidia-smi右上角显示的CUDA Version指的是当前驱动支持的最高 CUDA 运行时版本不是你装了哪个版本。我第一次看到这个数字的时候也以为被系统自动装好了结果/usr/local下面空空如也。用个类比驱动是家里的电源插座标准220V 还是 110VCUDA Toolkit 是你买的一整套电动工具cuDNN 是这套工具里专门用来切硬木的锯片框架就是拿这些工具干活的木工。插座标准决定了你能用哪些电器但插座本身不会给你一把电钻。再补一个反直觉的点驱动是向下兼容的不是向上兼容的。新驱动能跑旧 CUDA runtime旧驱动跑不了新 CUDA runtime。所以「我驱动版本比较老能不能装新版 CUDA」这个问题答案是基本不行正确做法是先升驱动。组件查看命令说明驱动nvidia-smi显示驱动版本与支持的最高 CUDA 运行时Toolkitnvcc -V或nvcc --version显示实际安装的编译器/toolkit 版本cuDNN查cudnn_version.h里的宏头文件在/usr/local/cuda/include框架torch.version.cuda框架自带编译时的 CUDA 版本还有一点Ubuntu 官方源里有个包叫nvidia-cuda-toolkitapt install一下确实能装上但版本通常停留在 11.x 甚至 10.x而且在 22.04/24.04 上还会顺带拖进一堆你不想要的依赖。想省事的话这条路可以试但如果你要跑比较新的框架或者要编译带 CUDA 的 OpenCV这个版本基本就是自找麻烦。我的建议是官方源只用来装驱动Toolkit 一律走 NVIDIA 自己的源。2. 版本矩阵怎么定从显卡算力和框架需求倒推选定版本这件事很多人是从「最新的是哪个」开始的这是个错误方向。正确的推导顺序是先定框架版本 → 再定 CUDA 版本 → 最后确认驱动够不够新。第一步看你的卡是什么架构、什么算力Compute Capability。算力决定了 CUDA 编译器要为目标生成哪种 SASS 指令sm_89、sm_86、sm_75这些数字就是它。显卡举例架构算力最低可用 CUDARTX 4090 / 4080 / 4070 / 4060 TiAda Lovelace8.911.8RTX 3090 / 3080 / 3070 / A100(80G 除外)Ampere8.611.1A100 80GAmpere8.011.0RTX 2080 / 2070 / T4Turing7.510.0RTX 1080 Ti / 2080 之前Pascal6.18.0猛一看 4060 Ti 只需要 CUDA 11.8好像挺宽松但别急还有第二步。第二步看框架官方支持哪个 CUDA。PyTorch 的官网上每个版本都绑定了几套 CUDA 编译产物。以近两年的情况为例cu118、cu121、cu124是最常见的几个尾巴。如果你手上的项目代码用的是某个特定的 PyTorch 版本那 CUDA 版本基本就被锁死在它支持的那几个里了。TensorFlow 更死板它的 wheel 跟 CUDA / cuDNN 版本是一对一硬绑定的版本差一点就ImportError。第三步倒查驱动。CUDA 版本对驱动有最低要求这个表在 NVIDIA 官方的 CUDA Toolkit Release Notes 里有一份「Table 3. CUDA Toolkit and Corresponding Driver Versions」。大致规律是CUDA 版本Linux 最低驱动近似11.852012.052512.153012.253512.354512.455012.555512.6560注意上面的驱动版本是「最低要求」具体以官方 Release Notes 为准。不同小版本可能微调而且.run安装包自带的驱动版本会和要求略有差异。如果你nvidia-smi显示的驱动版本低于目标 CUDA 的要求只有两个选择升级驱动或者降低 CUDA 版本。不要尝试用--override强行跳过驱动检查那只是把报错从安装阶段推迟到运行阶段而且运行阶段的报错会更难查。顺便说一句很多人问 4060 Ti 能不能用。能Ada 架构支持得很好cu118和cu121的 PyTorch 都能跑只是要注意 cuDNN 版本得配 8.9 以上或者 9.x。再强调一个新手最容易搞混的事nvidia-smi里写着CUDA Version: 13.0而你想装 PyTorch这不代表必须装 CUDA 13。那只是驱动支持的上限装 12.1 完全没问题反而是最稳的选择。3. 驱动安装的三条路线与重启这件事驱动这块Ubuntu 上有三条常见的路子各有代价我按推荐度排序。路线一Ubuntu 官方仓库推荐给绝大多数人# 先看看系统推荐哪个版本 ubuntu-drivers devices # 自动安装推荐版本 sudo ubuntu-drivers install # 或者手动指定分支 sudo ubuntu-drivers install nvidia:550Ubuntu 22.04 和 24.04 的仓库里驱动版本更新得还算及时而且有linux-modules-nvidia-*这类配套包跟内核升级的配合比较好。装完重启即可。路线二NVIDIA 官方 CUDA 仓库版本最全# 以 Ubuntu 22.04 为例 wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-keyring_1.1-1_all.deb sudo dpkg -i cuda-keyring_1.1-1_all.deb sudo apt update # 装一个具体分支的驱动 sudo apt install nvidia-driver-550这条路的好处是可选版本非常多从 470 到最新的都有适合需要精确控制驱动版本的场景比如某台服务器上跑着老框架不能乱动。路线三官方.run文件不推荐除非有特殊理由手动跑.run装驱动每次内核升级之后都可能要重装一遍 DKMS 模块而且它不会帮你处理nouveau冲突、Secure Boot 签名这些事。除非你要在没网的机器上离线部署否则我不太建议。几个必须知道的坑第一个装完必须重启。这不是建议是必须。nvidia-smi报Failed to initialize NVML: Driver/library version mismatch这个错99% 的情况是 apt 升级了驱动包用户态库已经是新的但内核里跑的还是老模块重启一次就好了。如果重启还没好试试sudo rmmod nvidia_uvm nvidia_drm nvidia_modeset nvidia再sudo modprobe nvidia不过有进程占着显存的话会失败还是重启省事。第二个Secure Boot 会拦驱动。开了 Secure Boot 的机器上装 NVIDIA 驱动DKMS 会要求你设置 MOK 密码重启时会弹出一个蓝底界面让你 Enroll MOK。很多人直接跳过结果驱动加载失败nvidia-smi报NVIDIA-SMI has failed because it couldnt communicate with the NVIDIA driver。要么老老实实按流程录入密钥要么进 BIOS 关掉 Secure Boot。第三个nouveau 冲突。开源驱动 nouveau 如果还在加载闭源驱动会起不来。用lsmod | grep nouveau检查有输出的话需要加 blacklist。apt 装的方式一般会自动处理.run方式装的时候安装器会问你要不要禁用选是。第四个别在虚拟机上折腾驱动。VMware Workstation、VirtualBox 这类软件默认没有 GPU 直通能力你装了驱动也用不上。这个后面单独说。4. CUDA Toolkit 落地网络 deb、本地 deb 与 .run 的取舍驱动搞定之后Toolkit 有三种装法。我把它们的适用场景摊开讲。方式 ANVIDIA 网络仓库最省心如果上一步已经装了cuda-keyring直接sudo apt update # 只装 toolkit不动驱动 sudo apt install cuda-toolkit-12-4 # 或者装完整套会连驱动一起装慎用 sudo apt install cuda-12-4这里有个关键区别必须记牢cuda-12-4是元包会连带安装驱动cuda-toolkit-12-4只装工具链不动驱动。如果你已经装好了满意的驱动一定选后者否则 apt 可能把你的驱动降级或者换成一个你没预期的版本。装完之后nvcc在/usr/local/cuda-12.4/bin/下需要配环境变量才能直接调用。方式 B本地 deb 包离线机器从 NVIDIA 的下载页选deb (local)会下到几个文件sudo dpkg -i cuda-repo-ubuntu2204-12-4-local_12.4.1-550.54.15-1_amd64.deb sudo cp /var/cuda-repo-ubuntu2204-12-4-local/cuda-*-keyring.gpg /usr/share/keyrings/ sudo apt update sudo apt install cuda-toolkit-12-4本地 deb 的优点是能塞进 U 盘带到内网机器上装缺点是本地仓库里的包有生命周期限制过一段时间apt update会报过期警告得删掉/etc/apt/sources.list.d/下对应的文件。方式 C.run文件最大自由度也最容易翻车chmod x cuda_12.4.1_550.54.15_linux.run sudo sh cuda_12.4.1_550.54.15_linux.run \ --toolkit \ --silent \ --override.run安装器是交互式的跑起来之后会问你Install NVIDIA Accelerated Graphics Driver for Linux-x86_64?—— 已经装好驱动的这里一定要选no。选了yes它会把你的驱动卸了重装而且装的是它自带的那个版本。Install the CUDA 12.4 Toolkit?—— 选yes。Install the CUDA 12.4 Samples?—— 老版本会问。注意 CUDA 11.x 之后官方推荐用 GitHub 上的cuda-samples仓库/usr/local/cuda/samples这个路径在很多新版本里已经不存在了这也是「cuda samples 找不到」这个搜索词的来源。Enter Toolkit Location—— 默认/usr/local/cuda-12.4不用改。Enter CUDA Samples Location—— 随意。--toolkit参数的作用就是跳过驱动安装、只装工具链配合--silent实现无人值守。但记得先装gcc和g。gcc 版本这个坑单独拎出来说NVIDIA 每个 CUDA 版本都有一个 host compiler 支持范围也就是它能接受的gcc版本上限。Ubuntu 22.04 自带 gcc 11Ubuntu 24.04 自带 gcc 13。装老一点版本的 CUDA 时安装器经常会甩一句unsupported GNU version! gcc versions later than 12 are not supported!网上流传的解决方案是创建软链接或者加--override跳过检查。这两个做法我都试过都能装完但都可能在你编译第三方项目时突然崩掉。更稳的方式是用apt install gcc-11 g-11装一个低版本然后sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-11 11 sudo update-alternatives --install /usr/bin/g g /usr/bin/g-11 11编译 CUDA 项目时临时指定cmake -DCMAKE_C_COMPILERgcc-11 -DCMAKE_CXX_COMPILERg-11 ..说到底host compiler 支持范围这事一定要去翻对应版本的 Release Notes别信博客上抄来抄去的数字。5. gzip: stdin: invalid compressed>ls -lh cuda_12.4.1_550.54.15_linux.runCUDA 12.x 的.run文件通常是 3.5G 到 4.5G 的量级具体看版本。如果你看到的是几十 KB 或者几 MB那不用猜了下的是错误页或者被截断的片段。第二查它到底是不是可执行文件head -c 200 cuda_12.4.1_550.54.15_linux.run file cuda_12.4.1_550.54.15_linux.run正常的话head会输出#!/bin/sh之类的内容file会说它是 shell script。如果head打印的是!DOCTYPE html或者一段 JSON说明你拿到的是 CDN 的重定向页或限流提示重新下载即可。第三查SHA256/MD5 校验和NVIDIA 的下载页面会给出每个文件的校验和。跑一遍sha256sum cuda_12.4.1_550.54.15_linux.run对不上就是文件坏了。这一步是硬证据别凭感觉判断。四大成因按我的踩坑频率排序成因现象处理方式下载中途断流大小明显偏小或接近但不等于官方值wget -c续传或换curl -C -重来U 盘拷贝被截断文件在网络机器上正常拷到目标机后变小见下方 FAT32 说明CDN 返回了 HTML大小只有几十 KB加-O明确指定文件名检查链接是否失效磁盘写满ls大小正常但校验不过df -h检查剩余空间FAT32 那个坑值得单独讲CUDA 12.x 的.run文件体积已经超过 4GB而 FAT32 文件系统的单文件上限正好是 4GB。你把安装包拷到 FAT32 格式的 U 盘上很多系统不会报错只是在 4GB 处悄悄截断。拷到目标机器上文件大小看着「挺大的」但 gzip 一解压就报这个错。排查方法很简单ls -l拿到字节数和官方值对比或者直接算 sha256。解决方案是格式化成 exFAT 或 NTFS。正确的下载姿势# wget 务必带上 -c断线可以续传 wget -c https://developer.download.nvidia.com/compute/cuda/12.4.1/local_installers/cuda_12.4.1_550.54.15_linux.run # 大文件用 aria2c 多线程更稳 aria2c -x 8 -s 8 -c url # 下完立刻校验别急着跑 sha256sum cuda_12.4.1_550.54.15_linux.run提示如果是在不稳定的网络环境下下 4GB 的大文件一次性下完的概率其实不高。带-c的wget或者aria2c是必备的不要用浏览器直接下然后手动挪来挪去。千万别做的事最后提醒一句网上有教程说「用cat分卷合并.run文件」或者「重新跑一遍安装器就好了」。前者如果你分卷切错了字节边界合并出来一样损坏后者如果文件本身坏了跑一百遍还是同一个报错。先校验文件完整性再谈安装这个顺序不能反。6. cuDNN 铺装tar 手动铺 vs deb 托管cuDNN 的版本跟 CUDA 是绑定的。粗略规律是cuDNN 8.x 配 CUDA 11.xcuDNN 9.x 配 CUDA 12.x。具体每个小版本支持哪些 CUDA得看官方的 Support Matrix 页面那上面有张很详细的表。NVIDIA 现在提供三种 cuDNN 包tar、deb、rpm。Ubuntu 上就是前两种。方式一tar 包手动铺最直观tar -xvf cudnn-linux-x86_64-9.1.0.70_cuda12-archive.tar.xz cd cudnn-linux-x86_64-9.1.0.70_cuda12-archive sudo cp include/cudnn*.h /usr/local/cuda/include sudo cp -P lib/libcudnn* /usr/local/cuda/lib64 sudo chmod ar /usr/local/cuda/include/cudnn*.h /usr/local/cuda/lib64/libcudnn*cp -P这个参数很重要它保留符号链接本身而不去解引用。cuDNN 的.so是带版本号的一串软链libcudnn.so→libcudnn.so.9→libcudnn.so.9.1.0不加-P的话cp可能把软链展开成实体文件导致运行时找不到对应的 soname。这里有个隐藏的坑/usr/local/cuda通常是个软链接指向/usr/local/cuda-12.4。你把文件拷到/usr/local/cuda/include实际落到的是具体版本目录里。这本来没问题但如果你之后切换了/usr/local/cuda的指向cuDNN 就跟着「消失」了。想避免这个情况的两个选择一是明确拷到具体版本目录/usr/local/cuda-12.4/include二是每个 CUDA 版本目录里各铺一份 cuDNN。方式二deb 包托管推荐sudo dpkg -i cudnn-local-repo-ubuntu2204-9.1.0.70_1.0-1_amd64.deb # 这一步很多人会漏漏了 apt update 会报找不到密钥 sudo cp /var/cudnn-local-repo-ubuntu2204-9.1.0.70/cudnn-*-keyring.gpg /usr/share/keyrings/ sudo apt update # 注意包名CUDA 12 用 cuda-12 后缀 sudo apt install libcudnn9-cuda-12deb 方式的好处是走 dpkg 数据库升级、卸载都能追踪后续apt upgrade也能一起更新。缺点是多版本共存时要格外小心包名冲突。验证 cuDNN 装好了没有老教程里流行这一句cat /usr/local/cuda/include/cudnn_version.h | grep CUDNN_MAJOR -A 2但 cuDNN 9 之后CUDNN_MAJOR这些宏改到了cudnn_version_v9.h或者被重新组织过你按老办法 grep 会一无所获然后误以为没装成功。原因是 cuDNN 8 和 9 的头文件组织方式变了。正确做法# 看头文件确实在 ls /usr/local/cuda/include/cudnn*.h # 更靠谱的是直接看库文件和版本宏 grep -r CUDNN_VERSION /usr/local/cuda/include/cudnn_version*.h # 动态库能不能被链接器找到 ldconfig -p | grep cudnn最后一条如果没输出说明你需要刷新一下链接缓存sudo ldconfig一个实际问题cuDNN 到底要不要装如果你的工作流是纯 pip 装 PyTorch 然后写模型训练那系统级别的 cuDNN 其实可以不装因为 PyTorch 的 wheel 里已经打包了一份对应的 cuDNN。真正需要系统级 cuDNN 的场景是自己编译 TensorFlow、编译带 DNN 模块 CUDA 加速的 OpenCV、或者直接调 cuDNN API 写 C 推理。搞清楚这一点能省不少时间。7. 环境变量与多版本共存别让 PATH 跟你作对装完之后nvcc敲不出来是最常见的「装好了但用不了」。根本原因是/usr/local/cuda-12.4/bin不在PATH里。基础配置在~/.bashrc末尾加export PATH/usr/local/cuda-12.4/bin:$PATH export LD_LIBRARY_PATH/usr/local/cuda-12.4/lib64:$LD_LIBRARY_PATH然后source ~/.bashrc或者重开终端。写法上的三个细节第一$PATH要放在后面。export PATH/usr/local/cuda-12.4/bin:$PATH和export PATH$PATH:/usr/local/cuda-12.4/bin是两回事后者会把 CUDA 排到最后如果前面有 conda 或者别的工具链里也有nvcc你调到的就不是你想要的。第二用${PATH}比$PATH更安全。在极少数情况下比如你写的脚本里紧跟了其他字符串$PATH后面直接跟字母会被解释成变量名的一部分。第三如果不想全局改可以用软链接策略让/usr/local/cuda始终指向当前想用的版本sudo rm -f /usr/local/cuda sudo ln -s /usr/local/cuda-12.4 /usr/local/cuda # 环境变量里直接写不带版本号的路径 export PATH/usr/local/cuda/bin:$PATH export LD_LIBRARY_PATH/usr/local/cuda/lib64:$LD_LIBRARY_PATH这样切换版本只需要改软链接不用改环境变量文件。多版本共存的三种切换方式方式操作适用场景软链接切换改/usr/local/cuda指向单机全局切换最常用环境变量覆盖脚本里临时 export多项目并行不改全局environment modulesmodule load cuda/12.4服务器多用户共享第二种最适合日常开发写个小函数扔进.bashrcuse_cuda() { export CUDA_HOME/usr/local/cuda-$1 export PATH$CUDA_HOME/bin:$PATH export LD_LIBRARY_PATH$CUDA_HOME/lib64:$LD_LIBRARY_PATH echo switched to CUDA $1 }然后use_cuda 12.4或use_cuda 11.8就能在当前 shell 里切。几个真实的坑坑一sudo nvcc找不到命令。因为sudo默认不继承当前用户的环境变量。解决方案是用sudo -E nvcc保留环境或者写绝对路径sudo /usr/local/cuda-12.4/bin/nvcc或者直接在 root shell 里操作。坑二conda 把你的PATH改了。conda 激活环境时会在PATH前面插一段如果你在 conda 环境里装了cudatoolkit那环境里就有一份 CUDA 的库文件。这时候nvcc -V显示的可能是系统那份但实际编译链接时用到的是 conda 那份版本对不上就会出各种莫名其妙的符号错误。排查方法which nvcc echo $LD_LIBRARY_PATH ldd ./your_binary | grep cudart坑三LD_LIBRARY_PATH覆盖成空。有些安装脚本或者框架的启动脚本会直接写export LD_LIBRARY_PATH/some/path把原来的值全冲掉。这里一定要用LD_LIBRARY_PATH/some/path:$LD_LIBRARY_PATH的形式追加。坑四ldconfig与LD_LIBRARY_PATH混用。更规范的做法是通过ld.so.conf让系统级链接器知道 CUDA 库的位置echo /usr/local/cuda/lib64 | sudo tee /etc/ld.so.conf.d/cuda.conf sudo ldconfig这样就不依赖每个用户的LD_LIBRARY_PATH系统服务、systemd 单元里也能正常找到库。如果你要跑后台推理服务这一步基本是必须的。坑五环境变量里写了不存在的路径。如果/usr/local/cuda-12.4根本不存在比如你改软链接的时候手滑PATH里多一个无效目录不会报错但LD_LIBRARY_PATH里多一个无效目录在某些程序里会引发链接警告。找不到nvcc的时候第一件事是ls /usr/local/ | grep cuda确认目录真的存在。8. 验证链条与典型报错对照装完不验证等于没装。我习惯分三级来确认逐级加码。第一级驱动和 GPU 可见性nvidia-smi期望输出包含驱动版本、CUDA 版本驱动支持上限、GPU 型号、显存占用、温度功耗。如果这一步就报command not found说明驱动没装或者PATH有问题如果报couldnt communicate with the NVIDIA driver看第 3 节的重启和 Secure Boot 部分。第二级Toolkit 可用性nvcc -V期望显示Cuda compilation tools, release 12.4, V12.4.xxx。如果显示的和你想装的版本不一致那就是PATH顺序问题或者软链接指向了别的版本。接着跑一个官方的 deviceQuery# CUDA 12.x 里设备查询工具在这个位置 /usr/local/cuda/extras/demo_suite/deviceQuery预期看到Result PASS以及你的 GPU 名称、算力版本、显存等。这一步能确认驱动和 toolkit 的对接是通的。再进一步写个最小的 CUDA 程序验证编译和运行cat hello.cu EOF #include stdio.h __global__ void hello() { printf(thread %d\n, threadIdx.x); } int main() { hello1, 4(); cudaDeviceSynchronize(); return 0; } EOF nvcc -o hello hello.cu ./hello能打印出四行thread 0到thread 3说明整条编译-运行链路是通的。第三级cuDNN 与框架ldconfig -p | grep cudnn应该有libcudnn.so.9之类的输出。然后是框架验证这是最终目的python -c import torch print(torch:, torch.__version__) print(built cuda:, torch.version.cuda) print(cudnn:, torch.backends.cudnn.version()) print(available:, torch.cuda.is_available()) print(device:, torch.cuda.get_device_name(0) if torch.cuda.is_available() else N/A) 四个关键字段torch.__version__是框架版本torch.version.cuda是框架编译时用的 CUDA 版本torch.backends.cudnn.version()是它链接的 cuDNN 版本torch.cuda.is_available()是最终判决。注意torch.version.cuda和你系统nvcc -V的版本可以不一样这是正常的。pip 装的 PyTorch 自带 CUDA runtime它只需要你的驱动够新就行不需要系统装对应版本的 toolkit。这一点很多人理解错了白白花时间去「对齐版本」。典型报错对照表报错根因处理libcudart.so.12: cannot open shared object file库路径没配加ld.so.conf.d/cuda.conf并ldconfigCUDA driver version is insufficient for CUDA runtime version驱动太老升级驱动或降低 CUDA 版本no kernel image is available for execution on the device编译时算力参数不包含本卡重编时加对-archsm_xx或CUDA_ARCH_BINFailed to initialize NVML: Driver/library version mismatch内核模块与用户态库不同步重启ImportError: libcudnn.so.9: cannot open shared object filecuDNN 没装或路径不对检查/usr/local/cuda/lib64并ldconfignvcc: command not foundPATH 未配置见第 7 节unsupported GNU versiongcc 版本超出支持范围装低版本 gcc 并 update-alternativesno kernel image is available for execution on the device这个错特别值得展开。它的意思是你的可执行文件里打包的 SASS 指令集不包含当前显卡的算力版本。比如你编译时写的是-archsm_75但卡是 8.9 的 4060 Ti运行时就找不到能用的内核。解决办法是重新编译时指定正确的sm_89或者干脆用-archnative让编译器自动探测。不过用native编译出来的二进制换到别的机器上就跑不了了跨机器部署时还是显式指定更好。9. WSL2、虚拟机、conda三条旁路的取舍有三个场景需要单独说因为它们的规则和裸机不一样照搬教程会掉坑。WSL2WSL2 的 CUDA 环境有个核心原则驱动装在 Windows 上Toolkit 装在 WSL2 里Linux 驱动不要装。Windows 那边装好 NVIDIA 的常规驱动之后WSL2 里会出现一个特殊路径ls /usr/lib/wsl/lib/ # libcuda.so.1 nvidia-smi ...这个nvidia-smi和libcuda.so.1是从 Windows 侧透传过来的。所以你不需要在 WSL2 里apt install nvidia-driver-*装了反而可能把透传的库覆盖掉导致nvidia-smi报错。WSL2 里要装的是 toolkitwget https://developer.download.nvidia.com/compute/cuda/repos/wsl-ubuntu/x86_64/cuda-keyring_1.1-1_all.deb sudo dpkg -i cuda-keyring_1.1-1_all.deb sudo apt update sudo apt install cuda-toolkit-12-4注意源地址里的wsl-ubuntu是专门的 WSL 源别用普通的ubuntu2204源那个源里的驱动包在 WSL 下用不了。还有一点WSL2 的显存是动态分配的nvidia-smi里显示的显存占用会跟 Windows 任务管理器对不上这是正常现象。可以建个.wslconfig限制一下内存占用。虚拟机VMware / VirtualBox这个必须说清楚普通虚拟机装的 UbuntuCUDA 装不了装了也跑不起来。原因在于 VMware Workstation 和 VirtualBox 这类桌面虚拟化软件没有 GPU 直通Passthrough能力。你在虚拟机里lspci | grep -i nvidia什么都看不到因为宿主机根本没把 GPU 设备暴露给虚拟机。装驱动的结果要么是装不上要么是装上了nvidia-smi一直报错。真要在虚拟化环境里跑 CUDA需要的是 KVM VFIO 直通或者 Proxmox、ESXi 这类支持 PCIe Passthrough 的方案而且还要主板支持 IOMMU。这是完全另一套技术栈跟本文的话题不是一回事。所以如果你只是想在 Linux 上写 CUDA 代码玩玩装双系统或者直接用物理机别绕虚拟机这条路。conda 装 cudatoolkitconda 生态里可以这样装 CUDA 运行时conda install -c nvidia cuda-toolkit # 或者老一点的写法 conda install cudatoolkit11.8 cudnn8.9这种方式的特点是所有东西都装在 conda 环境目录里不污染系统环境删掉就完全清干净了。但有三个限制第一conda 的cudatoolkit只有运行时库通常不含nvcc。也就是说你能跑预编译好的程序但没法编译 CUDA 代码。要nvcc的话得装cuda-nvcc之类的单独包或者用cuda-toolkit这个 meta 包。第二版本选择受限于 conda 频道。有些 CUDA 小版本在 conda 源里就没有硬要装就得混源很容易出现依赖冲突。第三跟 pip 装的 PyTorch 可能打架。因为 pip 版 PyTorch 自带一份 CUDA runtimeconda 环境里又有一份运行时到底加载哪个取决于LD_LIBRARY_PATH和 rpath出问题时非常难查。我的经验是conda 适合快速起一个隔离的实验环境长期的生产环境还是老老实实系统级安装。如果是纯粹的 Python 训练任务直接用 pip 装 PyTorch让框架自己管 CUDA 依赖是最省心的路径。10. 编译带 CUDA 的 OpenCV算力参数最容易踩空最后一个高频场景自己编译带 CUDA 加速的 OpenCV。这条路踩坑的概率比装 CUDA 本身高得多因为 CMake 会自动去探测一堆东西。依赖先装齐sudo apt install build-essential cmake git pkg-config \ libgtk-3-dev libavcodec-dev libavformat-dev libswscale-dev \ libv4l-dev libxvidcore-dev libx264-dev libjpeg-dev libpng-dev \ libtiff-dev gfortran openexr libatlas-base-dev \ python3-dev python3-numpy libtbb2 libtbb-devCMake 关键参数cmake -D CMAKE_BUILD_TYPERELEASE \ -D CMAKE_INSTALL_PREFIX/usr/local \ -D WITH_CUDAON \ -D WITH_CUDNNON \ -D OPENCV_DNN_CUDAON \ -D WITH_CUBLASON \ -D CUDA_TOOLKIT_ROOT_DIR/usr/local/cuda-12.4 \ -D CUDA_ARCH_BIN8.9 \ -D CUDA_ARCH_PTX \ -D WITH_OPENCLOFF \ -D BUILD_opencv_python3ON \ -D OPENCV_GENERATE_PKGCONFIGON \ ..几个参数的作用必须讲清楚WITH_CUDAON是最基础的开关不开的话后面全是白搭。OPENCV_DNN_CUDAON才会让cv2.dnn模块走 GPU。很多人只开了WITH_CUDA结果发现 DNN 推理还是 CPU 在跑就是这个参数没开。CUDA_ARCH_BIN是最容易出错的。它指定为目标显卡生成哪些算力的指令。CUDA_ARCH_PTX留空表示不生成 PTX 中间码。如果你的目标是只在这台机器上跑留空可以减小体积、加快编译如果要分发到其他显卡上跑建议填一个较低的算力值来生成 PTX让运行时能 JIT 编译。CUDA_ARCH_BIN怎么填对照这张表显卡算力RTX 4090 / 4080 / 4070 / 4060 Ti8.9A1008.0RTX 3090 / 3080 / 30708.6RTX 2080 / 2070 / T47.5GTX 1080 Ti6.1如果填错了比如给 4060 Ti 填了7.5编译能过运行时cv::cuda::GpuMat一用就抛no kernel image is available for execution on the device。这个错在第 8 节的对照表里出现过根因是同一个。编译时容易翻车的几件事第一内存不够导致 nvcc 被杀。OpenCV 的 CUDA 编译会并行跑好几个nvcc进程每个都能吃 2-4GB 内存。16GB 内存的机器上开make -j8很容易触发 OOM Killer报c: fatal error: Killed signal terminated program cc1plus。解决方案是降并行度make -j4 # 或者更保险 make -j2虽然编译时间会长到一两个小时但至少能编完。第二算力列表填了多个值时编译时间暴涨。比如你写CUDA_ARCH_BIN7.5;8.0;8.6;8.9编译时间大致是单值的四倍。除非你确实要跨架构分发否则就填你实际的卡。第三libcudnn找不到。CMake 配置阶段如果看到Could NOT find CUDNN说明 cuDNN 没铺到 CUDA 目录里或者LD_LIBRARY_PATH没配好。回头检查第 6 节的拷贝步骤。第四Python 绑定没生成。BUILD_opencv_python3ON开了之后还要确认 CMake 输出里有Python 3: ... Interpreter和numpy的路径。如果只有 Interpreter 没有 numpy绑定会静默跳过编译完import cv2就找不到。装个python3-numpy或者用 pip 装 numpy 都行。验证 CUDA 加速真的生效python3 -c import cv2 print(cv2.__version__) print(cuda devices:, cv2.cuda.getCudaEnabledDeviceCount()) getCudaEnabledDeviceCount()返回大于 0才算真的编进去了。返回 0 的话翻回去看 CMake 的配置输出多半是某个WITH_*参数没开或者算力填错导致 CUDA 模块被跳过。我个人在编译 OpenCV 这件事上的体会是配置阶段把 CMake 的完整输出拉到文件里存一份出了任何问题都能回溯。cmake ... 21 | tee cmake_config.log这份日志里会告诉你每个模块是开启还是跳过、每个依赖找没找到比编译完再猜要高效得多。编译本身可能要一两个小时但排查配置问题只要几分钟把时间花在前面的检查上回报率高得多。