一、显存溢出初探:什么是显存溢出?
显存溢出,说白了就是 GPU 的「内存」不够用了。
你想想看,深度学习训练时,模型参数、梯度、优化器状态、中间激活值……这些东西全都要塞进显存里。一旦总需求超过了 GPU 的物理显存容量,就会触发 CUDA out of memory 错误。
我个人习惯把显存比作一个「临时仓库」。训练时,数据进来、计算完、再出去,仓库里的货物不断流转。但如果货物太多,仓库装不下,那就只能报错了。
为什么深度学习训练中容易遇到?
这个问题我经常被问到。其实原因很直接:
- 模型越来越大:从几百万参数到几十亿参数,显存需求是指数级增长的
- 批量大小(batch size)太贪心:很多人一上来就设 64、128,结果显存直接爆掉
- 中间激活值被忽略:我见过不少新手,只算了模型参数的大小,忘了算前向传播时每一层的激活值——这些才是吃显存的大头
- 混合精度没用好:FP32 和 FP16 混着用,有时候反而让显存碎片化更严重
核心结论:显存溢出不是「模型太大」这一个原因,而是多个因素叠加的结果。定位问题,得一个一个拆。
常见报错信息解读
CUDA out of memory 的报错,其实藏着不少信息。我教你怎么看。
RuntimeError: CUDA out of memory. Tried to allocate 2.00 GiB
(GPU 0; 8.00 GiB total capacity; 6.32 GiB already allocated;
1.12 GiB free; 4.78 GiB reserved in total by PyTorch)
这段报错里,关键信息有四个:
| 字段 | 含义 | 我的经验 |
|---|---|---|
| Tried to allocate | 这次尝试分配多大显存 | 2.00 GiB,说明这次操作比较重 |
| already allocated | 已经占用了多少 | 6.32 GiB,已经用了大部分了 |
| free | 剩余多少 | 1.12 GiB,不够分配 2 GiB |
| reserved in total | PyTorch 总共预留了多少 | 4.78 GiB,注意这个值可能比实际用的多 |
一个小技巧:看到「reserved in total」比「already allocated」大很多时,说明 PyTorch 的缓存机制占了不少显存。这时候可以试试 torch.cuda.empty_cache() 释放缓存。
还有一种常见的报错变体:
CUDA error: out of memory
CUDA kernel errors might be asynchronously reported
这种报错更「粗暴」,没有详细数字。我曾经在调试一个 GAN 模型时遇到过,排查了半天才发现是生成器里有个卷积层的通道数设错了,导致中间特征图爆炸。
注意:CUDA out of memory 不一定发生在模型加载时,也可能发生在训练中途。比如某个 batch 的数据特别大,或者某个层的激活值突然暴增。所以别只看初始化阶段。
显存溢出的本质
我用一张图来总结显存溢出的核心逻辑。这张 SVG 图展示了从「模型加载」到「训练报错」的完整链路。
从这张图你能看到,显存溢出往往发生在前向传播阶段。因为中间激活值占了显存的大头(约 40%),而且随着 batch size 增大,激活值线性增长。
一句话总结:显存溢出不是玄学,是数学。搞清楚每部分占了多少,你就能精准定位问题。
避坑指南
我曾经在训练一个 7B 参数的 LLM 时,连续爆了三次显存。第一次是因为忘了开梯度检查点(gradient checkpointing),第二次是因为 batch size 设了 32 没降下来,第三次最离谱——有个数据加载器把整张 4K 图片 resize 成了原始尺寸,直接撑爆了显存。
所以我的建议是:
- 先算后跑:用
torch.cuda.memory_summary()看看每块显存的使用情况 - 从小开始:batch size 从 1 开始试,逐步增加,找到临界点
- 别信默认值:很多框架的默认 batch size 都是 64 或 128,对于大模型来说太高了
- 监控显存碎片:有时候显存总量够,但碎片太多导致分配失败。可以用
nvidia-smi看显存使用率
一个小工具:我习惯在训练脚本开头加一行 torch.cuda.set_per_process_memory_fraction(0.9),限制 PyTorch 最多用 90% 的显存,留点余量给系统和其他进程。
嗯,这一章先讲到这里。显存溢出其实没那么可怕,关键是你得知道它为什么发生。下一章我们会深入讲如何用工具定位具体是哪一层、哪个操作吃掉了显存。