
优化理论(四):学习率与调度策略
从一维抛物线讲到 LLM 预训练配方,覆盖 cosine/WSD/Schedule-Free、LR range test、warmup 新理论与诊断 checklist。
模型崩溃了,你把学习率减半——模型终于能训练了,但速度慢得惊人;再减半,损失几乎不再下降,曲线趋于平缓。这种场景是不是很熟?在所有可调的超参数里,学习率(learning rate, LR)是最容易决定训练成败的那一个——它直接决定了模型是顺利收敛、进展极其缓慢,还是迅速发散。
这篇文章把学习率从最简单的一维抛物线讲起,一路讲到 LLM 预训练的真实配方。目标很明确:一是建立清晰的直觉,二是提供一套可立即落地的操作流程。
训练一开始模型就崩了,把学习率减半,模型终于能跑了,但慢得离谱;再减半,loss 几乎不动。这种循环熟不熟悉?在所有可调的超参里,学习率是最容易决定训练成败的那一个——不是“收敛与否”,就是“快与慢”。
这篇文章我想把学习率讲成一个连贯的故事:从最简单的一维抛物线开始(让你看清楚“为什么太大就炸”),一直讲到 LLM 预训练里 cosine、WSD、Schedule-Free 这些真实在用的调度。目标是两件事——一是让你建立稳的直觉,看到一条 loss 曲线就能反推“是不是 LR 的问题”;二是给你一套能直接抄走的操作流程。
你将学到什么#
- 为什么“太大就炸、太小就慢”——从最干净的模型推出来
- 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$ 越小,越稳,但越慢,甚至原地不动。
后面的所有内容,本质上都是在讲:“研究者和工程师怎么在这根钢丝上走稳”。
为什么“太大就炸、太小就慢”#
从一维抛物线开始(最干净的直觉)#
$$L(\theta) = \tfrac{1}{2} a \theta^2, \qquad a > 0.$$ $$\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 的那种“几何爆炸”。
高维情况:最陡的方向决定上限#
$$\eta < \frac{2}{\lambda_{\max}(H)}.$$关键洞察:大多数方向再缓也没用——只要有一个特别陡的方向(最大特征值),它就独自决定了整个优化器的上限。即使多数方向曲率平缓,只要存在一个曲率极大(即 Hessian 最大特征值很大)的方向,优化过程就可能失稳。
这也解释了为什么训练比“理论上”更难:最大特征值会随训练单调上涨(Cohen et al. 2021 把这种现象叫做 progressive sharpening)。第 100 步还安全的学习率,到了第 10 000 步可能就直接爆炸。
$L$ -光滑:教科书里 $\eta \leq 1/L$ 的来源#
$$\|\nabla L(\theta) - \nabla L(\theta')\| \leq L \,\|\theta - \theta'\|.$$ $$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)$ 在这件事上扮演的是同一个角色。
为什么必须有调度#
真实网络里,曲率、梯度噪声、甚至 Hessian 的特征向量都会随训练变化。不存在一个固定的常数学习率,能够在整个训练过程中始终保持最优性能。 一个典型的调度通常包含三个阶段:
- Warmup——参数还是随机的,曲率巨大,先让 $\eta$ 慢慢爬上去;
- Stable / 高 LR——曲率稳定下来,趁机狠狠推进;
- Decay / cooldown——梯度均值很小但噪声不变,把 $\eta$ 降下来精修。
将常见调度绘制在同一张图上,差异一目了然:

每条曲线分别适合什么场景,第五节会逐一拆解。
batch size、动量、权重衰减:藏起来的耦合#
学习率从来不是孤立的超参数。下面三个朋友一直跟着它跑。
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$ 是绑在一起的。

左图:经验上,线性规则 $\eta \propto B$ 在达到一个临界 batch size 之前都能在几个百分点以内成立,超过该点后开始走平——再加 batch 不会多出 LR 余量。右图:梯度标准误差以 $1/\sqrt B$ 衰减,这正是“大 batch 能承受大步长”背后的原因。
动量:藏在背后的 LR 放大器#
$$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 的一阶矩本质上是同样的事情。
权重衰减:耦合得很紧的正则化#
$$\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 就是装了一柜子小锤的工具箱——每个参数都有自己的步长。
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 才能勉强跟上的原因。
为什么 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%。

不加 warmup 的崩坏样子很可观:前 30 步左右梯度范数冲出 clip 阈值很高,损失出现明显隐凸,之后的训练也几乎追不上加了 warmup 的曲线。几百步的 warmup 往往就是“能收敛”与“发散或卡住”的分界。
调度大全:从老办法到大模型默认#
上面那张图把四个最常用的家族画在了一起,下面看每条线分别适合什么场景。
常数 LR#
简单。基本上永远是错的——不是早期太慢,就是后期太抖,没有两全。
阶梯衰减#
到达指定 milestone 时把 $\eta$ 乘以 $\gamma$ (通常 0.1)。经典 ResNet 配方就用这个。优点:实现简单、手工调参直观。缺点:突然的下台阶可能让 weight decay 或 BN 敏感的网络出现 loss spike。
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$ 决定。想延长训练?整条曲线得重做。
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 圈成为默认有三个理由:
- 可续训、可扩展: 想多跑 2× tokens?继续 stable 阶段,再 cooldown 即可。Cosine 没法在不重新拟合曲线的情况下做到这点。
- “cooldown 最后一跳”现象。 经验上 cooldown 一开始 loss 就会出现一次明显下降——好像模型一直被“按着”,到此终于被允许精细贴合。
- 理论支持。 Schaipp et al. 2025(The surprising agreement between convex optimization theory and learning-rate scheduling,arXiv:2501.18965 )证明 cooldown 形状刚好对上凸优化里一个紧的界,cooldown 这一段在界里对应的是“去掉对数项”。
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)提出:
- 把 $\eta$ 设成 $\eta_{\min} \approx 10^{-7}$ ;
- 每个 mini-batch 之后把 $\eta$ 乘以一个固定因子(如 1.1),让它指数增长;
- loss 开始上升就停;
- 把 loss 对 $\log\eta$ 画图。
你会看到四个阶段:噪声平台 → 下降段 → 噪声最低点 → 爆炸。“边界”就在爆炸前那一点;正式训练的峰值 LR 取在 $[0.3 \times, 1.0 \times]$ 这个边界之间。

| |
工程实现上更稳的做法是给 loss 加一个指数滑动平均,并且在 loss 超过历史最低值 $4\times$
时自动停止——fastai 里 lr_find() 就是这么写的。
不同优化器,曲线长得不一样#
同一条调度套到不同优化器上,得到的 loss 曲线并不一样。下图把同一条 warmup-cosine 调度同时应用到 AdamW 和 SGD-with-momentum 的合成任务上:AdamW 早期下降更快,SGD 往往后段才追上来,且对峰值 LR 更敏感。

十年配方浓缩成几条经验:
- 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)。

最小可用的 PyTorch 实现:
| |
LLM 微调里同样的思路换了几张皮:
- LoRA / adapter——只训练一小撮新参数,LR 给满;其余冻住。
- LLaMA-Adapter 风格——逐渐解冻,被解冻部分用更小的 LR。
Schedule-free 与 learning-rate-free#
调度本身、甚至学习率这个标量,原则上都可以被消掉。最近两条研究路线在做这件事。
D-Adaptation(Defazio & Mishchenko, 2023)#
D-Adaptation 在训练过程中估计“当前点到最优点的距离”,再用这个距离反推步长。没有 $\eta$ 可调。在很多任务上能在几个百分点内追平手调的基线。
无调度 AdamW(Defazio 等, 2024,arXiv:2405.15682 )#
它把 iterate averaging 和一个常数基础 LR 结合起来,得到“看起来像 cosine 衰减过”的轨迹,但全程并不显式地降 $\eta$ 。这意味着你不需要事先承诺训练总步数 $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}$ 。

公开论文里的具体数字:
| 模型 | 峰值 LR | 最小 LR | Warmup | 调度 | Batch (tokens) |
|---|---|---|---|---|---|
| GPT-3 175B(Brown et al., 2020) | 0.6e-4 | 0.6e-5 | 375M tokens | cosine | 3.2M |
| LLaMA-7B(Touvron et al., 2023) | 3e-4 | 3e-5 | 2 000 步 | cosine | 4M |
| LLaMA-65B | 1.5e-4 | 1.5e-5 | 2 000 步 | cosine | 4M |
| Chinchilla 70B(Hoffmann et al., 2022) | 1e-4 | 1e-5 | 1 875 步 | cosine | 1.5M–3M |
| MiniCPM(Hu et al., 2024) | 1e-2 | 1e-3 | 2% 步数 | WSD | 视情况 |
几个几乎是常识但容易忽略的点:
- 最小 LR ≈ 峰值 LR 的 10% 是事实标准,不是 0。一退到 0 经常意味着最后几千步等于白跑。
- 梯度裁剪到 1.0 在这一规模几乎是必备的;不裁的话,偶尔一个坏 batch 就能把你推下悬崖。
- weight decay = 0.1(decoupled,AdamW 风格)也是 LLM 配方里的常见默认——比视觉里的 1e-4 要大得多。
从“能跑”到“跑得好”:可操作的工作流#
Step 1 —— 先判断失败的类型#
训练失败有三种典型形态:
| 症状 | 大概率原因 |
|---|---|
| 几步内 loss → NaN/Inf | LR 太大;缺 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 大变,就说明你已经贴在稳定边界上了,留点余量。
故障排除检查表#
Loss 一开始就炸(NaN / Inf)#
按优先级排:
- 把峰值 LR 降一个数量级(如
3e-4 → 3e-5); - 加上或延长 warmup(如从 0 → 5% 步数);
- 加梯度裁剪:
torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0); - 检查混合精度:fp16 是否在用
GradScaler,或者切到bf16; - 加大 weight decay(尤其是 LLM)。
Loss 下降太慢#
常见原因:
- LR 太小(先做一次 LR range test);
- 调度衰得太快(用 WSD 拉长 stable 阶段);
- batch 太小、噪声太大(增大 batch 或用 gradient accumulation);
- 数据/标签有问题(这不是 LR 能救的,先查流水线)。
Loss 大幅震荡#
- 把峰值 LR 降 10–30%;
- 减小动量($\beta = 0.9 \to 0.85$ ,或 Adam 的 $\beta_1 = 0.9 \to 0.85$ );
- 加梯度裁剪;
- 检查优化器和归一化的搭配(AdamW + LayerNorm 很稳;SGD + BatchNorm 在大 LR 下脆弱)。
验证 loss 偏离训练 loss#
这是过拟合,不直接是 LR 问题,但 LR 影响隐式正则:
- 加大 weight decay;
- 把峰值 LR 略降(更慢的训练通常泛化更好);
- 加 dropout、label smoothing、数据增强;
- 配 patience 5–10 的 early stopping。
参考实现#
预热 + 余弦#
把这两段话先念清楚:cosine 调度让学习率沿着半个余弦周期从峰值滑到谷底,公式是 $\eta(t) = \eta_{\min} + \tfrac{1}{2}(\eta_{\max} - \eta_{\min})\bigl(1 + \cos(\pi t/T)\bigr)$ ,前半段几乎不掉、后半段加速衰减——这正是大多数任务想要的:先充分探索,再老老实实退火收敛。线性退火 $\eta(t) = \eta_{\max}(1 - t/T)$ 看上去更朴实,但在我自己的实验里同样的总步数下 cosine 的最终 loss 几乎总是更低,原因是它把“低学习率”的尾段拉得更长。阶梯衰减 $\eta_k = \eta_0 \cdot \gamma^{\lfloor t/s \rfloor}$ 是远古时代留下来的写法,现在只有在我明确知道训练动力学有“分阶段”特征(比如 ResNet on ImageNet 那种)时才会用。
warmup 这一段我习惯写得很死板:从 $\eta_0 = 10^{-7}$
起步线性涨到峰值 $\eta_{\max}$
。比方说我设 1000 步 warmup、峰值 $1\times 10^{-4}$
,那么第 1 步是 $1\times 10^{-7}$
,第 500 步大约 $5\times 10^{-5}$
,第 1000 步正好打到 $1\times 10^{-4}$
。这一段从直觉上看是“保护脆弱的早期统计量”,但更深层的理由(Kalra 2024)是它压住了预条件 Hessian 的最大特征值,让一个原本会炸的峰值 LR 变得可持续。下面是我用了好几个项目的实现版本,调度逻辑全在 lr_warmup_cosine 一个函数里。
| |
预热 + 稳定 + 衰减 (WSD)#
| |
接到训练循环里#
调度函数写好之后,剩下的事其实只有一件:每个 step 拿到 lr 之后,把 optimizer.param_groups 里所有组的 "lr" 字段改写一遍,然后照常 loss.backward()、optimizer.step()。这里有几个我踩过的坑想先说在前头。第一,lr 必须每步刷新,不要图省事写成“epoch 末尾改一次”——cosine 在每一步的曲率不同,间隔太大会让损失曲线出现可见的阶梯。第二,optimizer.zero_grad(set_to_none=True) 比 zero_grad() 更省内存、也更快,老代码里如果还没改过来值得顺手改掉。第三,梯度裁剪 clip_grad_norm_ 几乎是 LLM 训练的必备项,写在 backward 和 step 之间,max_norm=1.0 是默认起点。
我喜欢把“调度函数”和“训练循环”彻底解耦:训练循环只负责接收一个 schedule_fn(step, total_steps) -> lr,至于这个函数内部是 cosine 还是 WSD、是否带 warmup,跟训练循环无关。这样换调度策略只需要换一个 lambda,不必动循环本身。下面这段就是我最近一个项目里直接复制粘贴在用的版本。
| |
典型配置:
| |
2023 年以来的新进展#
下面五条线值得跟踪。
D-Adaptation —— 无学习率(2023)#
思路:在训练过程中估计“当前点到最优点的距离”,再用这个估计推算步长。没有可调的 $\eta$ 。原型迭代和 grid search 收敛阶段非常有用。
参考:Learning-Rate-Free Learning by D-Adaptation (Defazio & Mishchenko, 2023) 。
无调度 AdamW(2024)#
把 iterate averaging 和常数基础 LR 结合起来,达到与有调度方法相当的性能,却不需要显式衰减——更不需要事先承诺总步数 $T$ 。
参考:Schedule-Free AdamW (Defazio et al., 2024, arXiv:2405.15682) 。
Warmup 为什么“真的”有效(2024)#
老解释——“等 Adam 统计量稳定下来”——并不完整。Kalra et al. 2024 证明 warmup 实际上降低了预条件化 Hessian 的最大特征值,从而让一个更大的可持续峰值 LR 变得安全。
参考:Why Warmup the Learning Rate? (Kalra et al., 2024, arXiv:2406.09405) 。
Power Scheduler —— 对 batch / token 不敏感(2024)#
换 batch、换训练 token 数,最优 LR 都会漂。Power Scheduler 利用 LR、batch、token 之间的幂律关系,给出一种在不同规模间可迁移的调度。
用小模型复现 LLM 不稳定(2023–2024)#
很多“只有 LLM 才会出现”的 loss spike,把小模型的 LR 调高就能复现。这意味着你可以用 1/100 的成本调研真实的不稳定性。
Cosine ↔ WSD 的凸优化桥梁(2025)#
Schaipp et al. 2025(arXiv:2501.18965 )证明 WSD 的 cooldown 形状和某个紧的凸优化界完全对应,cooldown 这一段在界里负责“消去对数项”。这给“为什么 cooldown 有用”提供了一个有原则的解释。
一页速查表#
AdamW 默认配方#
下面这份配方是我把过去两年用 AdamW 训练 vision、NLP、LLM 的经验压缩成的“无脑挡”——拿来当起点几乎不会出大错。具体每一项都还是要根据任务微调,但顺序我建议照着走:先固定 schedule 的形状、再定 warmup 长度、再决定 cooldown,最后才动峰值 LR。我观察过一个常见错误是初学者一上来就盯着峰值 LR 调,调了三五次还看不出规律,根本原因是底下的 schedule 形状没固定、变量太多。把 schedule 当作几何形状先画出来,再把峰值当成一个标量乘子去调,效率会高得多。
另一件事:weight decay 视觉任务我用 0.01,LLM 用 0.1,差一个量级。这不是因为 LLM 本身需要更强的正则——而是因为 AdamW 里 decoupled weight decay 实际作用强度跟 $\eta$ 成反比,LLM 的峰值 LR 比 vision 小 10 倍左右,所以名义值要拉高 10 倍才能维持同样的有效正则强度。把这条记牢可以省下很多盲目调参。
- 调度: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。
- 从零训练 Transformer:
监测三个信号(比看 loss 更靠谱)#
只盯 loss 曲线是新手最容易犯的毛病。loss 是滞后指标,等它出问题往往已经过了好几百步,而早期信号其实埋在三个量里。我现在每个项目第一天搭训练循环时,都会顺手把这三个量打到 wandb 或者 tensorboard 上,几乎不花时间,但救过我无数次。
第一个是梯度模长 $\|g\|$ 。warmup 结束后它应该稳定在某个范围内,几个小波动正常,但如果突然飙升一两个量级,就是马上要 NaN 的预警——这时候立刻降 LR 通常还来得及。第二个是参数相对变化率 $\|\Delta\theta\| / \|\theta\|$ ,稳态训练时大约在 $10^{-3}$ 量级;如果远超这个值,说明步子迈得太大,反过来如果远小于(比如 $10^{-5}$ ),说明根本没在学。第三个是 LR 敏感度——把 LR 改 ±20% 重跑一小段,如果最终 loss 变化明显,说明你已经踩在稳定边界上,再往上就会炸。这三个量加起来比单看 loss 更能早预警,也更能告诉我“现在到底是 LR 太大、太小、还是正合适”。
- 梯度模长——warmup 之后应当平稳;飙升 = 麻烦;
- $\|\Delta\theta\| / \|\theta\|$ ——稳态大约 $10^{-3}$ ;
- LR 敏感度——小变动就能影响最终 loss = 你贴着边界。
快速分诊表#
下面这张表是我自己常年贴在工位边上的版本——出现某个症状时第一步该怎么动、第二步该怎么动,写成肌肉记忆。它不能替代你对系统的理解,但能省掉“看到 NaN 之后慌乱地把所有超参数都改一遍”那种灾难性操作。这里特别想多说一句关于“早期 NaN”的:很多初学者一遇到 NaN 就把 LR 砍到 1/100,其实大多数时候只要砍 10 倍 + 加 warmup 就够了,砍太狠会让训练慢得看不出收敛趋势,反而会怀疑模型本身有问题。
还有一个反直觉的认知:初学者常以为学习率越小越好,反正“慢一点总比炸了好”。但实际上,过小的 LR 不只是慢——它会把模型困在初始化附近的烂局部解里,loss 曲线看上去“在下降”,可降到一定程度就再也不动了,最终 loss 比恰当 LR 高一截。我见过的最糟糕的案例是某个同事把 LR 设得比经验值小 50 倍,跑了两周才发现 loss 卡在 plateau,重新跑一次只用了三天就到了更好的点。所以下面这张表里“下降缓慢”那一行的第一动作永远是 LR range test,不是“再降 LR”。
| 症状 | 第一步 | 第二步 |
|---|---|---|
| 早期 NaN / Inf | 降 LR 10× | 加 warmup;裁剪到 1.0 |
| 下降缓慢 | LR range test | 拉长 stable(WSD) |
| 大幅震荡 | 降 LR 或动量 | 加裁剪 |
| 训练-验证差距大 | 加 weight decay | 略降 LR |
总结#
- 跑一次 LR range test,找到稳定边界;
- 峰值 LR 取边界的 0.3–1×;
- 加 warmup——视觉 1–5%,LLM 5–10%;
- 选调度——预算固定用 cosine,可续训 LLM 用 WSD,预算未知用 schedule-free;
- 联动调 batch、weight decay、梯度裁剪。永远不要孤立地调 LR。
如果只能记一句话:绝大多数被甩锅给“优化器”的训练问题其实是 LR 调度问题,而绝大多数 LR 调度问题,一个下午、一次 LR range test、一段 warmup 就能解决。
接下来#
这篇里讲到的工具——LR range test、warmup、cosine、WSD、三个监控信号——之后的几篇会被当作黑盒反复用到。如果某个概念你现在读着还有点滑、抓不住,不用强求一次理解透;标记一下回头再来看,这些想法会在整个 series 里反复出现,第二、第三遍碰到时往往会突然通了。我自己当年学的时候,cosine 这一段也是过了大半年才真的“看懂”——看懂的瞬间不是因为又读了一遍论文,而是因为某次训练失败之后画了张 LR vs loss 图,突然明白“这个形状就是为退火设计的”。
如果你想立刻把今天的内容用起来,最高 ROI 的练习是这个:找一个你已经训练过、对结果有大致预期的任务(哪怕是 MNIST 上的小 MLP),把它跑一次完整的 LR range test,然后用得到的边界值反过来检查你之前用的峰值 LR——绝大多数人会发现自己一直在远离最优区间的位置训练。这种“事后才看清”的练习比再读两篇论文有用得多,因为它直接把抽象概念绑定到你自己的训练曲线上。下一篇文章会建立在这些工具之上继续推进,所以现在让“做 LR range test”变成肌肉记忆,是非常划算的投资。
参考文献#
- Learning-Rate-Free Learning by D-Adaptation (2023)
- Schedule-Free AdamW (2024)
- Why Warmup the Learning Rate? (2024)
- Power Scheduler (2024)
- Small-scale proxies for large-scale Transformer instabilities (2023)
- Convex theory view of WSD cooldown (2025)
- Cyclical Learning Rates for Training Neural Networks (Smith, 2015)
- Accurate, Large Minibatch SGD: Training ImageNet in 1 Hour (Goyal et al., 2017)
- Edge of Stability (Cohen et al., 2021)