学习率与 warmup
训练初期 LR 过大容易 loss spike——linear/cosine warmup 让优化稳定;peak LR 和 total steps 要匹配 batch size 和 optimizer。

1. 第三步 loss 变 NaN,多半是 LR 不是数据
ViT 微调,backbone 从 ImageNet 预训练加载,head 随机初始化。直接用 peak LR 训 AdamW,第 3 step loss spike 后 NaN——不是标签错,是 冷启动 LR 对随机 head 和预训练 backbone 同时过大。Transformer 大 batch + 大 LR 无 warmup 是常见炸点;CNN 小模型有时能扛,不能照搬 schedule。NaN 后先查 LR 曲线与 spike 点对齐,再查数据——顺序反了会浪费一天洗数据。
2. warmup 在改什么
训练初期梯度方向噪声大、Adam 二阶矩未稳定。warmup 把 LR 从接近 0 线性(或 cosine)升到 peak,让 optimizer state 和 loss landscape 对齐,再进入 decay。peak LR 必须与 effective batch size(batch × grad accum × GPU 数)匹配——batch 翻倍,linear scaling rule 下 peak LR 常近似翻倍,warmup steps 也要按 total steps 比例调整。total steps 算错(忘了 grad accum)会导致 cosine 提前结束或尾巴过长,表现像「训不够」或「后期过拟合」。
3. PyTorch 接线:per-step,不是 per-epoch
Transformer 按 step 调度;把 scheduler.step() 放 epoch 末是 silent bug——同一 epoch 内 LR 不变,等效少 warmup 几百步。
from torch.optim.lr_scheduler import LinearLR, CosineAnnealingLR, SequentialLR
warmup = LinearLR(optimizer, start_factor=0.01, total_iters=warmup_steps)
cosine = CosineAnnealingLR(optimizer, T_max=total_steps - warmup_steps)
scheduler = SequentialLR(optimizer, [warmup, cosine], milestones=[warmup_steps])
for step, batch in enumerate(loader):
loss.backward()
optimizer.step()
optimizer.zero_grad(set_to_none=True)
scheduler.step()HuggingFace get_linear_schedule_with_warmup 同理。OneCycleLR 含 warmup + anneal,pct_start=0.1,也要 per-step。训练 loop 里 log 当前 optimizer.param_groups[0]['lr'],与 tensorboard 曲线交叉验证。
4. 分层 LR
ViT 常用 backbone lr × 0.1、head lr。预训练层已收敛,大 LR 毁表征;head 需快速适配。param group 名必须与 model 模块一致——改一层 LR 时固定 seed 与 batch 单变量 ablation,log lr、loss、grad_norm(clip 前)、AMP scale。若 backbone 也一起大 LR,表现常像「head 没学好且 backbone 花了」。
5. resume 与 checkpoint
checkpoint resume 必须 reload scheduler state_dict,否则 LR 从 0 重启或跳到 decay 中段。已训 step 数要扣进 T_max 和 warmup milestone。只 load model 不 load scheduler 是「resume 后曲线怪」的常见原因。实验 log 应存 scheduler state,而不只是 model weights。多节点中断恢复时,全局 step 计数与 dataloader skip 也要对齐,否则 LR 与数据 epoch 错位。
6. weight decay 与 LR 的耦合
AdamW 里 weight decay 与 LR 同乘在参数上;调 peak LR 时不调 decay,effective 正则会变。微调小数据集略增 decay 或 early stop,而不是无限加 epoch 指望 cosine 尾部「自己好」。config 注释里联动记录 LR 与 decay,避免后人只改一项。
7. 失败模式
| 现象 | 常见原因 |
|---|---|
| warmup 后仍 spike | warmup 太短 / peak LR 过大 |
| LR 曲线阶梯 | step() 放 epoch 末 |
| resume 后 loss 跳 | scheduler state 未 load |
| 分层 LR 无效 | param group 名不匹配 |
8. 验收
log LR vs step 与 loss 同图;warmup 段 loss 应单调降而非 spike。val 存 best → test 一次,不用 test 调 peak LR。相对无 warmup baseline 有明确 metric 增益;改动可单变量回滚。NaN 回溯四件套:LR 曲线、loss scale、augment、num_classes。
9. 案例:epoch step 放错
某 ViT 微调把 scheduler.step() 放在 epoch 结束,log 显示 LR 每 epoch 才变一次——warmup 名义 500 step 实际只升了 2 个 epoch 的 LR,第 3 epoch 仍 spike NaN。改 per-step 后同 config 稳定训满。Code review 对 Transformer 训练 loop 默认查 scheduler 调用位置,与查 loss.backward() 一样硬。
10. 与 AMP / GradScaler 的交点
warmup 段 LR 小,GradScaler 可能长期不 unscale,grad 看起来接近零——别误判为「梯度消失」。log 应同时有 LR、loss、grad_norm(unscale 前)、scale。Transformer 微调若开 AMP,NaN 回溯顺序:LR spike → loss scale 过大 → 某层 inf。warmup 与 AMP 无冲突,但 resume 时要同时 reload scaler state。
11. 团队 config 契约
训练 yaml 必填:peak_lr、warmup_steps、total_steps、scheduler_type、per_step: true、分层 LR param groups。改 batch size 必须联动改 peak_lr 与 warmup_steps,PR 描述写清 scaling 依据。没有契约字段,后人复制 config 换 GPU 数后 silent 改 effective schedule。Cosine 尾巴过长时 val 已 overfit 但 train loss 仍缓慢降——看 val 曲线截断 total_steps,而不是加 warmup 救场。OneCycle 的 max_lr 与 warmup 内 peak 不是同一概念,换 scheduler 类型时重写 yaml 注释,避免复制旧 key 名。微调 LLM 时 warmup 常占 total 的 3–10%,分类 CNN 可更短——照抄 HF 默认值而不按 task 调是常见 under-warmup。Grad clip max norm 与 warmup 同期调,大 LR 窗口需更紧 clip 防 spike。
12. 案例:resume 丢 scheduler
某 ViT 微调 checkpoint resume 只 load model,LR 从 cosine 尾部跳回 warmup 起点,loss 震荡三轮。fix:resume 必 load scheduler+scaler;yaml 加 resume_load_scheduler: true 默认开。团队 template 训练脚本统一封装 save/load 字段,禁止每人手写五版本 checkpoint 格式。Fine-tune 总 step 少时 warmup 占 10% 仍可能 only 几十 step——按绝对 step 数而非百分比 blindly 抄大模型 recipe。Cosine restart 与 warmup 并用时 milestone 列表易错,改 scheduler 类型应配单元测试验 LR 序列前 100 step。HuggingFace Trainer 用户确认 args.max_steps 与 dataloader len×epochs 一致,避免 scheduler 与真实 step 脱节。Linear scaling LR 时同步 scale warmup_steps,否则 effective warmup 比例漂移。DeepSpeed 等封装 scheduler 时确认 step 钩子仍 per-iteration 触发。Fine-tune 总 step 少于 warmup 时改用固定 warmup_steps 下限,例如至少 100 step。Report LR 曲线截图进 PR,reviewer 可目视 warmup 是否生效。
Warmup 是把 optimizer 契约与 total steps、batch size 绑在一起的调度前置条件,不是可选装饰。
相关
也可以看看
- ·3 分钟阅读
grad_norm spike 与 misclass grid
只看 train loss 不够——要 log lr、grad norm、val slice、GPU 利用率和样例可视化,异常通常是 loss 曲线先以外的信号。
- ·5 分钟阅读
beta=0.999 与 eval 权重
训练时对参数做指数滑动平均,验证和部署常用 EMA 权重——曲线更顺,有时泛化更好,但要与 optimizer 步和 checkpoint 策略一致。
- ·5 分钟阅读
use_reentrant=False 粒度
Gradient checkpointing 用重算 forward 换显存——训练大模型或高分辨率输入时 OOM 的常用解法,wall-clock 涨 20–40% 要算进预算。
johan's blog