☰
Ubuntu下N卡驱动与CUDA安装全指南:避坑详解
2026/10/20 12:14:34 网站建设 项目流程

装显卡驱动和CUDA,这个主题听起来挺老生常谈,但我在实际接触中,发现每年都有大量新入坑的人卡在这一步,而且卡的方式千奇百怪。有人装完驱动黑屏,有人循环登录,有人好不容易装上CUDA,结果跟框架版本对不上,还有人升级一次内核之后,nvidia-smi直接原地消失。这篇文章我打算把所有关键细节都摊开讲,围绕Ubuntu系统上安装N卡驱动和CUDA这件事,尽量把原理、步骤和坑都讲透,覆盖从下载到验证的完整链路。

这篇文章适合这几类人看:准备在Ubuntu上搭深度学习环境的人、被黑屏和循环登录折磨到想重装系统的人、以及在驱动和CUDA版本之间反复横跳的新手。我会尽量用“为什么要这样做”的视角来讲,而不是简单甩给你一串命令。

1. 安装前必读:版本、环境与整体思路

1.1 先把版本关系捋清楚

很多人装驱动失败,根源只有一个:没搞明白驱动、CUDA和系统内核三者之间的关系。

先说驱动与CUDA的关系。N卡驱动是“向下兼容”的,也就是说,新版驱动通常支持所有旧版CUDA,但旧版驱动不一定支持新版CUDA。每个CUDA版本都有一个最低驱动版本要求,这个表格在NVIDIA官网能查到。举个实际例子,CUDA 12.x需要驱动版本至少在530以上,而你现在用的是550或者560的驱动,那跑CUDA 12.x完全没问题。反过来如果你只装了520的驱动,却想用CUDA 12.2,那就装不上了。

再一个容易混淆的点是nvidia-smi显示的CUDA版本和nvcc -V显示的CUDA版本。nvidia-smi右上角显示的CUDA Version是指当前驱动支持的最高CUDA版本,它表示你最多可以装到这个版本的CUDA;而nvcc -V显示的是你实际安装的CUDA Toolkit版本。两者不一定要完全一致,只要“实际安装的CUDA版本 <= 驱动支持的最高版本”就行。

系统内核同样重要。Ubuntu的驱动安装包基本都是针对特定内核版本编译的,如果你升级内核后驱动没有跟着重新编译,就会莫名其妙“掉驱动”。这也是为什么我要在后面强调dkms的重要性。

1.2 工具与准备工作清单

在正式安装之前,我建议你花五分钟把环境信息看清楚。打开终端,依次执行以下命令:

# 查看系统版本,比如Ubuntu 22.04 LTS lsb_release -a # 查看内核版本 uname -r # 查看显卡型号,确认是N卡且型号正确 lspci | grep -i nvidia # 查看是否有gcc编译器,后面编译驱动需要 gcc --version

如果是刚装好的系统,gcc大概率没有安装,最好先补上基础编译工具。

sudo apt update sudo apt install build-essential dkms

build-essential包含编译器和基础库,dkms则是动态内核模块支持工具。dkms能帮你在内核升级后自动重新编译驱动模块,这个后面详细说。

另外强烈建议在动手前开启系统自带的“创建快照”功能,或者用timeshift之类的工具做一个系统备份。装驱动最坏的结果就是系统反复重启不进桌面,有备份能让你随时回到安全状态继续折腾,没有备份你可能就得抱着启动U盘重装系统了。

下载驱动时,先去NVIDIA官网的“驱动下载”页面,选择你的显卡型号和Linux 64位系统,会得到一个类似NVIDIA-Linux-x86_64-550.xx.run的文件。注意不要下载成Windows版。CUDA Toolkit从官网选择Linux对应的版本下载即可,建议选择.run格式的本地安装包,而不是Debian网络安装包,原因后面讲。

1.3 三种主流安装方式如何选

N卡的驱动安装方式大体有三种,我在这里把它们放在一起对比一下,方便你根据自己情况选:

安装方式优点缺点适用场景
apt仓库安装命令简单,跟系统集成好,卸载方便版本通常不是最新的;可能被系统更新影响只跑稳定应用、不想折腾的人
官方.run文件最新版本,可控性强,安装参数灵活需要手动管理;内核升级后可能掉驱动追求新版本、自己解决问题的人
CUDA Toolkit捆绑安装驱动和CUDA一次性装好容易重复装驱动导致冲突全新环境、最省事的情况

我的建议是:第一次安装,优先尝试用官方.run文件单独装驱动,再用.run方式单独装CUDA。虽然步骤多一些,但每一步发生了什么你都清楚,出问题时排查起来也简单。如果只是为了用某个固定版本的驱动,也不想处理奇怪的问题,那么apt仓库方式肯定更省心。两种方式我下面都会给出详细步骤。

2. 第一步:安装N卡驱动,两个最稳的方案

2.1 推荐方案:官方.run文件手动安装

手动安装标准的流程分为四个阶段:屏蔽开源驱动、进入纯命令行模式、执行安装程序、重启验证。

先解释为什么需要屏蔽开源驱动。Ubuntu内核自带一个叫nouveau的开源驱动模块,它会在系统启动时自动加载,占住显卡设备。如果NVIDIA官方驱动要安装,就会和nouveau产生冲突,导致模块加载失败、黑屏或者循环登录。所以要在驱动安装前把它拉黑。

创建一个拉黑配置文件:

sudo vim /etc/modprobe.d/blacklist-nouveau.conf

写入下面的内容:

blacklist nouveau options nouveau modeset=0

然后更新内核引导配置并重启:

sudo update-initramfs -u sudo reboot

重启之后验证一下nouveau确实被禁掉了:

lsmod | grep nouveau

如果没有任何输出,说明拉黑成功。这一步别偷懒,我见过太多人跳过这步直接装驱动,然后百思不得其解为什么启动进不了桌面。

接着进入纯命令行模式。在桌面环境下按Ctrl + Alt + F2,会切换到全黑的虚拟终端界面,用你的用户名登录。执行下面命令关闭图形桌面服务:

# Ubuntu 22.04以后一般是gdm3,如果用的是lightdm则换成lightdm sudo service gdm3 stop

注意,如果你的显卡原本是正常工作的,关闭图形服务后屏幕会进入类似纯文本终端的状态,这是正常的。从这里执行驱动安装程序可以避开图形环境对安装过程的干扰。

先确认你下载的.run驱动文件有执行权限:

chmod +x NVIDIA-Linux-x86_64-550.xx.run

然后执行安装:

sudo ./NVIDIA-Linux-x86_64-550.xx.run --no-opengl-files --no-x-check --no-nouveau-check --dkms

标志参数解释一下:

  • --no-opengl-files表示不安装OpenGL相关文件。虽然NVIDIA驱动自带的OpenGL库在某些场景下是必要的,但对普通用户和深度学习场景来说,跳过OpenGL文件可以避免很多桌面环境下的兼容性问题,特别是如果你不打算用这台机器玩游戏或跑桌面级图形加速。
  • --no-x-check意思是安装时不检查X服务是否在运行。因为我们手动关了图形服务,这个参数告诉安装程序不用纠结当前有没有图形环境。
  • --no-nouveau-check跳过nouveau检测。
  • --dkms让驱动以dkms方式注册,这样以后升级内核时驱动模块能自动重新编译。

安装过程中会问你一些问题,比如是否接受许可证、是否需要注册内核模块等,基本一路选“Yes”或“OK”即可。有些版本会问是否安装32位兼容库,如果你主要的场景是深度学习,其实不是必须的,可以选“No”加快安装速度。

安装完成后重启系统:

sudo reboot

重启完打开终端,执行:

nvidia-smi

如果能看到类似下面这样的一张表格,包含驱动版本、GPU利用率、显存使用情况,那驱动就算装成功了。

+---------------------------------------------------------------------------------------+ | NVIDIA-SMI 550.54.15 Driver Version: 550.54.15 CUDA Version: 12.4 | |-----------------------------------------+----------------------+----------------------+

2.2 省心方案:apt仓库一键安装

如果你想用更省心的方式,Ubuntu的apt仓库里也维护了NVIDIA驱动。优点是不需要关图形界面、不需要手动下载run文件,直接一条命令搞定:

# 查看系统推荐哪些驱动版本 ubuntu-drivers devices

执行后,它会列出你的显卡支持的驱动列表,并在某个版本后面标记recommended。然后直接一键安装:

sudo ubuntu-drivers autoinstall

这个命令会自动安装推荐版本的驱动。如果想手动指定版本:

sudo apt install nvidia-driver-550

装完同样重启,然后nvidia-smi验证。

apt方式的缺点也比较明显:第一,仓库里的驱动版本往往不是最新,发布节奏比NVIDIA官方慢不少;第二,如果你以后手动安装CUDA Toolkit时选择“安装驱动”,可能会把apt装的驱动覆盖成另一个版本,导致版本混乱。如果你确定自己以后只通过apt管理驱动,那就保持这种方式。如果以后打算频繁更新CUDA版本,建议还是用.run方式。

2.3 安装后的验证与驱动状态解读

nvidia-smi输出的信息量很大,这里简单说下怎么看:

  • 上方的Driver Version就是驱动版本号,CUDA Version表示当前驱动能支持的最高CUDA版本。
  • 下方的表格显示每个GPU的实时状态,包括温度、显存使用率、功耗、运行中的进程等。
  • 如果GPU被某些进程占用了,在进程列表能看到PID和占用显存大小。

如果在nvidia-smi里能看到显卡,但运行nvidia-settings报错,或者图形界面有问题,绝大多数情况是因为OpenGL相关的文件被跳装了,或者和显卡桌面会话冲突。对纯粹跑深度学习的人来说,这并不影响实际使用。如果很在意图形界面性能,可能要回到图形模式下重新执行一次不带--no-opengl-files的安装,但这属于进阶调优了。

另外提醒一点:如果你的机器是笔记本双显卡(Intel核显+N卡独显),装完闭源驱动后可能需要用prime-select切换显卡模式。比如:

# 查看当前模式 prime-select query # 切换到N卡独显 sudo prime-select nvidia

这个命令和桌面环境集成度有关,有的人需要,有的人不需要。遇到相关问题时可以朝这个方向查。

3. 第二步:安装CUDA Toolkit与环境配置

3.1 下载CUDA Toolkit与安装参数解析

驱动装好之后,接着装CUDA Toolkit。先去NVIDIA官网的CUDA下载页面,选择操作系统、架构、发行版本、安装方式。我建议选择runfile (local)格式,这样能用本地安装包离线安装,可控性最好。

它会给你类似下面这样的下载链接和安装命令:

wget https://developer.download.nvidia.com/compute/cuda/12.4.0/local_installers/cuda_12.4.0_550.54.15_linux.run

下载完成后执行安装:

sudo sh cuda_12.4.0_550.54.15_linux.run

注意,执行后它首先会进入一个文本图形界面(类似ncurses菜单),里面有一堆组件选项。这里有个极其关键的步骤:如果你已经手动装好了驱动,在组件列表里一定要取消勾选“Driver”。怎么操作?在Driver那一项上按回车,把[X]改成[ ]。其余组件比如CUDA Toolkit、Samples、Documentation可以都保留,然后选“Install”开始安装。

为什么要取消Driver?因为官方run包里的驱动版本可能和你已经安装的不完全一致,重复安装可能覆盖已有驱动或者版本冲突。我在实际安装中见过好几次有人没取消Driver,装完CUDA之后驱动直接出问题,回去查才发现驱动被覆盖了,版本还不匹配。多花这一步操作,能少踩一个大坑。

如果你从一开始就打算让CUDA安装包顺便把驱动也装了,那可以不加任何参数直接装,但前提是系统从没装过NVIDIA驱动,并且你也想省事。这种适合全新系统。

安装过程中它会提示安装路径,一般是/usr/local/cuda-X.Y,同时会帮你建立一个/usr/local/cuda软链接指向这个版本目录。这个软链接在版本切换中很有用,后面细说。

3.2 环境变量配置与软链接的作用

安装完成后,把CUDA的bin和lib64目录加入环境变量。编辑用户配置文件:

vim ~/.bashrc

在文件末尾追加:

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

然后让配置生效:

source ~/.bashrc

为什么这里的路径写的是/usr/local/cuda而不是/usr/local/cuda-12.4?因为/usr/local/cuda是一个软链接,始终指向当前默认要使用的CUDA版本。这样你如果以后想切换到另一个版本,只需要改变软链接指向,环境变量不用动。

LD_LIBRARY_PATH是运行时库搜索路径。CUDA程序在编译和运行时要找libcudart.so、libcublas.so这一类动态库,不设置这个环境变量的话,即使编译过了,运行程序时也会报error while loading shared libraries的错误。这类报错的排查方式无非是确认lib64下确实有对应的.so文件,以及确认这个路径确实在LD_LIBRARY_PATH里。

3.3 多版本CUDA共存与切换

实际项目中经常出现这种情况:代码框架依赖的是CUDA 11.8,但新训练的框架非要CUDA 12.x。于是很多人被逼着学会管理CUDA多版本。多版本共存完全可行,因为每个CUDA Toolkit安装后都在独立目录下,互不干扰。

关键是管理好/usr/local/cuda这个软链接。比如我装了CUDA 11.8和CUDA 12.4,需要切到11.8时:

sudo rm -rf /usr/local/cuda sudo ln -s /usr/local/cuda-11.8 /usr/local/cuda

切回12.4就把目标路径换成/usr/local/cuda-12.4。切换后重新打开一个终端或重新source ~/.bashrc,nvcc -V就会显示对应版本。

如果你想更规范一点,也可以用update-alternatives管理:

sudo update-alternatives --config cuda

但说实话,手动改软链接对个人开发机来说已经足够简单粗暴好用了。唯一要注意的是,环境变量PATH和LD_LIBRARY_PATH里的路径写的是/usr/local/cuda,所以它们始终跟随软链接变化,不需要改配置文件。这个设计是为了省事,也是很多老手管理多版本CUDA的通用做法。

3.4 验证CUDA:从nvcc到deviceQuery再到写段代码

装完之后先验证工具链:

nvcc -V

如果能看到类似Cuda compilation tools, release 12.4, V12.4.131这样的输出,说明编译器装好了。

接着编译并运行NVIDIA官方自带的示例程序:

# 进入示例目录(在安装目录下) cd /usr/local/cuda/samples/1_Utilities/deviceQuery # 编译 sudo make # 运行 ./deviceQuery

如果最后输出Result = PASS,说明驱动、CUDA Toolkit、显卡之间的通路完全正常。

但我还是建议你亲手写一段最简单的CUDA代码编译运行一下,这样能完整走一遍“编辑-编译-运行”的流程,对后续理解更深。下面是设计用来验证CUDA环境的最小示例,主要功能是打印设备信息。

#include <cstdio> #include <cuda_runtime.h> int main() { int devCount = 0; cudaGetDeviceCount(&devCount); if (devCount == 0) { printf("No CUDA device found.\n"); return -1; } cudaDeviceProp prop; cudaGetDeviceProperties(&prop, 0); printf("Device name: %s\n", prop.name); printf("Compute capability: %d.%d\n", prop.major, prop.minor); printf("Total global memory: %.2f GB\n", (double)prop.totalGlobalMem / 1024 / 1024 / 1024); cudaDeviceReset(); return 0; }

保存为test.cu,然后:

nvcc -o test test.cu ./test

如果能看到设备名称、算力版本、显存大小,说明你的CUDA环境已经能正常编译和运行GPU程序了。

3.5 顺手把cuDNN装上

深度学习框架几乎都依赖cuDNN。虽然严格来说它不是CUDA Toolkit的一部分,但既然做深度学习,迟早要用到。先把cuDNN库文件解压,然后复制到CUDA目录下:

tar -xzvf cudnn-linux-x86_64-8.9.x_cuda12-archive.tar.xz cd cudnn-linux-x86_64-8.9.x_cuda12-archive # 复制头文件和库文件 sudo cp include/cudnn*.h /usr/local/cuda/include/ sudo cp lib/libcudnn* /usr/local/cuda/lib64/ # 给库文件加读权限 sudo chmod a+r /usr/local/cuda/include/cudnn*.h /usr/local/cuda/lib64/libcudnn*

注意cuDNN版本要和你的CUDA版本匹配。比如CUDA 12.x的安装包里会有适配12.x的cuDNN包,千万别下错版本。还有一点,NVIDIA官网的cuDNN下载需要注册账号,这个步骤没法通过wget直接搞定,下载后把文件放到本地再复制即可。

验证一下cuDNN是否被正确识别:

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

如果有响亮的版本号输出,说明库已经装好。有些新版头文件名是cudnn_ops_infer.h之类的细节差异,解法都一样,搜索包含CUDNN_MAJOR定义的头文件即可。

4. 高频问题排查实录:黑屏、循环登录、掉驱动、版本冲突

4.1 驱动装完进不去桌面怎么办

这是最常见也是最让人崩溃的问题。装完驱动重启,系统卡在登录界面,输入密码后又跳回登录界面,或者干脆黑屏。

我从几十次折腾经验里总结出几个排查方向:

第一,检查nouveau有没有拉黑成功。登录到Ctrl+Alt+F2的虚拟控制台,执行lsmod | grep nouveau。如果还能看到nouveau,说明拉黑没生效。可能是配置文件名写错,或者update-initramfs之后没重启。

第二,看安全启动(Secure Boot)的情况。很多品牌机默认开启安全启动,NVIDIA驱动模块如果没有签名,内核会拒绝加载它。处理方式有两种:进BIOS关闭Secure Boot,或在内核模块加载时配置签名。对个人开发机来说,直接关闭Secure Boot最省事。

第三,注意是使用了闭源驱动还是开源内核模块。如果你的显卡是较新的Ampere或Ada Lovelace架构(比如RTX 30/40系列),推荐尝试NVIDIA的“open”内核模块;如果用的是比较老的显卡,还是用传统闭源模块更稳。.run安装程序在检测到新架构显卡时有时会直接使用open模块,有时又让你选择,选错就会出现能装上但启动时无法加载的场景。

第四,查看日志。在虚拟控制台执行:

journalctl -xe

搜索nvidia、smi、gdm等关键词,能很直观地看到驱动加载失败的具体原因。比如缺失模块、符号错误、权限问题等,日志里都会明确提示。

4.2 升级内核后nvidia-smi消失

这种情况我遇到过太多次了。系统一升级内核,nvidia-smi显示“command not found”,GPU也找不到了。原因很简单:驱动的内核模块是针对旧内核编译的,新内核里没有这个模块。

前面我提到的dkms就是用来解决这个问题的。如果你在安装.run驱动时加了--dkms参数,那么驱动模块会注册到dkms里,内核升级时系统会尝试自动重新编译驱动。如果没有自动重编,可以手动执行:

sudo dkms install -m nvidia -v 550.54.15

如果提示找不到模块,说明驱动注册信息丢了,可以先sudo dkms remove -m nvidia -v 550.54.15 --all,再重新运行驱动安装程序并确认带上--dkms参数。

如果是通过apt装的驱动,一般是nvidia-dkms-550之类的包,检查一下包是否还在,必要时sudo apt install --reinstall nvidia-dkms-550。

这个问题的核心就一句话:驱动模块要和当前内核版本对应。dkms是减轻这种痛苦的利器,建议所有用.run方式装驱动的人都用起来。

4.3 CUDA与PyTorch/TensorFlow版本不匹配

很多人好不容易装好CUDA,结果装PyTorch时发现:PyTorch的预编译包只支持CUDA 12.1,你却装了11.8,或者反过来。其实这种情况并不是装错了,而是你只需要安装对应当前CUDA版本的PyTorch版本即可。比如:

pip install torch --index-url https://download.pytorch.org/whl/cu121

它会根据cu121自动选择匹配CUDA 12.1的版本。但要注意,如果GPU驱动版本过低,跑PyTorch时会报CUDA driver version is insufficient for CUDA runtime version。这种情况就只好升级驱动了。

如果已经安装了很多个CUDA版本,担心环境变量指向错误,可以用nvcc -V先确认当前生效的版本,再用which nvcc看看这个命令到底来自哪个路径下的软链接。这样能快速定位是不是环境变量配置的问题。

4.4 问题速查表

问题现象可能原因解决方法
安装时提示nouveau已加载没拉黑nouveau或拉黑后没重启配置blacklist文件后执行update-initramfs -u并重启
循环登录驱动与显卡不匹配、Secure Boot开启检查journalctl -xe,关闭Secure Boot,换open/closed模块
nvidia-smi:No devices were found驱动模块未加载dkms status查看模块信息,重新编译模块
nvcc: command not found环境变量没配好检查~/.bashrc中的PATH配置并source
运行时找不到libcudart.soLD_LIBRARY_PATH缺失确认/usr/local/cuda/lib64在环境变量里
CUDA安装时勾选了Driver,导致驱动冲突驱动版本被覆盖重装正确版本的驱动,或用nvidia-smi核对版本
编译CUDA程序报错nvcc fatalgcc和CUDA版本不兼容安装对应版本的gcc,或用-ccbin参数指定编译器版本

5. 最后分享几条经验

很多官方文档只会告诉你“执行这个命令”,但我在实际使用中觉得,真正提高效率和降低试错成本的,反而是那些不起眼的习惯。这里挑几个我觉得特别管用的分享出来。

第一条经验,是“先备份,再动手”。我在装驱动之前一定会做一次系统快照,哪怕是虚拟机也留着快照。原因很简单:驱动和CUDA牵涉到底层系统库和内核模块,出了问题之后恢复的成本往往远高于备份的成本。如果你当时偷懒没备份,一旦反复黑屏,你会后悔的。

第二条经验,是“统一用.run方式管理驱动和CUDA”。如果用apt装驱动、run装CUDA,两者混在一起的版本状态其实很难理清。要么全用apt,要么全用run。我自己在开发机上一直用run方式,因为它把驱动、CUDA和cuDNN的安装过程全都变成“可重复执行的脚本”,以后重装系统,照着同一套流程来,结果是一致的。

第三条经验,是安装完成后的“固化配置”。每次装完驱动和CUDA后,我会把当前版本号、下载链接、安装参数、遇到的坑,以及最后的验证命令,都记在一个文本文件里,放到家目录下。别小看这个习惯,半年后当你需要在新机器上重装环境时,这份记录就是最大的财富。你在终端里敲过的每一条命令,都会在这个文件里有明确的下一步说明和优先级标注。

最后再说一下,如果你在安装过程中碰到了某个问题,并且查了很多资料都找不到答案,不妨把关键日志贴给社区,或者在技术论坛发帖讨论。我遇到过不少问题,最后都是靠别人的一句提示才恍然大悟。这本来就是一个需要“折腾”的过程,正常。希望你装的这次从开机到验证都顺顺利利。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询