一、显存基础与瓶颈分析

大家好,我是你们的老朋友。今天咱们聊聊显存——这个在深度学习里既熟悉又让人头疼的东西。

说实话,我刚开始做模型训练那会儿,对显存的理解就是「越大越好」。直到有一次,我往一张 24GB 的卡上塞了个 7B 模型,结果直接 OOM,连个 warning 都没给我留。嗯,从那以后我才开始认真研究显存到底是怎么工作的。

1.1 显存架构:HBM vs GDDR

先说说显存的两种主流架构。你可能会问:为什么有的卡用 HBM,有的用 GDDR?

HBM(High Bandwidth Memory),说白了就是堆叠起来的显存。像 HBM2e 和 HBM3,带宽能到 2TB/s 以上。我习惯把 HBM 比作「多层停车场」——占地面积小,但层数多,数据进出快。

GDDR(Graphics Double Data Rate),比如 GDDR6 和 GDDR6X,带宽一般在 500GB/s 到 1TB/s 之间。它更像「平铺的停车场」——占地大,但每层跑得快。

特性 HBM(如 HBM2e) GDDR(如 GDDR6X)
带宽 ~2 TB/s ~1 TB/s
容量 单颗 8-16GB 单颗 8-32GB
功耗 较低 较高
成本 高 低
典型应用 A100, H100, MI250 RTX 4090, A6000

我在项目中遇到过一个问题:用 RTX 4090 跑大模型推理,batch size 稍微大一点就 OOM。后来换成 A100,虽然单卡容量差不多,但 HBM 的带宽优势让吞吐量直接翻倍。说白了,带宽和容量你得一起看,不能只看一个。

1.2 带宽与容量的权衡

你想想看,显存带宽决定了「数据能多快被喂给计算单元」,而容量决定了「能同时放多少数据」。这两者往往是矛盾的。

  • 带宽瓶颈:如果你的模型计算量不大,但数据量很大(比如视频理解),带宽就是短板。我曾经用 GDDR 卡跑一个 3D 卷积模型,计算单元大部分时间在等数据,利用率不到 30%。
  • 容量瓶颈:如果你的模型参数多(比如 LLM),容量就是硬伤。我记得有一次训练 13B 模型,batch size 设为 1 都 OOM,最后不得不做梯度累积。

核心原则:带宽和容量,你得根据你的 workload 来选。计算密集型选高带宽,参数密集型选大容量。

1.3 PyTorch 显存分配机制

PyTorch 的显存分配,说白了就是「缓存池」机制。它不会每次需要显存都去问 CUDA 要,而是先预分配一大块,然后自己管理。

为什么会这样?因为 CUDA 的显存分配开销很大。我做过测试,一次 cudaMalloc 大概要几十微秒,而 PyTorch 内部的缓存分配只要几微秒。所以 PyTorch 选择「先囤着,慢慢用」。

# 查看 PyTorch 显存分配情况
import torch

# 分配一个 1GB 的张量
x = torch.randn(256, 1024, 1024, device='cuda')

# 查看当前显存使用
print(torch.cuda.memory_summary())

# 释放张量
del x

# 显存不会立即归还给系统
print(torch.cuda.memory_summary())  # 缓存还在

嗯,这里要注意:del 之后显存不会立刻释放,而是回到 PyTorch 的缓存池。如果你想强制清空缓存,可以调用 torch.cuda.empty_cache()。但我个人建议别频繁调用,因为清空缓存后下次分配又要重新申请,反而更慢。

1.4 常见 OOM 场景剖析

OOM(Out of Memory)是每个炼丹师的噩梦。我总结了几种最常见的场景:

  1. batch size 太大:这是最直接的。你想想看,batch size 翻倍,显存占用也翻倍。我建议从 batch size=1 开始,逐步往上加。
  2. 中间激活值爆炸:很多人只算了模型参数,忘了算中间激活值。比如一个 7B 模型,序列长度 2048,单层激活值可能就要 1GB 以上。我遇到过有人把序列长度设到 8192,结果显存直接爆了。
  3. 梯度累积没清缓存:梯度累积时,如果你不手动清空计算图,显存会越积越多。我曾经踩过这个坑,训练到一半突然 OOM,查了半天才发现是计算图没释放。
  4. 多进程显存泄漏:用 DataLoader 的 num_workers 时,如果子进程没有正确释放显存,会导致显存慢慢被吃光。我建议用 torch.multiprocessing 的 set_start_method('spawn') 来避免。

避坑指南:我曾经在训练一个 30B 模型时,发现显存占用一直在涨,但明明没有新的张量分配。后来发现是 DataLoader 的 worker 进程里有个 torch.no_grad() 没加,导致计算图被保留。加了之后,显存就稳定了。

1.5 知识体系总览

下面这张图是我自己画的,把本章的核心逻辑串起来了。你可以把它当作一个「显存优化地图」。

显存优化知识体系(第1章) 显存基础与瓶颈 显存架构 HBM:高带宽,低延迟 GDDR:大容量,低成本 带宽 vs 容量 计算密集型 → 高带宽优先 参数密集型 → 大容量优先 PyTorch 分配机制 缓存池预分配 del 不立即释放 常见 OOM 场景 batch size 过大 中间激活值爆炸

个人经验:我建议你在开始训练之前,先用 torch.cuda.memory_summary() 看一下显存分配情况。这样能提前发现潜在问题,而不是等到 OOM 了才去排查。

好了,这一章就到这里。显存这东西,说白了就是「知己知彼,百战不殆」。你理解了它的架构、分配机制和常见坑,后面优化起来就顺手多了。

可可精品资料库