训练与优化 / 学习率、精度与梯度 原理笔记入门 4 分钟阅读 查看源文件 ↗

学习率调度#

TL;DR#

本页内容7 个部分

1. 背景与问题#

固定学习率让每次更新共用同一个步长系数,但训练初期、持续拟合与预算末期的需求可能不同。Warmup 先限制步幅,再提高到峰值;衰减则逐渐缩小更新,给后期调整更小的尺度。

这并不是从“离最优解远”直接推出的必然做法。先看一个局部模型,就能理解为什么步长会同时影响稳定性与进展。

2. 目标与定义#

考虑一维二次损失 L(θ)=aθ2/2\mathcal L(\theta)=a\theta^2/2,其中曲率 a>0a>0。SGD 的确定性更新满足 θt=(1−aηt)θt−1\theta_t=(1-a\eta_t)\theta_{t-1};固定步长要让误差收缩,需要 ∣1−aη∣<1|1-a\eta|<1,即 0<η<2/a0<\eta<2/a。

真实模型有不同曲率与随机梯度,不能直接用一个 aa 设定日程,但这个关系说明步幅过大可能放大误差。本文用调度位置 tt、总预算 TT、warmup 长度 TwT_w,三者都按优化步计,0<Tw<T0<T_w<T;峰值为 ηmax⁡\eta_{\max},最低值为 ηmin⁡\eta_{\min}。

3. 方法与推导#

3.1 用阶段进度确定学习率#

先将 warmup 进度归一化为 t/Twt/T_w,从零升至峰值:ηt=ηmax⁡t/Tw\eta_t=\eta_{\max}t/T_w,适用 0≤t≤Tw0\le t\le T_w。起点为非零值的实现需另定义初始学习率。

3.2 怎样得到连续的余弦衰减#

把衰减阶段进度写成 u=(t−Tw)/(T−Tw)u=(t-T_w)/(T-T_w)。希望它在 u=0u=0 取峰值、u=1u=1 取最低值,使用余弦插值:

ηt=ηmin⁡+ηmax⁡−ηmin⁡2[1+cos⁡(πt−TwT−Tw)],Tw≤t≤T.\eta_t=\eta_{\min}+\frac{\eta_{\max}-\eta_{\min}}2\left[1+\cos\left(\pi\frac{t-T_w}{T-T_w}\right)\right],\qquad T_w\le t\le T.

代入两个端点即可检查拼接;对衰减段求导,得到 −π(ηmax⁡−ηmin⁡)sin⁡(πu)/[2(T−Tw)]-\pi(\eta_{\max}-\eta_{\min})\sin(\pi u)/[2(T-T_w)],所以两端下降速度为零,中间最快。这里使用单段余弦,不采用周期重启。[1]

Warmup 与余弦衰减

图示在前 10% 预算 warmup,之后降至峰值的 10%;下面算例使用另一组明确的数值。

4. 计算过程#

设 T=100000T=100000、Tw=2000T_w=2000、ηmax⁡=10−4\eta_{\max}=10^{-4}、ηmin⁡=10−5\eta_{\min}=10^{-5}。下表按同一分段函数计算:

调度位置 tt 学习率 阶段
0 00 warmup
500 2.5e−052.5e-05 warmup
1,000 5e−055e-05 warmup
2,000 0.00010.0001 峰值
10,000 9.8528e−059.8528e-05 余弦衰减
30,000 8.3057e−058.3057e-05 余弦衰减
50,000 5.6442e−055.6442e-05 余弦衰减
51,000 5.5e−055.5e-05 余弦衰减
70,000 2.9255e−052.9255e-05 余弦衰减
90,000 1.2292e−051.2292e-05 余弦衰减
100,000 1e−051e-05 余弦衰减

余弦段中点是 t=(T+Tw)/2=51000t=(T+T_w)/2=51000,此时 ηt=5.5×10−5\eta_t=5.5\times10^{-5};t=50000t=50000 仍略高于这一值。表为公式演算,不是训练效果实验。

5. 比较与边界#

5.1 线性与余弦怎样比较#

比较项 线性衰减 余弦衰减
相同进度 uu 的学习率 ηmin⁡+(ηmax⁡−ηmin⁡)(1−u)\eta_{\min}+(\eta_{\max}-\eta_{\min})(1-u) 使用上节余弦式
下降速度 恒定 先慢、再快、再慢
到达最低值的位置 t=Tt=T t=Tt=T
选择依据 与任务和预算一起验证 与任务和预算一起验证

比较效果时固定峰值、最低值、warmup、有效 batch、总 token 和调参预算。曲线形状本身不能保证某个日程更优。延长训练也会改变同一步对应的衰减进度,不能只修改总步数而忽略已有日程。

5.2 实现约定与其他日程#

Warmup 与 cosine 的调用位置#

按优化步调度时,在一次有效更新后推进 scheduler;梯度累积的 microbatch 不单独推进。AMP 因溢出跳过更新时,是否推进预算应明确定义;本文训练循环采用“只随成功更新推进”的约定。组合实现见训练循环。[2]

OneCycle 的初值与终值#

OneCycle 先升后降,并可让动量反向变化。PyTorch 中 pct_start 决定升温所占比例,initial_lr=max_lr/div_factor,min_lr=initial_lr/final_div_factor。最低值还要包含 div_factor,不能写成 max_lr/final_div_factor。具体参数见 [3]。

LayerNorm 每次前向使用当前输入的统计量,不存在 BatchNorm 那样需要预热的运行均值。Warmup 的必要性仍依赖初始化、结构与优化器;它不能修复错误监督或非有限计算。按优化步调度的接口还需明确首次更新位置与调用顺序。[2]

参考资料#

  1. SGDR(2016). §3:余弦退火;本文只采用单段曲线。
  2. PyTorch 2.9 调度器. 文档:optimizer 与 scheduler 的调用位置。
  3. OneCycleLR(PyTorch 2.9). 文档:初值、终值与阶段比例。

相关阅读路线

完成一次训练更新 ↗