2.5 KiB
2.5 KiB
第7节:混合精度 + 梯度累积 + 梯度裁剪
训练流程核心机制笔记
📚 本节目录
1. 整体训练流程(核心顺序)
scaler.scale(loss).backward()
if step % accumulation_steps == 0:
scaler.unscale_(optimizer)
clip_grad_norm_(model.parameters(), max_norm)
scaler.step(optimizer)
scaler.update()
optimizer.zero_grad(set_to_none=True)
2. 每一步在干什么
(1) scaler.scale(loss).backward()
作用:AMP 防止 FP16 下溢
- loss 先乘一个 scale(放大)
- backward 计算梯度
目的:防止 FP16 数值太小 → 梯度变 0
(2) 梯度累积(accumulation)
每 N 步才更新一次参数
作用:
- 模拟大 batch training
- 节省显存
(3) scaler.unscale_(optimizer)
作用:梯度"还原"
因为之前 loss 被放大了:grad = grad × scale
所以这里要把梯度恢复到真实数值(为了梯度裁剪)
(4) clip_grad_norm_()
作用:防止梯度爆炸
数学本质:
先算整体梯度范数:
\|g\| = \sqrt{\sum_i g_i^2}
- 如果
norm ≤ max_norm:不变 - 如果
norm > max_norm:缩放 →g := g × max_norm / norm
直觉:不改变方向,只限制"更新步子大小"
(5) scaler.step(optimizer)
作用:真正更新参数
- 如果检测到 NaN/Inf → 自动跳过
- 否则正常 optimizer.step()
(6) scaler.update()
作用:动态调整 loss scale
| 情况 | 动作 |
|---|---|
| 出现 NaN/Inf | scale ↓(变小,更保守) |
| 训练稳定 | scale ↑(变大,提高精度) |
本质:自动调节 FP16 "放大倍率",保证稳定 + 高效
(7) optimizer.zero_grad(set_to_none=True)
作用:清空梯度
set_to_none=True → 更省显存 + 更快
3. 三大核心机制总结
AMP(scaler)
👉 解决 FP16 数值问题
- scale loss(防 underflow)
- 自动调 scale(防 overflow)
梯度累积
👉 解决显存限制
- 多 step 累积梯度
- 再统一更新
梯度裁剪
👉 解决梯度爆炸
- 控制 norm 上限
- 保持方向不变
4. 一句话总理解
这套流程本质是在做三件事:
- 用 AMP 提速
- 用 accumulation 放大 batch
- 用 clipping 保稳定