显存主要被这几部分占用:
梯度累积主要解决的是:
无法一次塞进大 batch,但希望保持大 batch 的更新效果
for each batch:
forward
backward → 计算梯度
step → 更新参数for micro_batch in range(k):
forward
backward → 梯度累加(不更新参数)
step → 累积 k 次梯度后,统一更新参数数学上等价于:
大 batch = k × micro_batch_size
for x, y in dataloader:
out = model(x)
loss = criterion(out, y)
loss.backward()
optimizer.step()
optimizer.zero_grad()accumulation_steps = 4 # 累积 4 次
for i, (x, y) in enumerate(dataloader):
out = model(x)
loss = criterion(out, y)
# 关键:除以累积步数
loss = loss / accumulation_steps
loss.backward()
if (i + 1) % accumulation_steps == 0:
optimizer.step()
optimizer.zero_grad()✅ 显存只取决于 micro batch size
因为:
loss.backward() 会累加梯度所以:
loss = loss / k保证:
梯度 ≈ 大 batch 的平均梯度
from torch.cuda.amp import autocast, GradScaler
scaler = GradScaler()
for x, y in dataloader:
with autocast():
out = model(x)
loss = criterion(out, y) / accumulation_steps
scaler.scale(loss).backward()
if step % k == 0:
scaler.step(optimizer)
scaler.update()
optimizer.zero_grad()✅ 显存减少 30~50%
适合:
model.gradient_checkpointing_enable()| 技巧 | 作用 |
|---|---|
| 减小 hidden size / 层数 | 最直接 |
| 用 LoRA / QLoRA | 只训少量参数 |
| 降低输入长度 | 激活显存线性下降 |
| 用 CPU offload | 牺牲速度换显存 |
经验法则:
new_lr ≈ base_lr × (global_batch_size / base_batch_size)单卡 16GB,训练 1.3B 模型
| 项目 | 设置 |
| micro batch size | 1 |
| accumulation steps | 16 |
| global batch size | 16 |
| AMP | ✅ |
| gradient checkpointing | ✅ |
| 优化器 | AdamW |
小显存训练大模型 = 小 batch + 梯度累积 + 混合精度 +(可选)ZeRO / LoRA
如果你愿意,可以告诉我:
我可以直接给你可运行的训练配置。