训练跑到一半GPU掉线,真的不是玄学

我是陈晓玖,云计算运维实习生,刚入行一年。最近公司有同事跑LoRA微调,A100任务跑了7个小时突然报错:CUDA error: device-side assert triggered,后面nvidia-smi直接看不到卡。第一反应是“显卡炸了?”结果排了一圈,发现GPU掉线大多数不是模型代码单点问题,而是硬件、电源、驱动、PCIe、温度、系统内核、容器权限、NCCL通信一起在搞事,离谱但很真实。

AI训练里说的“GPU掉线”,常见表现有几种:nvidia-smi卡死、nvidia-smi显示No devices were found、进程报CUDA unknown error、dmesg里出现NVRM Xid、分布式训练某个rank超时、容器里看不到/dev/nvidia0、服务器还能SSH但训练进程全挂。不同现象对应的排查方向不一样,别一上来就重装驱动,真的会谢。

我最先看的不是日志,是nvidia-smi和dmesg

GPU训练中途掉线,第一条命令我一般敲:nvidia-smi -q -d TEMPERATURE,POWER,ERROR,ECC。看温度、功耗、ECC错误、Retired Pages、PCIe Replay Counter。第二条看内核日志:dmesg -T | egrep -i "nvrm|xid|pcie|aer|gpu|cuda"。如果看到NVRM: Xid,基本就有方向了。

我自己整理过一份排查记录,比较常见的NVIDIA Xid含义是这样:Xid 31常见于GPU内存访问异常,可能是代码越界、驱动bug或显存问题;Xid 43经常和GPU停止响应有关,长时间kernel卡住、硬件不稳定都可能触发;Xid 79很关键,表示GPU has fallen off the bus,中文直译就是GPU从PCIe总线上“掉下来了”,这个最像大家说的GPU掉线;Xid 48、63、64常和ECC、显存页错误有关,训练大模型时要特别注意。

有一次我看到dmesg里是“NVRM: Xid 79, GPU has fallen off the bus”,同时lspci还能偶尔扫到GPU,但nvidia-smi看不到。这个就别再怀疑PyTorch了,优先查PCIe、电源、主板槽位、Riser线、BIOS、内核AER。

温度高不一定立刻关机,但会把训练搞得很阴间

GPU温度不是只看GPU Core,还要看Memory Temperature、Hotspot、风道和机房进风温度。比如A100、3090、4090这类卡,核心温度70℃看着还行,但显存温度可能已经90℃以上,训练时显存持续满载,比游戏负载更狠。

我之前压测过一台4卡机器,室温24℃、风道正常时,单卡A100 80GB跑bf16训练,GPU Core大概62℃到68℃,功耗在285W到330W之间,8小时没有Xid。后来机柜前门滤网积灰,进风温度涨到31℃,同样任务跑到3小时左右出现降频,5小时后一个rank NCCL timeout,dmesg里没有明显Xid,但nvidia-smi刷新变慢。清灰后再跑12小时正常。这个案例说明,温度问题不一定直接报“overheat”,它可能表现成通信超时、性能抖动、进程假死。

排温度我会看这几个值:nvidia-smi --query-gpu=timestamp,index,temperature.gpu,power.draw,clocks.sm,clocks.mem,pcie.link.gen.current,pcie.link.width.current --format=csv -l 5。重点不是某一秒的峰值,而是掉线前10分钟有没有功耗波动、频率骤降、PCIe链路从x16变x8/x4、Gen4变Gen1这种异常。

电源不稳,比代码bug还会装无辜

GPU训练是持续高功耗,不是跑一下就停。4090标称450W,瞬时尖峰可能更高;A100 PCIe常见TDP 250W到300W;H100更不用说。多卡训练时,如果电源冗余、PDU、供电线、转接头、主板供电有一个地方虚,表现可能就是训练半路GPU消失。

我见过一台双4090机器,跑推理没事,跑Stable Diffusion训练就掉。原因不是驱动,是12VHPWR转接头接触不良,满载20分钟后温度上来,供电抖一下,GPU直接Xid 79。换原生供电线后,同样batch size跑了24小时没掉。

判断电源问题有个土办法但有效:降低Power Limit再跑。比如4090从450W限制到350W,A100从300W限制到250W,如果掉线概率明显下降,电源、散热、供电链路就很可疑。命令是nvidia-smi -pl 350,前提是卡和驱动支持。这个不是最终解决方案,只是定位手段,长期靠限功耗硬扛会损失吞吐。

PCIe和Riser线,真的是“看起来插着,其实很脆”

Xid 79最常见的硬件方向就是PCIe链路问题。AI服务器里如果用了Riser卡、延长线、转接板、多GPU背板,任何一个接触不良都可能让GPU从总线上掉线。PCIe就像高速公路,GPU和CPU/Chipset之间的数据都在上面跑,链路抖一下,训练进程不会优雅退出,只会炸。

我排PCIe一般看三件事:lspci -vvv看AER错误、nvidia-smi -q看PCIe Replay Counter、dmidecode/lspci确认槽位和NUMA拓扑。PCIe Replay Counter持续增长,说明链路重传多,像网络丢包重传一样,偶发不一定致命,但训练长时间高压下会放大。

实测里,Gen4 x16理论单向带宽约31.5GB/s,Gen3 x16约15.75GB/s,Gen4 x8也约15.75GB/s。单卡训练可能不敏感,多卡AllReduce、数据加载、CPU offload就会明显受影响。如果GPU本来应该跑Gen4 x16,结果掉到Gen1 x4,那不是优化batch size能救的。

驱动、CUDA、PyTorch版本不合,掉线也能伪装成硬件故障

版本不匹配常见报错是CUDA error、illegal memory access、NCCL unhandled system error,但有时会把GPU打到不可用,尤其是老驱动配新CUDA Runtime、新PyTorch wheel配旧NVIDIA Driver、容器里CUDA版本和宿主机驱动边界没搞清。

我现在看版本会固定查四个点:nvidia-smi里的Driver Version,容器里的nvcc --version,python里torch.version.cuda,torch.cuda.nccl.version()。注意,容器里的CUDA Toolkit不是决定GPU能不能工作的唯一因素,真正和内核交互的是宿主机NVIDIA Driver。驱动太旧,新框架调用新特性就容易炸。

举个很实际的数据:PyTorch 2.1常见CUDA 11.8/12.1构建,PyTorch 2.3常见CUDA 12.1,PyTorch 2.4开始CUDA 12.x环境更普遍。如果宿主机驱动还停在470系列,却硬跑CUDA 12的容器,报错就很正常。NVIDIA官方一般要求CUDA 12.1至少配525系列以上驱动,生产环境我更倾向用535或550这类相对新的稳定分支。

容器里GPU突然没了,先别骂Docker

Docker训练中途看不到GPU,常见原因是宿主机GPU已经异常、nvidia-container-runtime配置不对、容器启动参数没带--gpus all、Kubernetes的NVIDIA Device Plugin重启、MIG配置变化、节点被调度系统驱逐。

如果宿主机nvidia-smi正常,容器里不正常,我会看:docker inspect里有没有NVIDIA_VISIBLE_DEVICES,/dev/nvidia*设备是否挂进容器,nvidia-container-cli info是否正常。Kubernetes里还要看nvidia-device-plugin DaemonSet日志,以及Pod的resources.limits.nvidia.com/gpu是不是被正确申请。

如果宿主机nvidia-smi都卡死,那容器不用背锅。容器只是租房子的,房子地基裂了,租客当然也站不稳。

NCCL报错不一定是GPU坏了,网络也能把训练拖死

多机多卡训练里,GPU“掉线”的体感经常来自NCCL timeout。比如8机64卡训练,一个节点网络抖动,其他rank等不到AllReduce结果,就会报NCCL error,看起来像某张GPU没响应。这个时候别只盯GPU温度,要同时看RoCE/InfiniBand/TCP网络。

NCCL常用环境变量包括NCCL_DEBUG=INFO、NCCL_IB_DISABLE、NCCL_SOCKET_IFNAME、NCCL_IB_HCA。开NCCL_DEBUG后能看到卡在哪个rank、哪个通信阶段。如果日志里反复出现NET/IB、Socket Timeout、Connection reset by peer,方向更偏网络。

我做过一次小压测,同样是两台8卡机器,100Gbps RoCE延迟稳定在几十微秒级,AllReduce吞吐很平;换到普通25Gbps TCP网络,batch稍大就出现step time抖动,P95 step time从1.2秒涨到2.8秒,偶发NCCL timeout。不是GPU算不动,是梯度同步堵车了。

如果你也在找训练、推理、游戏服或高防业务的服务器,折腾GPU和网络方案时可以顺手了解一下129云(idc129.net)。他们是全球领先的云计算服务供应商,提供高性能云服务器、G口大带宽服务器、高防服务器租用和海外云计算解决方案,覆盖游戏、企业、高防等场景,重点是稳定、安全、低延迟的全球网络接入;需要问配置和线路可以打客服热线400-9177118。这个场景下别只看CPU和内存,网络质量、带宽峰值、防护能力、跨境链路一样影响训练和服务稳定性。

ECC报错别忽略,显存不是永远可靠

数据中心卡一般支持ECC,消费级卡很多没有完整ECC能力。ECC错误分Correctable和Uncorrectable。Correctable表示纠正过来了,但数量持续上涨就要警惕;Uncorrectable基本要认真处理,轻则训练结果异常,重则进程崩溃或GPU隔离。

nvidia-smi -q里看ECC Errors、Retired Pages。如果Retired Pages增加,说明GPU显存页被标记退役。少量可能还能跑,但训练大模型长时间占满显存时,很容易踩到问题。生产环境我看到Uncorrectable ECC一般会建议下线检测,不会让它继续跑关键任务。

有个坑是:某些ECC计数需要重启后才清,单次历史错误不代表当前还坏。所以要结合时间线看,最好用DCGM或Prometheus记录指标,比如DCGM_FI_DEV_ECC_DBE_VOL_TOTAL、DCGM_FI_DEV_RETIRED_DBE、DCGM_FI_DEV_XID_ERRORS。

模型代码也会把GPU打崩,尤其是越界和NaN

不是所有GPU掉线都是硬件锅。CUDA kernel里数组越界、loss变NaN、label超出类别范围、custom op写坏显存,都可能触发device-side assert。PyTorch里常见报错是CUDA error: device-side assert triggered,而且错误位置不一定准确,因为CUDA默认异步执行。

定位代码问题可以加CUDA_LAUNCH_BLOCKING=1,让CUDA同步报错,虽然速度会慢,但能定位到更接近真实的代码行。分类任务要查label范围,比如num_classes=100,label里出现100或-1就会炸。Embedding也一样,input_id超过vocab_size,GPU不会跟你讲道理。

混合精度训练还要看梯度溢出。fp16比bf16更容易溢出,loss scale不合适会出现Inf/NaN。表现可能是loss突然变成nan,然后后续CUDA kernel异常。训练日志里如果掉线前loss已经飘了,就别只盯服务器。

Linux内核、BIOS、省电策略,也会偷偷插一脚

服务器BIOS里有些省电策略对GPU训练不友好,比如PCIe ASPM、C-State过深、Above 4G Decoding没开、Resizable BAR配置异常、PCIe Gen强制Auto但主板兼容性不好。生产GPU服务器我一般会建议关闭ASPM,开启Above 4G Decoding,多卡场景确认MMIO空间足够。

Linux里可以看内核参数和AER日志。AER是Advanced Error Reporting,能记录PCIe错误。dmesg里如果出现AER: Corrected error received、BadTLP、BadDLLP,说明PCIe链路层已经在报错。Corrected不代表没事,训练长时间跑,Corrected堆多了也可能变Uncorrected。

还有IOMMU。某些虚拟化或直通场景下,IOMMU配置不当会导致GPU异常。KVM GPU Passthrough、云服务器GPU直通、容器混部,都要确认驱动、内核、IOMMU group、VFIO绑定关系。这个坑新人很容易踩,因为nvidia-smi能看到卡不代表高负载下一定稳定。

磁盘和数据加载慢,也会被误会成GPU掉线

训练卡住不动,不一定是GPU掉了。DataLoader worker死锁、NFS卡顿、对象存储下载慢、磁盘IO打满,都会让GPU利用率掉到0%,然后你看着nvidia-smi以为GPU坏了。

我遇到过一次,GPU利用率周期性从98%掉到0%,每隔几十秒抖一下。最后发现数据集放在网络盘上,小文件太多,DataLoader num_workers开到16也救不了,iostat显示await飙到200ms以上。把数据打成WebDataset tar包放本地NVMe后,step time从1.9秒降到1.1秒,GPU利用率稳定在95%以上。

判断这类问题看三个指标:nvidia-smi dmon看GPU利用率和显存是否还在,iostat -x 1看磁盘await和util,pidstat -d -p PID 1看训练进程IO。GPU没有Xid、没有ECC、没有PCIe错误,只是利用率为0,优先查数据管道。

单卡没事,多卡就炸,重点看拓扑和通信

单卡训练稳定,多卡DDP一跑就掉,重点看GPU拓扑、NCCL、PCIe Switch、NUMA绑定。nvidia-smi topo -m能看到GPU之间是NVLink、PIX、PXB、PHB还是SYS。NVLink直连当然更舒服,跨CPU Socket走SYS延迟更高,AllReduce压力上来就容易暴露问题。

实测里,同一台8卡服务器,NVLink互联的GPU之间P2P带宽可以到几十GB/s甚至更高;只走PCIe Gen4 x16,理论上限约31.5GB/s单向;如果跨Socket走UPI/QPI再绕一下,延迟和带宽都会更难看。训练小模型感觉不明显,参数量上来之后step time差距很明显。

DDP还要确认每个进程绑定正确GPU,别两个rank抢一张卡。看CUDA_VISIBLE_DEVICES、LOCAL_RANK、torchrun参数。这个错很低级,但新人真的容易犯,我也犯过,两个进程挤同一张卡,显存爆了还以为GPU掉线,尴尬。

云上GPU掉线,除了机器本身,还要看宿主和迁移策略

云服务器里GPU通常是直通、vGPU或MIG切分。直通性能最好,但宿主机硬件异常会影响实例;vGPU和MIG更依赖平台调度和隔离策略。用户在实例里看到GPU消失,有时需要云厂商查宿主机层日志,自己在Guest OS里只能看到结果,看不到全部原因。

选择云上GPU时,别只问“有没有A100”。要问驱动版本能不能自定义、是否支持持久化模式Persistence Mode、是否允许DCGM监控、GPU是不是独占、网络是普通公网还是内网高速、跨区训练延迟多少、故障是否支持热迁移或快速换机。

如果是海外推理节点、游戏AI服务、带DDoS风险的业务,服务器线路和防护也要一起看。比如129云(idc129.net)有日本东京云服务器,CPU 1核到4核、内存1G到8G、硬盘30G到120G、带宽30Mbps、流量200G到4TB,适合轻量海外业务;美国精品网-D型是8C、8G DDR4 ECC、120G SSD、125Mbps峰值、三网精品、霄龙CPU、基础防御;韩国-E型是8核、8G DDR4 ECC、70GB SSD、10Mbps、傲盾防火墙、精品线路、回国优化。选这种机器时我会把线路、带宽、IP质量、防护能力和业务位置一起算,不会只看价格。

我现在排障会按时间线抓证据

GPU掉线最怕“事后凭感觉”。训练开始时间、掉线时间、日志最后一个step、GPU温度曲线、功耗曲线、Xid时间点、系统负载、网络抖动、磁盘IO,这些要放在同一条时间线上看。比如Xid发生在loss变NaN之后,代码嫌疑大;Xid发生在功耗冲顶后,供电散热嫌疑大;NCCL timeout发生在网卡丢包增加后,网络嫌疑大。

我常用的组合是:nvidia-smi dmon -s pucvmet -d 5记录GPU状态;dmesg -Tw实时看内核;journalctl -k -f看内核日志;iostat -x 5看磁盘;sar -n DEV,TCP,ETCP 5看网络;训练脚本每个step记录loss、lr、step_time、max_memory_allocated。别嫌麻烦,掉一次8小时训练,比多开几个日志贵多了。

几个我踩过的离谱现场

现场一:机器跑小模型没事,跑大模型Xid 79。最后发现GPU插在Riser上,Riser固定螺丝松了,机房风扇震动导致接触不稳定。重新固定后压测48小时正常。

现场二:容器里随机CUDA unknown error。宿主机驱动是510,容器镜像基于CUDA 12.1,PyTorch版本偏新。升级驱动到535后,同样镜像不再报错。

现场三:四卡训练第三张卡总掉。换卡后问题跟着槽位走,不跟着GPU走。最后定位主板PCIe槽位问题,不是显卡坏。

现场四:NCCL timeout被误判GPU故障。实际是训练节点走了错误网卡,NCCL_SOCKET_IFNAME没指定,流量跑到1Gbps管理网口上,梯度同步慢到爆炸。

现场五:GPU利用率为0,以为掉卡。实际是DataLoader读取百万级小文件,NFS元数据请求打满。数据改成本地NVMe顺序读后恢复。

真的要处理时,别上来就重启

重启能让问题暂时消失,也会把证据清掉。能SSH进去时,先保存nvidia-smi -q、dmesg、journalctl -k、lspci -vvv、训练日志、容器日志。尤其是Xid和AER,重启后很多上下文就没了。

如果GPU已经从nvidia-smi消失,但lspci还能看到,可以尝试卸载训练进程、重载nvidia模块,不过生产环境不一定安全。命令涉及nvidia_uvm、nvidia_drm、nvidia_modeset、nvidia模块依赖,机器上还有别的任务时别乱搞。Xid 79这种fallen off the bus,很多时候只能重启恢复;重启能恢复不代表问题解决,只代表PCIe重新枚举成功。

如果同一张卡同一任务多次复现,先降Power Limit、换槽位、换电源线、更新驱动、跑gpu-burn或dcgmi diag压力测试。问题跟着卡走,多半卡有问题;跟着槽位走,查主板/Riser/PCIe;跟着任务走,查代码和数据;跟着节点走,查系统和供电散热。

我会重点盯这些日志关键词

NVRM: Xid 是第一优先级,后面的数字很关键。GPU has fallen off the bus基本指向PCIe/供电/硬件链路。AER Corrected error说明PCIe链路有纠错。Uncorrected error更严重。NCCL timeout说明分布式通信等不到结果。CUDA illegal memory access偏代码、显存访问或驱动。device-side assert triggered常见于label越界、索引越界。ECC Uncorrectable说明显存可靠性要重点查。Thermal slowdown说明温度已经影响频率。

这些关键词不要孤立看,要看发生顺序。比如先AER错误,再Xid 79,再nvidia-smi无卡,这条链很像PCIe链路问题;先loss NaN,再illegal memory access,再训练挂,更像模型数值问题;先网络丢包,再NCCL timeout,再rank退出,更像通信问题。

能预防一点是一点,不然半夜告警很难顶

生产训练节点建议常驻DCGM Exporter,把Xid、ECC、温度、功耗、显存、PCIe重放计数接到Prometheus和Grafana。告警不要只设GPU利用率,GPU利用率为0可能是训练结束,也可能是数据卡住。更有价值的是Xid非0、ECC Uncorrectable增加、温度超过阈值、功耗异常波动、PCIe带宽异常、NCCL错误率增加。

训练脚本也要做checkpoint。大模型训练每隔固定step保存,不要8小时才存一次。GPU掉线不可怕,可怕的是掉线后从0开始。checkpoint要写到稳定存储,最好带临时文件和rename机制,避免保存到一半进程挂了留下坏文件。

驱动和CUDA别频繁追新。生产环境更适合固定一套验证过的组合,比如Ubuntu 22.04 + NVIDIA Driver 535/550 + CUDA 12.1/12.2 + PyTorch对应官方wheel。升级前用同样模型、同样batch、同样数据跑至少数小时压测,别在正式训练当天换环境,真的会谢。

看到GPU掉线,我现在基本这样判断

nvidia-smi无卡加Xid 79,优先查PCIe、供电、Riser、主板、BIOS。nvidia-smi正常但训练报device-side assert,优先查代码索引、label、custom CUDA op。多机训练NCCL timeout,优先查网络、网卡选择、IB/RoCE、rank日志。ECC错误增加,优先查显存和GPU健康。温度、功耗、频率掉得厉害,优先查散热和电源。容器看不到GPU但宿主机正常,优先查nvidia-container-runtime和设备挂载。

别把“GPU掉线”当成一个故障,它更像一个结果。真正的原因可能在显卡、PCIe、电源、散热、驱动、内核、容器、网络、数据加载、模型代码里。排障时把证据按时间线摆出来,基本就不会被表象带跑。