训练开始时,所有参数都是随机的。随机参数产生的输出是噪声,噪声产生的 loss 很大,大 loss 产生的梯度也很大且方向不稳。
如果此时直接用峰值学习率(0.0003),大梯度 × 大学习率 = 非常大的更新量。参数被巨幅调整,可能从一个随机位置跳到另一个更糟的随机位置——训练在起跑线上就崩溃了。
Warmup 的做法
Warmup 在训练的最初几百或几千步中,把学习率从接近零逐步增加到峰值:
步数 0: 学习率 = 0
步数 100: 学习率 = 0.00003
步数 200: 学习率 = 0.00006
...
步数 1000: 学习率 = 0.0003(峰值)
最简单的 warmup 是线性的:学习率 = 峰值 × (当前步数 / warmup 步数)。第 500 步时就是峰值的一半。
为什么 Adam 特别需要 Warmup
Warmup 不只是「因为初始梯度大所以要小心」——它还跟 Adam 的内部机制有关。
回顾上一章节:Adam 维护两个统计量 m(一阶动量)和 v(二阶动量),初始值都是零。训练刚开始时:
- m ≈ 0,v ≈ 0
- 偏差修正会把 m 和 v 放大——但放大的倍率在前几步非常不稳定
具体来看第 1 步(β₁ = 0.9,β₂ = 0.95):
m₁ = 0.9 × 0 + 0.1 × g = 0.1g
v₁ = 0.95 × 0 + 0.05 × g² = 0.05g²
偏差修正:m̂₁ = 0.1g / (1−0.9) = g
v̂₁ = 0.05g² / (1−0.95) = g²
偏差修正在第 1 步完全依赖单个 batch 的梯度——一个样本的估计。这个估计可能很不准确:如果第一个 batch 恰好有极端数据,Adam 的更新方向可能完全错误。
到了第 100 步,m 和 v 已经积累了 100 个 batch 的信息,估计就稳定多了。Warmup 正好在这段不稳定的区间里压低学习率——等 Adam 的统计量稳定之后再释放全部学习速率。
在这个过程中发生了什么
三个阶段叠加在一起:
步数 学习率 Adam 状态 参数状态
─────────────────────────────────────────────────
0-100 极小 m,v 刚开始积累 随机噪声
100-500 逐渐增大 m,v 越来越准 开始有意义
500-1000 接近峰值 m,v 已经稳定 进入高效学习
1000+ 峰值 正常运行 主训练阶段
到 warmup 结束时,三个条件同时满足:Adam 的统计量稳定了、参数已经离开随机区域、学习率到达峰值——训练进入最高效的阶段。
为什么不一直用小学习率
如果小学习率更安全,为什么不一直用小学习率呢?
因为太慢了。学习率 0.00003 比峰值小了 10 倍——训练速度也大致慢了 10 倍。Sophia 的预训练花了 315 个 GPU 小时;如果学习率一直只有峰值的十分之一,相同的训练效果需要几千个 GPU 小时。
Warmup 让训练在安全和速度之间取得平衡:起步慢一点,确保不崩溃,然后尽快提速到最高效率。
Sophia 的 Warmup
Sophia 的 warmup 阶段大约占训练总步数的 1-2%。如果总训练是 40,000 步,warmup 大约 400-800 步。
这个比例在大模型训练中是常见的。太短(几十步)会不够安全——Adam 的统计量还没稳定就直接冲到峰值。太长(10% 以上)会浪费训练预算——在低学习率下跑了太久,等于减少了高效训练的时间。
下一章节来看训练后期为什么要把学习率降下来。