一、显存基础与瓶颈分析

大家好,我是你们的老朋友。今天咱们聊聊显存——这个在大模型训练里,既烧钱又让人头疼的东西。

说实话,我刚开始做分布式训练那会儿,对显存的理解也就停留在「显存越大越好」这个层面。直到有一次,一个 70B 的模型怎么都跑不起来,我盯着 nvidia-smi 看了半天,才发现问题根本不在算力,而在显存。嗯,从那以后,我就开始认真研究显存了。

1.1 GPU显存架构:HBM vs GDDR

先说说显存的类型。目前主流的 GPU 显存就两种:HBM 和 GDDR。

HBM(High Bandwidth Memory),说白了就是堆叠起来的显存。像 H100、A100 这些高端卡用的就是 HBM。它的特点是带宽极高——H100 的 HBM3 带宽能到 3.35 TB/s。为什么这么快?因为它把多个 DRAM 芯片堆在一起,中间用 TSV(硅通孔)连接,数据路径短,延迟低。

GDDR(Graphics Double Data Rate),比如 GDDR6、GDDR6X,常见于消费级显卡。带宽比 HBM 低一个数量级,但容量可以做得更大,成本也更低。

我个人的习惯是:做训练用 HBM,做推理用 GDDR。为什么?训练时数据吞吐量大,带宽是瓶颈;推理时模型参数固定,容量更关键。

特性 HBM (HBM3) GDDR (GDDR6X)
带宽 ~3.35 TB/s ~1 TB/s
容量 80 GB (H100) 24-48 GB (消费级)
功耗 较低 较高
成本 高 低
避坑指南:我曾经在项目里用 RTX 3090 跑一个 13B 的模型,结果发现显存带宽根本喂不饱计算单元。GPU 利用率只有 30% 左右,说白了就是「等数据」的时间比「算数据」的时间还长。后来换成 A100,同样的模型,利用率直接拉到 90% 以上。

1.2 显存带宽与容量限制

带宽和容量,这两个指标经常被混为一谈。但你要知道,它们限制的是不同的事情。

带宽限制:决定了你能多快地把数据从显存搬到计算单元。大模型训练里,每次前向和反向传播都要读写大量参数和激活值。如果带宽不够,计算单元就会「饿着」等数据。

容量限制:决定了你能装下多大的模型。一个 70B 的模型,光参数就要 140 GB(FP16)。加上优化器状态、梯度、激活值,轻松突破 300 GB。单卡根本放不下。

你想想看,为什么现在大家都在搞分布式训练?说白了就是单卡显存放不下了。我见过不少团队,模型设计得挺好,结果一跑就 OOM(Out of Memory),然后开始各种「显存优化骚操作」——梯度检查点、混合精度、模型并行……其实根源就是显存容量不够。

核心公式:模型训练所需显存 ≈ 模型参数 × 2 (FP16) + 优化器状态 × 4 (Adam) + 梯度 × 2 + 激活值 × batch_size × 序列长度

1.3 大模型训练中的显存墙问题

「显存墙」这个词,我估计做分布式训练的人都听过。它指的是:模型规模的增长速度,远超单卡显存的增长速度。

你看,GPT-3 有 1750 亿参数,需要大约 350 GB 的显存(FP16)。而当时最先进的 A100 也只有 80 GB。差距有多大?4 倍多。到了 GPT-4,据说参数上万亿,这个差距就更大了。

为什么会这样?因为显存容量受物理限制——芯片面积、功耗、散热,都是瓶颈。而模型参数的增长,几乎不受物理限制——只要你有数据、有算力,就能堆。

我在项目中遇到过最典型的情况:一个 30B 的模型,用 8 张 A100 跑流水线并行。按理说 8×80=640 GB,够了吧?结果一跑,OOM。为什么?因为流水线并行里,每个 stage 不仅要存自己的参数,还要存前后 stage 的通信缓冲区、激活值、梯度……实际可用显存,远小于理论值。

注意:显存墙不是「显存不够」那么简单。它会导致你不得不使用更复杂的并行策略(流水线并行、张量并行、数据并行混合),而这些策略本身又会引入额外的显存开销和通信开销。说白了,显存墙是一个「连锁反应」。

1.4 显存分配的生命周期

最后聊聊显存是怎么被分配和释放的。这个知识点,我建议你好好理解,因为很多显存优化技巧都跟它有关。

显存分配的生命周期,大致分三个阶段:

  1. 模型加载阶段:把模型参数从 CPU 内存搬到 GPU 显存。这个阶段分配的是「持久显存」——只要模型还在,这些显存就不会释放。
  2. 训练阶段:动态分配显存给梯度、优化器状态、激活值、临时缓冲区。这个阶段是显存使用的「高峰期」,也是最容易 OOM 的时候。
  3. 推理阶段:只保留模型参数和 KV Cache(对于 Transformer),其他显存可以释放。

你可能会问:为什么训练阶段显存波动这么大?因为 PyTorch 的显存分配器是「懒惰」的——它不会用完就立刻释放,而是缓存起来,下次再用。这样做的好处是减少 cudaMalloc 的开销,坏处是显存碎片化严重。

我记得有一次,一个模型训练到一半突然 OOM,但 nvidia-smi 显示还有 10 GB 空闲。怎么回事?后来发现是显存碎片化——虽然总空闲空间够,但没有一块连续的区域能放下一个大的 tensor。嗯,这个问题在长序列训练里特别常见。

避坑指南:我曾经用 torch.cuda.memory_summary() 查看显存分配情况,发现大量「已缓存但未使用」的显存。解决方案是手动调用 torch.cuda.empty_cache(),或者在每个 epoch 结束后重置显存分配器。但注意,频繁调用会影响性能。
显存分配生命周期 模型加载阶段 持久显存分配 参数从CPU→GPU 训练阶段 动态显存分配 梯度/激活值/优化器 推理阶段 释放非必要显存 仅保留参数+KV Cache 低 高(峰值) 中 显存使用量 显存上限

上面这张图,展示的就是显存在不同阶段的使用情况。你可以看到,训练阶段是显存使用的「洪峰期」,也是我们优化的重点。

好了,这一章的内容就到这里。显存的基础知识,说白了就是理解「有什么、限制在哪、怎么分配」。下一章我们会深入聊聊流水线并行中,显存是怎么被「切」开的。

本章小结:
  • HBM 带宽高,适合训练;GDDR 容量大,适合推理
  • 显存墙是模型规模与单卡显存之间的根本矛盾
  • 显存分配分三个阶段:加载、训练、推理,训练阶段是瓶颈
  • 显存碎片化是 OOM 的隐形杀手,记得用 memory_summary 排查

想要更多资料,联系可可