学习率:从入门到大模型训练的终极指南

模型炸了,你把学习率减半。能跑了,但训练慢得令人发指。再减半,损失曲线变成一条直线。这种场景是不是很熟?在所有可调的超参数里,学习率(learning rate, LR)是最容易决定训练成败的那一个——它决定模型是收敛、龟速爬行,还是直接发散。

这篇文章把学习率从最简单的一维抛物线讲起,一路讲到 LLM 预训练的真实配方。目标只有两个:把直觉打通,把可操作的工作流交到你手里。

你将学到什么

  • 为什么"太大就炸、太小就慢"——从最干净的模型推出来
  • batch size、动量、权重衰减为什么必须和学习率一起调
  • 调度大全:constant、step、cosine、WSD、schedule-free 各自适合什么场景
  • LR range test:用 200 个 mini-batch 找到你的稳定上限
  • NaN、震荡、平台期的诊断 checklist
  • 2023 年以来的新进展:Schedule-Free AdamW、D-Adaptation、Power Scheduler、warmup 的新理论

前置知识:基础微积分(梯度、链式法则),且至少训练过一次神经网络。


一、一句话定义

学习率 $\eta$ 决定了你每一步沿梯度方向迈多远。

最基础的更新公式:

$$ \theta_{t+1} = \theta_t - \eta \cdot \tilde g_t, $$

其中 $\tilde g_t$ 通常是 mini-batch 下对真实梯度 $\nabla L(\theta_t)$ 的随机估计。

核心矛盾:

$\eta$ 越大,进步越快,但越容易不稳;$\eta$ 越小,越稳,但越慢,甚至原地不动。

后面的所有内容,本质上都是在讲:“研究者和工程师怎么在这根钢丝上走稳”。


二、为什么"太大就炸、太小就慢"

2.1 从一维抛物线开始(最干净的直觉)

考虑最简单的非平凡损失:

$$ L(\theta) = \tfrac{1}{2} a \theta^2, \qquad a > 0. $$

梯度是 $\nabla L(\theta) = a\theta$,所以梯度下降的递推为:

$$ \theta_{t+1} = \theta_t - \eta a \theta_t = (1 - \eta a)\,\theta_t. $$

整条轨迹其实就是一个公比 $r = 1 - \eta a$ 的等比数列。三种情况一目了然:

  • $|r| < 1 \Leftrightarrow 0 < \eta < 2/a$ —— 收敛到 0;
  • $|r| = 1 \Leftrightarrow \eta = 2/a$ —— 永远在两侧弹跳;
  • $|r| > 1 \Leftrightarrow \eta > 2/a$ —— 直接发散。

稳定上限是 $\eta < 2/a$,其中 $a$ 是曲率。曲率越大,最大可用学习率越小。下面这张图把三种情况画在同一个损失碗里。

三种学习率在一维二次损失上的轨迹

注意右图里参数不是简单地越过谷底——它的振幅在指数级放大。这正是真实训练里把 loss 推成 NaN 的那种"几何爆炸"。

2.2 高维情况:最陡的方向决定上限

真实损失当然不是一维抛物线,但局部用二次近似 $L(\theta) \approx \tfrac{1}{2} (\theta - \theta^\star)^\top H (\theta - \theta^\star)$ 就够用了。Hessian $H$ 的特征值排成 $\lambda_1 \geq \dots \geq \lambda_n \geq 0$,稳定条件就变成:

$$ \eta < \frac{2}{\lambda_{\max}(H)}. $$

关键洞察:大多数方向再缓也没用——只要有一个特别陡的方向(最大特征值),它就独自决定了整个优化器的上限。山谷再宽,只要有一处悬崖边,你就有可能掉下去。

这也解释了为什么训练比"理论上"更难:最大特征值会随训练单调上涨(Cohen et al. 2021 把这种现象叫做 progressive sharpening)。第 100 步还安全的学习率,到了第 10 000 步可能就直接爆炸。

2.3 $L$-光滑:教科书里 $\eta \leq 1/L$ 的来源

把场景从二次推广到一般情形。函数被称为 $L$-光滑($L$-smooth)当其梯度是 $L$-Lipschitz 的:

$$ \|\nabla L(\theta) - \nabla L(\theta')\| \leq L \,\|\theta - \theta'\|. $$

直觉:损失曲面没有"无穷尖锐"的方向,曲率被 $L$ 上界。在这个假设下,经典分析给出:$\eta \leq 1/L$ 时梯度下降不会让损失上升。完整形式叫 descent lemma

$$ L(\theta_{t+1}) \leq L(\theta_t) - \eta\left(1 - \tfrac{\eta L}{2}\right) \|\nabla L(\theta_t)\|^2. $$

这个表达式在 $\eta < 2/L$ 时单调下降,在 $\eta = 1/L$ 时下降最快。这就是优化教材里"安全选择"的由来——你也能看出 $L$ 和 $\lambda_{\max}(H)$ 在这件事上扮演的是同一个角色。

2.4 为什么必须有调度

真实网络里,曲率、梯度噪声、甚至 Hessian 的特征向量都会随训练变化。没有任何一个常数学习率能从头跑到尾。 一个典型的调度通常按顺序做三件事:

  • Warmup——参数还是随机的,曲率巨大,先让 $\eta$ 慢慢爬上去;
  • Stable / 高 LR——曲率稳定下来,趁机狠狠推进;
  • Decay / cooldown——梯度均值很小但噪声不变,把 $\eta$ 降下来精修。

把常见调度画在同一张图上,差异立刻清晰:

常见学习率调度对比:cosine、step、linear、WSD

每条曲线分别适合什么场景,第五节会逐一拆解。


三、batch size、动量、权重衰减:藏起来的耦合

学习率从来不是孤立的超参数。下面三个朋友一直跟着它跑。

3.1 batch size 与线性缩放法则

mini-batch 梯度 $\tilde g_t$ 是真实梯度 $\nabla L(\theta_t)$ 的无偏估计,方差大约是 $\sigma^2 / B$,$B$ 是 batch size。所以:

  • batch 越大 → 噪声越小 → 大 LR 更安全;
  • batch 越小 → 噪声越大 → 大 LR 容易被随机方向"抖飞"。

经典经验法则(Goyal et al. 2017,“Accurate, Large Minibatch SGD”)就是 线性缩放法则:batch 增大 $k$ 倍,LR 也乘 $k$。但必须配 warmup——光靠线性缩放,训练初期会直接过冲。

后来 LAMB、LARS 等大 batch 算法把这一思路又推了一步,但本质没变:LR 和 $B$ 是绑在一起的

3.2 动量:藏在背后的 LR 放大器

带动量的 SGD(Polyak / heavy-ball 形式):

$$ v_{t+1} = \beta v_t + g_t, \qquad \theta_{t+1} = \theta_t - \eta \, v_{t+1}. $$

稳态时 $v_t \approx g / (1 - \beta)$,所以等效步长大约是 $\eta / (1 - \beta)$。常用的 $\beta = 0.9$ 意味着动量把你的有效 LR 放大了 10 倍。这就是为什么"SGD + momentum"配方里的 $\eta$ 通常比裸 SGD 用的更小——动量已经替它踩了一脚油门。

Adam 的一阶矩本质上是同样的事情。

3.3 权重衰减:耦合得很紧的正则化

decoupled weight decay(AdamW)是这样写的:

$$ \theta_{t+1} = \theta_t - \eta \, (\text{自适应更新}) - \eta \lambda \theta_t, $$

每步施加的"收缩"是 $\eta \lambda$。LR 加倍 = 有效权重衰减加倍。稳态权重模长大致是 $\propto \sqrt{1/\lambda}$,与 $\eta$ 无关;但多快达到稳态取决于 $\eta$。所以"LR 越小,正则化越弱"是真实存在、却经常被忽视的效应。

实操结论:重新调 LR 的时候,把 weight decay 也一起再扫一遍。


四、自适应优化器:把学习率变成"一组学习率"

如果说 SGD 的 LR 是一把大锤,Adam 就是装了一柜子小锤的工具箱——每个参数都有自己的步长。

4.1 Adam 的更新式

$$ \begin{aligned} m_t &= \beta_1 m_{t-1} + (1-\beta_1) g_t, \\ v_t &= \beta_2 v_{t-1} + (1-\beta_2) g_t^2, \\ \hat m_t &= m_t / (1 - \beta_1^t), \quad \hat v_t = v_t / (1 - \beta_2^t), \\ \theta_{t+1} &= \theta_t - \eta \cdot \frac{\hat m_t}{\sqrt{\hat v_t} + \varepsilon}. \end{aligned} $$

关键就在 $\eta / \sqrt{\hat v_t}$ 这一项——每个参数的有效 LR 大约是 $\eta / |g|$。梯度持续大的参数被自动调小步长,梯度小的参数仍然能走完整 $\eta$。这就是 Adam 在不同尺度的参数(embedding、attention、layer norm)上都能开箱即用、而 SGD 必须靠 per-layer LR 才能勉强跟上的原因。

4.2 为什么 Adam 仍然需要 warmup

很多人会想:Adam 都自适应了,还要 warmup 干嘛?两个理由:

  • 早期统计量非常不稳。 $\hat v_t$ 是几个噪声梯度估出来的;偏置修正项 $(1 - \beta_2^t)$ 在 $t$ 很小时会被除得非常大。这是过去的标准解释。
  • 预条件化曲率(preconditioned sharpness)很大。 更新的解释来自 Kalra et al. 2024 的 Why Warmup the Learning Rate?:warmup 把网络推到一个"预条件化 Hessian 最大特征值更小"的区域——本质上是在重塑优化地形,让后面更大的峰值 LR 变得安全。

无论哪种解释,结论都一样:Adam 永远要 warmup。视觉/CNN 用 1–5% 的总步数;LLM 和超大 batch 推荐 5–10%。


五、调度大全:从老办法到大模型默认

上面那张图把四个最常用的家族画在了一起,下面看每条线分别适合什么场景。

5.1 常数 LR

简单。基本上永远是错的——不是早期太慢,就是后期太抖,没有两全。

5.2 Step decay

到达指定 milestone 时把 $\eta$ 乘以 $\gamma$(通常 0.1)。经典 ResNet 配方就用这个。优点:实现简单、手工调参直观。缺点:突然的下台阶可能让 weight decay 或 BN 敏感的网络出现 loss spike。

5.3 Cosine decay(深度学习的工作马)

$$ \eta_t = \eta_{\min} + (\eta_{\max} - \eta_{\min}) \cdot \tfrac{1}{2}\left[1 + \cos\left(\pi \cdot \tfrac{t - t_w}{T - t_w}\right)\right], $$

前面再接一段长度 $t_w$ 的线性 warmup。它的形状——前期降得慢、后期降得快——刚好契合直觉:在高 $\eta$ 上探索得越久越好,最后再快速收敛。

2019 到 2023 年间几乎所有"大模型"论文(BERT、RoBERTa、GPT-3、ViT、ImageNet 上的大规模 ResNet)默认就是它。最大的缺点是死板:cosine 半周期由已知的总步数 $T$ 决定。想延长训练?整条曲线得重做。

5.4 WSD:Warmup–Stable–Decay(现代 LLM 默认)

Hägele et al. 2024(Scaling Laws and Compute-Optimal Training Beyond Fixed Training Durations)等工作把 WSD 推成了主流:

  • Warmup——和以前一样;
  • Stable——把 $\eta = \eta_{\max}$ 持续整个训练的大部分(60–90%);
  • Cooldown——最后 10–20% 线性(或多项式)降到 $\eta_{\min}$。

它能在 LLM 圈成为默认有三个理由:

  1. 可续训、可扩展。 想多跑 2× tokens?继续 stable 阶段,再 cooldown 即可。Cosine 没法在不重新拟合曲线的情况下做到这点。
  2. “cooldown 最后一跳"现象。 经验上 cooldown 一开始 loss 就会出现一次明显下降——好像模型一直被"按着”,到此终于被允许精细贴合。
  3. 理论支持。 Schaipp et al. 2025(The surprising agreement between convex optimization theory and learning-rate scheduling,arXiv:2501.18965)证明 cooldown 形状刚好对上凸优化里一个紧的界,cooldown 这一段在界里对应的是"去掉对数项"。

5.5 Cosine vs WSD vs Schedule-Free 速览

调度优点缺点适合
Cosine平滑、久经考验需要事先知道 $T$训练长度固定
WSD可续训、阶段清晰、cooldown 末段下降明显需要选 cooldown 起点长训练 / 可续训的 LLM
Schedule-Free不需要 $T$、几乎不用调较新、实战经验少原型迭代、训练预算不定

六、LR range test:200 个 batch 找到你的上限

挑选 $\eta_{\max}$ 最有用的工具,最初由 Smith 2015(Cyclical Learning Rates)提出:

  1. 把 $\eta$ 设成 $\eta_{\min} \approx 10^{-7}$;
  2. 每个 mini-batch 之后把 $\eta$ 乘以一个固定因子(如 1.1),让它指数增长;
  3. loss 开始上升就停;
  4. 把 loss 对 $\log\eta$ 画图。

你会看到四个阶段:噪声平台 → 下降段 → 噪声最低点 → 爆炸。“边界"就在爆炸前那一点;正式训练的峰值 LR 取在 $[0.3 \times, 1.0 \times]$ 这个边界之间。

LR range test:取稳定边界的 0.3-1×

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import math
import torch

def lr_range_test(model, loader, loss_fn, optimizer,
                  lr_min=1e-7, lr_max=10, num_steps=200):
    """指数扫一遍 LR,返回 (lrs, losses) 用于画图。"""
    model.train()
    mult = (lr_max / lr_min) ** (1 / (num_steps - 1))
    lr = lr_min
    for g in optimizer.param_groups:
        g["lr"] = lr

    lrs, losses = [], []
    it = iter(loader)
    for _ in range(num_steps):
        try:
            x, y = next(it)
        except StopIteration:
            it = iter(loader)
            x, y = next(it)

        optimizer.zero_grad(set_to_none=True)
        loss = loss_fn(model(x), y)
        loss.backward()
        optimizer.step()

        lrs.append(lr)
        losses.append(loss.item())
        lr *= mult
        for g in optimizer.param_groups:
            g["lr"] = lr
    return lrs, losses

工程实现上更稳的做法是给 loss 加一个指数滑动平均,并且在 loss 超过历史最低值 $4\times$ 时自动停止——fastailr_find() 就是这么写的。


七、不同优化器,曲线长得不一样

同一条调度套到不同优化器上,得到的 loss 曲线并不一样。下图把同一条 warmup-cosine 调度同时应用到 AdamW 和 SGD-with-momentum 的合成任务上:AdamW 早期下降更快,SGD 往往后段才追上来,且对峰值 LR 更敏感。

Adam vs SGD 在同一条 warmup-cosine 调度下的对比

十年配方浓缩成几条经验:

  • AdamW + lr ≈ 1e-4 ~ 5e-4——Transformer 类、NLP/多模态预训练。
  • AdamW + lr ≈ 1e-5 ~ 5e-5——预训练 Transformer 的微调。
  • SGD + momentum 0.9 + lr ≈ 0.1——从零训练 ResNet/CNN,配 cosine 或 step decay。
  • 想省显存(不存二阶矩)、且愿意花时间调参时,仍然首选 SGD + momentum。

八、Layer-wise / 判别式 LR:微调的杀手锏

微调预训练模型时,底层已经学会了如何提取好的特征——你不希望大学习率把它们冲掉;高层是随机的、任务特定的,需要更大的更新。ULMFiT(Howard & Ruder 2018)把这件事系统化为 判别式学习率(discriminative learning rates):顶层用一个小的基础 LR,每往下一组就除以一个因子(通常 2.6 或 0.8)。

ULMFiT 风格的逐层判别式 LR

最小可用的 PyTorch 实现:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
def layer_wise_param_groups(model, base_lr=3e-4, decay=0.8):
    """越靠近输入的层,LR 越小。"""
    layers = list(model.encoder.layer)            # Hugging Face 风格
    groups = []
    n = len(layers)
    for i, layer in enumerate(layers):
        groups.append({"params": layer.parameters(),
                       "lr": base_lr * (decay ** (n - 1 - i))})
    groups.append({"params": model.classifier.parameters(), "lr": base_lr})
    return groups

LLM 微调里同样的思路换了几张皮:

  • LoRA / adapter——只训练一小撮新参数,LR 给满;其余冻住。
  • LLaMA-Adapter 风格——逐渐解冻,被解冻部分用更小的 LR。

九、Schedule-free 与 learning-rate-free

调度本身、甚至学习率这个标量,原则上都可以被消掉。最近两条研究路线在做这件事。

9.1 D-Adaptation(Defazio & Mishchenko, 2023)

D-Adaptation 在训练过程中估计"当前点到最优点的距离”,再用这个距离反推步长。没有 $\eta$ 可调。在很多任务上能在几个百分点内追平手调的基线。

9.2 Schedule-Free AdamW(Defazio et al., 2024,arXiv:2405.15682)

它把 iterate averaging 和一个常数基础 LR 结合起来,得到"看起来像 cosine 衰减过"的轨迹,但全程并不显式地降 $\eta$。这意味着你不需要事先承诺训练总步数 $T$:想停就停,想延长就延长,不必重调调度。

Schedule-free vs cosine:不必指定 T 仍能匹敌

什么时候考虑这两类方法?

  • 原型阶段,预算还没定;
  • 多预算研究(比较 5%、25%、100% tokens),每条都重做 cosine 太烦;
  • 弹性算力场景(被抢占、被重新调度)。

十、真实 LLM 调度长什么样

GPT-3(175B)和 LLaMA(7B/13B/65B)用的是同一个模板:短的线性 warmup,然后 cosine 退到峰值 LR 的 10%。峰值本身随模型规模下降——按 GPT 缩放律大致是 $\eta_{\max} \propto 1/\sqrt{N}$。

典型 LLM 预训练调度(GPT-3 / LLaMA 风格)

公开论文里的具体数字:

模型峰值 LR最小 LRWarmup调度Batch (tokens)
GPT-3 175B(Brown et al., 2020)0.6e-40.6e-5375M tokenscosine3.2M
LLaMA-7B(Touvron et al., 2023)3e-43e-52 000 步cosine4M
LLaMA-65B1.5e-41.5e-52 000 步cosine4M
Chinchilla 70B(Hoffmann et al., 2022)1e-41e-51 875 步cosine1.5M–3M
MiniCPM(Hu et al., 2024)1e-21e-32% 步数WSD视情况

几个几乎是常识但容易忽略的点:

  • 最小 LR ≈ 峰值 LR 的 10% 是事实标准,不是 0。一退到 0 经常意味着最后几千步等于白跑。
  • 梯度裁剪到 1.0 在这一规模几乎是必备的;不裁的话,偶尔一个坏 batch 就能把你推下悬崖。
  • weight decay = 0.1(decoupled,AdamW 风格)也是 LLM 配方里的常见默认——比视觉里的 1e-4 要大得多。

十一、从"能跑"到"跑得好":可操作的工作流

Step 1 —— 先判断失败的类型

训练失败有三种典型形态:

症状大概率原因
几步内 loss → NaN/InfLR 太大;缺 warmup;缺裁剪;AMP underflow
loss 大幅震荡LR 太大;动量过大;norm-decay 不匹配
loss 几乎不动LR 太小;调度衰得太快;数据/标签有 bug

Step 2 —— 找你的上限

跑一次 LR range test(第六节)。绝大多数"我试了 1e-3 和 1e-4 都不行"的故事,到这一步就解决了。

Step 3 —— 选调度

场景默认
中型模型(<1B 参数),预算固定warmup + cosine
LLM 预训练,可能续训warmup + WSD
微调预训练模型线性 warmup + 线性衰减,峰值 ≈ 1e-5 ~ 5e-5
预算未知 / 不固定Schedule-Free AdamW

Step 4 —— LR、batch、weight decay 联动

不要孤立地动 LR。心里要装着这张三方耦合表:

问题错的做法更合理
训练不稳闷头降 LR加梯度裁剪、延长 warmup、加大 weight decay
Loss 卡在高位闷头加 LR增大 batch(降噪声);先排查数据流水线
过拟合降 LR加 weight decay;加 dropout/数据增强

Step 5 —— 监控三个量,不只是 loss

  • 梯度模长——warmup 之后应该大致平稳;突然飙升通常是发散的前兆。
  • 更新 / 参数比 $\|\Delta\theta\| / \|\theta\|$——大约 $10^{-3}$ 是健康值。低于 $10^{-5}$ 是欠拟合,高于 $10^{-2}$ 接近不稳。
  • LR 敏感度——$\eta$ 的小变动如果造成最终 loss 大变,就说明你已经贴在稳定边界上了,留点余量。

十二、Troubleshooting checklist

12.1 Loss 一开始就炸(NaN / Inf)

按优先级排:

  1. 把峰值 LR 降一个数量级(如 3e-4 → 3e-5);
  2. 加上或延长 warmup(如从 0 → 5% 步数);
  3. 加梯度裁剪:torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
  4. 检查混合精度:fp16 是否在用 GradScaler,或者切到 bf16
  5. 加大 weight decay(尤其是 LLM)。

12.2 Loss 下降太慢

常见原因:

  • LR 太小(先做一次 LR range test);
  • 调度衰得太快(用 WSD 拉长 stable 阶段);
  • batch 太小、噪声太大(增大 batch 或用 gradient accumulation);
  • 数据/标签有问题(这不是 LR 能救的,先查流水线)。

12.3 Loss 大幅震荡

  • 把峰值 LR 降 10–30%;
  • 减小动量($\beta = 0.9 \to 0.85$,或 Adam 的 $\beta_1 = 0.9 \to 0.85$);
  • 加梯度裁剪;
  • 检查优化器和归一化的搭配(AdamW + LayerNorm 很稳;SGD + BatchNorm 在大 LR 下脆弱)。

12.4 验证 loss 偏离训练 loss

这是过拟合,不直接是 LR 问题,但 LR 影响隐式正则:

  • 加大 weight decay;
  • 把峰值 LR 略降(更慢的训练通常泛化更好);
  • 加 dropout、label smoothing、数据增强;
  • 配 patience 5–10 的 early stopping。

十三、参考实现

Warmup + Cosine

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import math

def lr_warmup_cosine(step, total_steps, warmup_steps, lr_max, lr_min=0.0):
    """线性 warmup,然后 cosine 从 lr_max 退到 lr_min。"""
    if step < warmup_steps:
        return lr_max * (step + 1) / max(1, warmup_steps)
    t = step - warmup_steps
    T = max(1, total_steps - warmup_steps)
    cos = 0.5 * (1.0 + math.cos(math.pi * t / T))
    return lr_min + (lr_max - lr_min) * cos

Warmup + Stable + Decay (WSD)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
def lr_wsd(step, total_steps, warmup_steps, cooldown_steps,
           lr_max, lr_min=0.0):
    """warmup → 常数 lr_max → 线性 cooldown 到 lr_min。"""
    if step < warmup_steps:
        return lr_max * (step + 1) / max(1, warmup_steps)
    stable_end = total_steps - cooldown_steps
    if step < stable_end:
        return lr_max
    t = step - stable_end
    T = max(1, cooldown_steps)
    frac = min(1.0, (t + 1) / T)
    return lr_max + (lr_min - lr_max) * frac

接到训练循环里

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import torch

def train_one_epoch(model, loader, optimizer, step_offset, total_steps,
                    schedule_fn, device="cuda", clip_norm=1.0):
    model.train()
    step = step_offset
    for x, y in loader:
        x, y = x.to(device), y.to(device)
        lr = schedule_fn(step, total_steps)
        for g in optimizer.param_groups:
            g["lr"] = lr

        optimizer.zero_grad(set_to_none=True)
        loss = torch.nn.functional.cross_entropy(model(x), y)
        loss.backward()
        torch.nn.utils.clip_grad_norm_(model.parameters(), clip_norm)
        optimizer.step()
        step += 1
    return step

典型配置:

1
2
3
4
5
6
schedule_fn = lambda s, T: lr_wsd(
    step=s, total_steps=T,
    warmup_steps=int(0.02 * T),
    cooldown_steps=int(0.10 * T),
    lr_max=3e-4, lr_min=3e-5,
)

十四、2023 年以来的新进展

下面五条线值得跟踪。

14.1 D-Adaptation —— Learning-rate-free(2023)

思路:在训练过程中估计"当前点到最优点的距离",再用这个估计推算步长。没有可调的 $\eta$。原型迭代和 grid search 收敛阶段非常有用。

参考:Learning-Rate-Free Learning by D-Adaptation (Defazio & Mishchenko, 2023)

14.2 Schedule-Free AdamW(2024)

把 iterate averaging 和常数基础 LR 结合起来,达到与有调度方法相当的性能,却不需要显式衰减——更不需要事先承诺总步数 $T$。

参考:Schedule-Free AdamW (Defazio et al., 2024, arXiv:2405.15682)

14.3 Warmup 为什么"真的"有效(2024)

老解释——“等 Adam 统计量稳定下来”——并不完整。Kalra et al. 2024 证明 warmup 实际上降低了预条件化 Hessian 的最大特征值,从而让一个更大的可持续峰值 LR 变得安全。

参考:Why Warmup the Learning Rate? (Kalra et al., 2024, arXiv:2406.09405)

14.4 Power Scheduler —— 对 batch / token 不敏感(2024)

换 batch、换训练 token 数,最优 LR 都会漂。Power Scheduler 利用 LR、batch、token 之间的幂律关系,给出一种在不同规模间可迁移的调度。

参考:Power Scheduler: A Batch Size and Token Number Agnostic Learning Rate Scheduler (Shen et al., 2024, arXiv:2408.13359)

14.5 用小模型复现 LLM 不稳定(2023–2024)

很多"只有 LLM 才会出现"的 loss spike,把小模型的 LR 调高就能复现。这意味着你可以用 1/100 的成本调研真实的不稳定性。

参考:Small-scale proxies for large-scale Transformer training instabilities (Wortsman et al., 2023, arXiv:2309.14322)

14.6 Cosine ↔ WSD 的凸优化桥梁(2025)

Schaipp et al. 2025(arXiv:2501.18965)证明 WSD 的 cooldown 形状和某个紧的凸优化界完全对应,cooldown 这一段在界里负责"消去对数项"。这给"为什么 cooldown 有用"提供了一个有原则的解释。

参考:The surprising agreement between convex optimization theory and learning-rate scheduling (Schaipp et al., 2025, arXiv:2501.18965)


十五、一页速查表

AdamW 默认配方

  • 调度:warmup + cosine 或 warmup + WSD;
  • warmup:1–5% 总步数(超大 batch / LLM 取 5–10%);
  • cooldown(仅 WSD):最后 10–20% 步数;最小 LR = 峰值的 10%;
  • 梯度裁剪max_norm = 1.0(LLM 几乎必备);
  • weight decay:视觉 0.01;LLM 0.1(decoupled);
  • 峰值 LR 经验值
    • 从零训练 Transformer:1e-4 ~ 5e-4
    • 微调 Transformer:1e-5 ~ 5e-5
    • 从零训练 CNN(SGD-momentum):0.05 ~ 0.1

比看 loss 更直接的三个信号

  • 梯度模长——warmup 之后应当平稳;飙升 = 麻烦;
  • $\|\Delta\theta\| / \|\theta\|$——稳态大约 $10^{-3}$;
  • LR 敏感度——小变动就能影响最终 loss = 你贴着边界。

快速分诊

症状第一步第二步
早期 NaN / Inf降 LR 10×加 warmup;裁剪到 1.0
下降缓慢LR range test拉长 stable(WSD)
大幅震荡降 LR 或动量加裁剪
训练-验证差距大加 weight decay略降 LR

十六、五步总结

  1. 跑一次 LR range test,找到稳定边界;
  2. 峰值 LR 取边界的 0.3–1×
  3. 加 warmup——视觉 1–5%,LLM 5–10%;
  4. 选调度——预算固定用 cosine,可续训 LLM 用 WSD,预算未知用 schedule-free;
  5. 联动调 batch、weight decay、梯度裁剪。永远不要孤立地调 LR。

如果只能记一句话:绝大多数被甩锅给"优化器"的训练问题其实是 LR 调度问题,而绝大多数 LR 调度问题,一个下午、一次 LR range test、一段 warmup 就能解决。


延伸阅读

Liked this piece?

Follow on GitHub for the next one — usually one a week.

GitHub