GPU 利用率突然掉到 0%,磁盘却 100% 打满?一次深度学习训练卡死的真实排查
GPU 利用率突然掉到 0%,磁盘却 100% 打满?一次深度学习训练卡死的真实排查
做深度学习训练时,很多人都见过一种很迷惑的现象:
GPU 利用率突然掉到 0%,训练像是“停住了”;与此同时,磁盘占用却冲到 100%,系统开始发卡,最后训练直接挂掉。
第一眼看上去,这很像是“磁盘太慢”或者“数据读取太重”。
但这次排查下来,我发现真正的根因并不是磁盘本身,而是更隐蔽的一类问题:
系统内存被 DataLoader 顶爆,进入疯狂换页,最后被内核 OOM Killer 直接杀进程。
这篇文章就把这次排查过程和结论完整整理一下。
一、现象:GPU 不干活了,磁盘却忙到飞起
训练过程中出现了这些症状:
- GPU 利用率突然降到
0% - 磁盘 I/O 占满,系统明显变卡
- 训练日志不再正常推进
- 最后分布式训练报错,进程退出
如果只看监控面板,很容易得出一个结论:
“是不是数据集在慢盘上,或者日志/权重写太多,把磁盘打满了?”
但这次并不是。
二、最开始的误判:像磁盘问题,其实不是
这类现象之所以容易误判,是因为系统在内存不足时会触发大量交换和回收。
一旦进入这个阶段,外在表现就会非常像“磁盘瓶颈”:
- 磁盘占用 100%
- GPU 空转
- 训练不推进
- 系统整体卡顿
但磁盘只是“表象”。
真正发生的是:
- DataLoader 供数变慢
- GPU 等不到下一批数据
- 系统内存被撑爆,开始频繁换页
- 磁盘因此被打满
- 最终内核触发 OOM,直接杀掉 Python 进程
三、关键证据:这次是 OOM,不是单纯 I/O
排查过程中,最关键的证据有四个。
1. data_time 异常升高
日志里在出事前出现了明显异常:
- 正常时
data_time大约在0.06 ~ 0.08 - 出问题前突然变成了
0.7384
这说明训练瓶颈已经不在模型计算,而是在“等数据”。
换句话说,GPU 没活干了。
2. 分布式训练开始报同步超时
后续日志里又出现了:
RendezvousTimeoutErrorDataLoader worker ... is killed by signal: Killed
这表明不是正常收敛中断,而是某些 worker 或 rank 已经出问题,导致整个分布式同步被拖死。
3. 内核日志明确出现 oom-kill
真正的定锤来自内核日志:
oom-killOut of memory: Killed process ... (python)anon-rss: 39634916kB
也就是说,被杀掉的是一个 Python 进程,匿名内存峰值接近 39GB。
4. 匿名页占用极高
同一段日志里还有:
inactive_anon: 122085532kB
这说明大量匿名内存页已经堆积,系统正在拼命回收和交换。
到了这个阶段,磁盘 100% 忙碌其实只是 OOM 前夜的常见症状。
四、根因链路:为什么 GPU 归零,磁盘却爆满
这次问题的链路,可以概括成下面这五步:
DataLoader配置过激,CPU 侧缓存和预取占用大量内存- 数据读取越来越慢,
data_time飙升 - GPU 等不到 batch,利用率掉到
0% - 系统开始 swap / reclaim,磁盘被打满
- 最后内核 OOM Killer 出手,直接
SIGKILL某个 Python 进程
所以这类问题的本质其实是:
内存爆了,磁盘只是被连带打爆。
五、这次把内存顶爆的配置长什么样
问题配置大致是这样的:
train_dataloader.batch_size = 40
train_dataloader.num_workers = 8
persistent_workers = True
如果你的数据又是这种类型,风险会更高:
- 双时相遥感图像
- TIFF 文件
rasterio / GDAL读取- 多 worker 并发
- 持久 worker 不释放
- DataLoader 预取较多 batch
这几项叠加起来,很容易出现下面这种情况:
batch_size很大num_workers很多- 每个 worker 都在提前准备数据
persistent_workers=True导致 worker 常驻- TIFF 解码、缓存、中间数组都占内存
- 最后不是显存先炸,而是 系统内存先炸
很多人会盯着显存看,其实这类问题里,先死的往往不是 GPU 显存,而是 CPU 内存。
六、为什么大显存机器也会踩这个坑
一个常见误区是:
“我有两张 96G 卡,显存很大,batch 开大点应该没问题吧?”
不一定。
因为:
batch_size撑的是训练吞吐和部分内存num_workers撑的是 CPU 侧的数据准备压力- TIFF、遥感、多通道、双时相读取,CPU 内存和 I/O 压力本来就重
- 多 worker 预取数据时,吃的是 系统 RAM,不是显存
所以显卡再大,也挡不住 DataLoader 把主机内存先顶爆。
七、这次更合理的修正建议
如果目标是“稳定优先”,那这组参数更合理:
batch_size = 16 or 24
num_workers = 2
persistent_workers = False
prefetch_factor = 1
同时建议:
- 数据放在本地 SSD / NVMe
work_dir也尽量放本地高速盘- 不要一开始就把 batch 顶到很大
- 遥感 TIFF 场景下,优先控制 DataLoader 压力
如果一定要给一个保守起步值,我会推荐:
batch_size = 24
num_workers = 2
persistent_workers = False
prefetch_factor = 1
这组参数通常比“batch_size=40, num_workers=8”稳定得多。
八、以后遇到类似问题,怎么快速判断是不是 OOM
如果你也遇到“GPU 0%,磁盘 100%”这种情况,可以按这个顺序排查:
- 看训练日志里的
data_time - 看是否出现
DataLoader worker killed - 看是否有
RendezvousTimeoutError - 查
dmesg或系统日志里有没有oom-kill - 看系统内存和 swap 是否被打满
如果同时满足下面几条,基本就可以锁定 OOM 链路:
data_time明显变大- GPU 利用率掉到 0
- 磁盘突然忙碌
- worker 被
Killed - 内核日志出现
oom-kill
九、结论
这次问题的结论很明确:
GPU 利用率掉到 0、磁盘占满,并不一定是磁盘问题。
在很多训练场景里,这其实是 DataLoader 把系统内存打爆后的连锁反应。
尤其是下面这种组合,风险非常高:
- 大 batch
- 多 workers
persistent_workers=True- TIFF / 遥感 / 大图 / 重增强
- 分布式训练
所以真正该盯的,不只是显存,还包括:
- 系统 RAM
- swap
- DataLoader 行为
data_time- worker 生命周期
一句话总结:
看到 GPU 归零 + 磁盘打满,不要先怪磁盘,先查 OOM。
更多推荐
所有评论(0)