梯度累积(Gradient Accumulation)之所以能节省显存,核心原因在于:
它用“时间换空间”,把一次大 batch 的训练拆成多次小 batch,从而避免了同时存储大 batch 的前向激活值和中间计算结果。
下面分层解释。
在训练神经网络时,显存主要被以下几部分占用:
其中:
假设:
如果直接跑 batch size = 64:
梯度累积把 batch size = 64 的训练拆成 4 步:
batch size = 16
accumulation steps = 4步骤:
代码逻辑类似:
optimizer.zero_grad()
for i in range(accumulation_steps):
loss = model(small_batch)
loss = loss / accumulation_steps
loss.backward() # 梯度累加
optimizer.step()| 对比项 | 大 batch(无累积) | 梯度累积 |
|---|---|---|
| 同时存在的激活值 | 64 个样本 | 16 个样本 |
| 峰值显存 | 高 | 低 |
| 梯度 | 一次计算 | 多次累加 |
| 参数更新 | 每步更新 | 多次累积后更新 |
因为:
每一小步 forward/backward 结束后,该 batch 的激活值就可以释放
而大 batch 必须等所有样本反向完成才能释放。
⚠️ 梯度累积 不能减少 以下显存占用:
✅ 所以它主要省的是:
前向激活值带来的显存峰值
把显存想象成一张桌子:
梯度累积通过把大 batch 拆成多个小 batch 分步计算,减少了同一时刻需要存储的激活值数量,从而降低显存峰值,实现“用更多计算换更少显存”。
如果你愿意,我也可以帮你: