想象你第一天学开车。教练绝不会让你一上车就猛踩油门冲上高速。你得先在空场地里低速绕圈,熟悉方向盘手感、刹车距离,等肌肉记住了基本操作,才慢慢提速上公路,最后才能平稳地巡航在高速上。深度学习训练里的 Warmup(学习率预热) 就是同一个道理:训练刚开始时,模型就像一个刚摸方向盘的新手,什么都不懂。如果此时直接给它一个很大的学习率(相当于猛踩油门),它很容易“开沟里”——损失值剧烈震荡甚至变成 NaN(梯度爆炸)。所以聪明的做法是:前几百步只给很小的学习率,让模型慢慢“找感觉”,再逐步把学习率升到正常水平,然后才开始衰减。这就是 Warmup 存在的意义:训练初期,慢就是快。

岗位关联

理解 Warmup 能让你在训练 Transformer、BERT 等大模型时少踩梯度爆炸的坑,训练损失曲线更平滑,模型收敛更稳定——这是从“调参直觉”走向“训练工程”的必备技能。

目录
  1. 可视化演示
  2. 什么是Warmup
  3. 为什么要预热
  4. 线性Warmup
  5. 余弦Warmup
  6. 参数怎么设
  7. 实战与坑
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

展示线性与余弦Warmup学习率曲线、有无Warmup的训练loss对比和不同模型类型的Warmup配置。切换模式探索训练稳定性优化。

本节配有交互动效(进入视口后自动加载,约 3KB)。

线性与余弦Warmup学习率曲线 线性Warmup:学习率从0线性增至峰值,实现简单效果稳定 余弦Warmup:学习率按余弦曲线平滑上升,过渡更自然 lr = peak_lr * min(1, step / warmup_steps) Warmup是训练稳定性的基础保障

什么是Warmup

还是说学车。教练给你的第一个指令是:“绕着广场转圈,时速 20 就行。”你不会一辈子开 20,但前半小时必须开 20。深度学习里的 Warmup 就是这个“先开 20 迈”的阶段:训练的最初几百步,学习率被压得很低,然后才慢慢升到预设的峰值,再开始衰减。所以 Warmup 不是一个独立的算法,而是学习率调度器的一部分——它决定了训练每个阶段用多大的学习率前进。

在 PyTorch 里,Warmup 通常以 LambdaLR 或 OneCycleLR 的形式出现。它的核心逻辑可以用一个分段函数描述:

  • 预热段(训练步数 $t$ 从 0 到 $T_{warm}$):学习率从 $\eta_{min}$ 线性或非线性地升到峰值 $\eta_{max}$。
  • 衰减段($t$ 从 $T_{warm}$ 到总步数 $T$):学习率按照既定策略从峰值降到接近 0。

这两个阶段合在一起,才是一条完整的 “先升后降” 学习率曲线。

这一段公式真正要传达的信息是:Warmup 只是一个“升速器”,真正决定训练后半程命运的是衰减策略。教练说“先开 20 迈”不是让你一直开 20,而是为后面上高速做准备。

ηt={ηmin+tTwarm⋅(ηmax−ηmin),0≤t<Twarm衰减策略(t),Twarm≤t≤T\eta_{t} =\begin{cases}\eta_{\text{min}} + \dfrac{t}{T_{\text{warm}}} \cdot (\eta_{\text{max}} - \eta_{\text{min}}), & 0 \le t < T_{\text{warm}} \\[8pt]\text{衰减策略}(t), & T_{\text{warm}} \le t \le T\end{cases}
这个公式就是 Warmup 的“施工蓝图”:前半段用比例系数决定学习率升多快,后半段交给衰减策略决定怎么降。
  1. 预热段学习率当训练步数 $t$ 还没达到预热步数 $T_{\text{warm}}$ 时,学习率从最小值 $\eta_{\text{min}}$ 开始爬升。
    ηt=ηmin+tTwarm⋅(ηmax−ηmin)\eta_{t} = \eta_{\text{min}} + \frac{t}{T_{\text{warm}}} \cdot (\eta_{\text{max}} - \eta_{\text{min}})
  2. 比例系数$\dfrac{t}{T_{\text{warm}}}$ 表示训练进度,当 $t=0$ 时系数为 0,当 $t=T_{\text{warm}}$ 时系数为 1,学习率刚好到达峰值。
    tTwarm\frac{t}{T_{\text{warm}}}
  3. 衰减段预热结束后,学习率交给衰减策略按总步数 $T$ 逐步降低,直到训练结束。
    衰减策略(t),Twarm≤t≤T\text{衰减策略}(t), \quad T_{\text{warm}} \le t \le T

为什么要预热

新手最怕什么?不是开得慢,而是开得快。速度一上来,遇到突发情况就手忙脚乱,方向盘一打,车子直接失控。模型也一样。刚初始化的神经网络,权重都是随机数,参数分布完全没规律。此时如果学习率太大,每个参数的更新步长都很大,梯度信号就像脱缰的野马——可能跑向完全错误的方向,损失值剧烈震荡,甚至梯度爆炸到 NaN。

还有一个更隐蔽的问题叫“提前拟合坏方向”。训练早期,模型对数据的判断完全是盲目的。如果给它大学习率,它会狠狠记住初始几步碰巧遇到的错误规律,后面再想纠正就难了。这就是为什么训练初期要用小学习率:让模型先“看清楚”数据的大致分布,再开始大步优化。

损失函数的图像是一座山谷,模型要从山顶滑到谷底。预热期是让你先站在山顶环顾四周,把地形看清楚;没有预热直接大学习率,相当于蒙着眼往山下跳——可能直接跳过山谷摔到对面的山上。

所以,预热期用小学习率,本质是把 $\eta_t$ 压小,让二阶项这个“搅局者”没机会发力。等模型走到地形平缓的区域,再加大步伐冲刺。

L(θt+1)≈L(θt)+ηt ∇L(θt)⋅g+ηt22 gTHgL(\theta_{t+1}) \approx L(\theta_t) + \eta_t \, \nabla L(\theta_t) \cdot g + \frac{\eta_t^2}{2} \, g^T H g
这个二阶展开式说明:损失变化不只受梯度 $g$ 影响,还受曲率 $H$ 影响。当初始参数处于高曲率区域(地形陡峭)时,$\eta_t$ 稍微大一点,损失就会剧烈上升——这就是预热存在的数学理由。
  1. 损失变化展开把损失函数在参数 $\theta_t$ 附近做二阶泰勒展开,近似估计下一步损失会变成多少。
    L(θt+1)≈L(θt)+ηt ∇L(θt)⋅gL(\theta_{t+1}) \approx L(\theta_t) + \eta_t \, \nabla L(\theta_t) \cdot g
  2. 一阶项$\eta_t \nabla L(\theta_t) \cdot g$ 是梯度下降的“常规操作”,只要顺着梯度反方向走,损失就会下降。
    ηt ∇L(θt)⋅g\eta_t \, \nabla L(\theta_t) \cdot g
  3. 二阶项$\dfrac{\eta_t^2}{2} g^T H g$ 是曲率修正项。如果地形(Hessian 矩阵 $H$)崎岖不平,这一项会让损失不降反升。
    ηt22 gTHg\frac{\eta_t^2}{2} \, g^T H g

线性Warmup

线性 Warmup 是最朴素的预热方式:学习率从 0(或一个极小值)出发,每一步增加固定的量,匀速上升到峰值。就像学车时的“每十分钟加 5 迈”——节奏均匀,容易掌握。

它的公式很简单,就是前面分段函数里预热段公式:

在 PyTorch 中,实现代码长这样:

这个策略的好处是行为可预测:你清楚每一步学习率是多少,调试方便。坏处是结束预热那一刻,学习率曲线有一个“折角”,从上升突然切换成衰减,如果衰减策略不匹配,这个折角可能引起损失一个小抖动。不过对于中小规模模型,线性 Warmup 完全够用,大多数情况下你已经看不到这个抖动对最终精度的影响。

直线加速的优点是直观,缺点是太“生硬”。就像学车时教练说“上 60 迈”,你一脚油门直接踩到 60,车身会顿一下。对于追求极致训练曲线的人来说,这个“顿”也想省掉——这就有了下一种更平滑的策略。

ηt=ηmin+tTwarm⋅(ηmax−ηmin)\eta_t = \eta_{\text{min}} + \frac{t}{T_{\text{warm}}} \cdot (\eta_{\text{max}} - \eta_{\text{min}})
python5 行
def linear_warmup(step, warmup_steps, peak_lr):    if step < warmup_steps:        return (step + 1) / warmup_steps * peak_lr    else:        return peak_lr

余弦Warmup

余弦 Warmup 是当下大模型训练的主流选择。它分两段:预热段先把学习率升到峰值,衰减段然后用余弦函数从峰值平滑地降到接近 0。相比线性升温+阶梯/指数衰减,余弦衰减的局部是一段“平缓的坡”,而不是突然的台阶,模型在最优参数附近能停留更久,从而有时间把参数磨得更精细——就像高速上从 120 迈慢慢滑行到服务区,而不是一脚急刹车。

完整公式如下:

BERT、GPT 等 Transformer 大模型几乎都把余弦 Warmup 作为默认配置。因为大模型参数多、地形复杂,任何“急转弯”都可能让训练误入歧途。用余弦曲线把所有转折都磨成圆弧,是最稳妥的做法。

ηt={ηmin+(1−cos⁡(πtTwarm))⋅ηmax−ηmin2,0≤t<Twarmηmin+12(ηmax−ηmin)(1+cos⁡(π(t−Twarm)T−Twarm)),Twarm≤t≤T\eta_t =\begin{cases}\eta_{\text{min}} + (1 - \cos(\dfrac{\pi t}{T_{\text{warm}}})) \cdot \dfrac{\eta_{\text{max}} - \eta_{\text{min}}}{2}, & 0 \le t < T_{\text{warm}} \\[10pt]\eta_{\text{min}} + \dfrac{1}{2}(\eta_{\text{max}} - \eta_{\text{min}})\left(1 + \cos(\dfrac{\pi (t - T_{\text{warm}})}{T - T_{\text{warm}}})\right), & T_{\text{warm}} \le t \le T\end{cases}
前半段是“升余弦”,学习率平滑爬坡;后半段是“降余弦”,学习率平滑下滑。整个训练过程没有锐角,损失曲线因此更丝滑。
  1. 预热升余弦训练步数 $t$ 从 0 走向 $T_{\text{warm}}$ 时,$\cos(\dfrac{\pi t}{T_{\text{warm}}})$ 从 1 走到 -1,学习率从 0 平滑升到峰值。
    ηmin+(1−cos⁡(πtTwarm))⋅ηmax−ηmin2\eta_{\text{min}} + (1 - \cos(\frac{\pi t}{T_{\text{warm}}})) \cdot \frac{\eta_{\text{max}} - \eta_{\text{min}}}{2}
  2. 升余弦因子$1 - \cos(\pi t/T_{\text{warm}})$ 恒为非负,除以 2 后取值范围是 0 到 1,恰好充当“进度条”。
    1−cos⁡(πtTwarm)1 - \cos(\frac{\pi t}{T_{\text{warm}}})
  3. 衰减降余弦$t$ 从 $T_{\text{warm}}$ 走向 $T$ 时,余弦从 1 滑到 -1,学习率从峰值平滑走向最小值。
    ηmin+12(ηmax−ηmin)(1+cos⁡(π(t−Twarm)T−Twarm))\eta_{\text{min}} + \frac{1}{2}(\eta_{\text{max}} - \eta_{\text{min}})(1 + \cos(\frac{\pi (t - T_{\text{warm}})}{T - T_{\text{warm}}}))

参数怎么设

教练说“先开 20 迈”,你问“开多久?”这就是热身步数 $T_{\text{warm}}$ 的问题。设短了,还没找到手感就上高速,危机四伏;设长了,一直在广场转圈,浪费宝贵时间。实践中 $T_{\text{warm}}$ 一般取总训练步数的 5% 到 10%。

具体来说,如果总步数 10 万步,预热 5000 到 10000 步;如果总步数 1000 步(小数据集),预热 50 到 100 步。一个常用直觉:模型越大、batch 越大,预热步数占比越高——因为大模型更需要“看清楚地形再跑”。

峰值学习率 $\eta_{\text{max}}$ 怎么定?一个标准做法是:先假设没有 Warmup,用常规方法找到一个能收敛的较大学习率,把它作为峰值;然后套上 Warmup,让模型在预热期“缓冲”到这个峰值。另外别忘了设置 $\eta_{\text{min}}$(最低学习率),通常取峰值的 1% 到 5%,避免最后阶段学习率彻底归零导致无法精细调整。

参数设置的本质是把握一个节奏感:起步多慢、加速多快、巡航多久、刹车多缓。这四个问题对应了预热步数、峰值学习率、衰减策略、最低学习率。初学者最容易犯的错是只关心峰值不关心比例,结果预热太短等于没预热,预热太长训练效率大幅下降。

实战与坑

看一个真实的例子。BERT 原始论文在预训练时用了 10000 步的 Warmup,配合峰值学习率 $1e-4$ 的 Adam 优化器。为什么是 10000?因为 BERT 的预训练总步数约 100 万步,10% 的预热比例是当时经过验证的“安全区间”。

但 Warmup 并不是越多越好。有过这样的失败案例:某工程师把 Warmup 设成总步数的 50%,结果损失确实不爆了,但训练进度也几乎停滞了——模型在热身区转圈的时间太长,最终精度反而不如不预热直接快速收敛的版本。这就像教练让你在广场上绕了整整一天,你真正上路练习的时间所剩无几。

还有一个常见的纠结:Warmup 是否必须从 0 开始?其实不需要。很多实践中 $\eta_{\text{min}}$ 设成峰值的 1%~5% 就足够了,从 0 开始会让前期几百步几乎没有学习进度。特别是你想用 0 然后瞬间跳到峰值,这反而人为制造了一个“断崖”。

总结成一句话:Warmup 是为了稳定而做的让步,不是训练目标本身。 用 5~10% 的步数做热身,让模型避开初始的高风险区,然后放心大胆地冲——这才是预热的正确姿势。

AI 应用场景

大语言模型预训练

阶段:模型训练与调优

解决的问题:预训练语言模型(如 BERT、GPT)动辄数十亿参数,随机初始化后参数分布不稳定。直接用大学习率训练,经常在几万步内碰到梯度爆炸导致 loss 变成 NaN,整个训练任务白跑。加入 Warmup 后,前 1~2 万步用小学习率稳定参数分布,再逐步升到峰值,训练一次性跑通。

具体案例:某团队训练 13B 参数的对话模型,初始用 $3e-4$ 学习率直接训练,在第 8000 步 loss 突变为 NaN。后将前 1 万步设为线性 Warmup,峰值学习率不变,loss 曲线全程平稳,训练顺利完成。

计算机视觉模型微调

阶段:迁移学习与微调

解决的问题:用 ImageNet 预训练权重微调下游任务时,分类头是随机初始化的,而骨干网络已经成熟。如果学习率太大,新初始化的分类头会产生巨大梯度,把预训练权重也带偏。Warmup 让分类头先快速适应,再用稳定大学习率微调整个网络。

具体案例:某安防公司的目标检测模型微调时,在检测头新增 3 个类别。设置 500 步线性 Warmup 后,mAP 从 58.2% 提升到 62.7%,且训练过程无震荡。

Python 演示

python41 行
import mathimport random  def train_one_step(model_params, grads, lr):    for i in range(len(model_params)):        model_params[i] -= lr * grads[i]    return model_params  def cosine_lr(step, warmup_steps, total_steps, peak_lr, min_lr):    if step < warmup_steps:        # 线性预热:从 min_lr 爬到 peak_lr        return min_lr + (peak_lr - min_lr) * (step + 1) / warmup_steps    # 余弦衰减:从 peak_lr 降到 min_lr    progress = (step - warmup_steps) / max(1, total_steps - warmup_steps)    return min_lr + 0.5 * (peak_lr - min_lr) * (1 + math.cos(math.pi * progress))  def simulate(warmup_steps, total_steps, peak_lr):    loss = 10.0    best = loss    record = []    for step in range(total_steps):        lr = cosine_lr(step, warmup_steps, total_steps, peak_lr, 0.01)        # 模拟带噪声的梯度:噪声幅度与 lr 正相关        grad = math.sqrt(loss) * 0.5 + random.uniform(-0.6, 0.6) * lr * 10        loss -= lr * grad        loss = max(loss, 0.1)        best = min(best, loss)        record.append((step, lr, loss))    return record, best  if __name__ == "__main__":    random.seed(42)    total = 2000    for warm in [0, 100, 200]:        history, best = simulate(warm, total, 0.1)        final = history[-1][2]        print(f"warmup={warm:3d}  best_loss={best:.4f}  final_loss={final:.4f}")
目的:用模拟梯度下降对比不同预热步数对训练稳定性和最终损失的影响,直观理解 Warmup 的价值。
  1. def cosine_lr(step, warmup_steps, total_steps, peak_lr, min_lr)核心调度函数,先升后降,返回第 step 步该用的学习率。
  2. return min_lr + (peak_lr - min_lr) * (step + 1) / warmup_steps线性预热公式,步数越多学习率越高。
  3. min_lr + 0.5 * (peak_lr - min_lr) * (1 + math.cos(...))余弦衰减公式,输出从 1 平滑滑向 0。
  4. grad = math.sqrt(loss) * 0.5 + random.uniform(-0.6, 0.6) * lr * 10学术上的噪声模拟,学习率越大梯度噪声越大,大学习率天然更容易震荡。
  5. loss -= lr * grad模拟参数更新的效果,学习率太小则收敛慢。
  6. for warm in [0, 100, 200]对比 0 预热、5% 预热、10% 预热三种配置,观察 best_loss 的差异。

常见误区

误区加了 Warmup 后,前面几千步学习率那么低,模型几乎学不到东西,纯属浪费时间,为什么不直接用大学习率开始?

正解Warmup 表面上是“浪费时间”,实则避免了梯度爆炸导致的训练中断。一次 NaN 崩溃就可能浪费几小时甚至几天。更重要的是,预热期虽然学习率小,但模型在这个阶段把参数分布调整到了“适合大步更新”的状态,后续训练每一步的质量更高,整体收敛速度反而更快。这就像学车时先花半小时低速绕圈,比直接上高速然后翻车快得多。

为何常见:人们习惯用“每步更新量”来评估效率,忽略了无效更新甚至破坏性更新的存在。

误区Warmup 的意思就是“学习率从 0 慢慢加”,所以 $\eta_{\text{min}}$ 必须设成 0,否则就不叫预热。

正解从 0 开始既无必要也可能有害。学习率为 0 意味着权重完全不动,浪费训练资源;而从 0 到峰值的“陡坡”又会引入人为的不连续。实践中 $\eta_{\text{min}}$ 通常设成峰值的 1%~5%,让模型在预热初期仍有微弱的更新能力。这就像热身不是“完全静止”,而是“小幅活动”。

为何常见:很多教程配图都画出从 0 出发的曲线,给读者留下错误印象。

误区既然梯度爆炸风险来自高学习率,那把预热期拉长,让学习率更慢地上涨,训练一定更稳定、效果更好。

正解预热过长会导致训练后期步数不足,模型在接近最优的区域来不及精细调优,最终精度反而下降。预热步数是“稳定”和“效率”的权衡,5%~10% 是大量实验验证的合理区间。就像热身跑 10 分钟有益,跑 2 小时就是透支体力。

为何常见:把“防止梯度爆炸”当成了 Warmup 的唯一目标,忽略了训练效率。

误区小模型或 CNN 模型训练很稳定,不需要 Warmup,这是大模型的专利。

正解Warmup 对任何有大规模随机初始化的模型都有价值。实践中 CNN 在 ImageNet 上训练也常加 5 个 epoch 的线性预热;目标检测、GAN 训练也普遍使用。只不过模型越小、数据越简单,不加 Warmup 的负面影响越小,所以看起来“不需要”。本质上,只要算力允许,加上 Warmup 几乎总能带来更平滑的训练曲线。

为何常见:小模型训练时即使不预热也很少直接崩溃,让从业者误以为 Warmup 无关紧要。

面试题

Q1. Warmup 阶段学习率的变化趋势是什么?

单选题 · easy

  • A.从低到高逐渐爬升← 正确答案
  • B.从高到低逐渐降低
  • C.一直保持固定值
  • D.随机的上下波动

答案:A。Warmup 的“预热”含义就是训练初期学习率从较小值逐步上升到峰值,对应选项 A。选项 B 是衰减策略,C 是固定学习率,D 是退化配置。

Q2. 下列哪项是训练开始时使用大学习率最直接的风险?

单选题 · easy

  • A.模型过拟合
  • B.梯度爆炸或发散← 正确答案
  • C.数据增强失效
  • D.显存不足

答案:B。初始参数随机分布不稳定,大学习率会让梯度信号失控,导致 loss 震荡甚至变成 NaN,这就是梯度爆炸/发散。过拟合是训练后期问题,和数据增强、显存无关。

Q3. 假设总训练步数为 100000,预热步数取多少最合理?

单选题 · mid

  • A.0 步
  • B.500 步
  • C.6000 步← 正确答案
  • D.95000 步

答案:C。预热步数通常取总步数的 5%~10%,100000 的 5%~10% 是 5000~10000 步,选项 C 的 6000 落在此区间。0 步等于没预热,95000 步会让训练几乎无法推进。

Q4. 线性 Warmup 中,学习率到达峰值时对应的训练进度系数是多少?

单选题 · mid

  • A.0
  • B.0.5
  • C.1← 正确答案
  • D.峰值学习率

答案:C。线性预热公式 $\eta_t = \eta_{\min} + \frac{t}{T_{\text{warm}}}(\eta_{\max}-\eta_{\min})$ 中,当 $t=T_{\text{warm}}$ 时系数 $\frac{t}{T_{\text{warm}}}=1$,学习率恰好达到峰值。

Q5. 余弦 Warmup 相比线性 Warmup 的主要优势是什么?

单选题 · mid

  • A.学习率峰值更高
  • B.训练速度一定更快
  • C.曲线平滑无锐角← 正确答案
  • D.不需要设置最低学习率

答案:C。余弦函数在升温和降温阶段都平滑过渡,避免线性策略在切换点产生的“折角”,损失曲线更丝滑。峰值由外部设定,速度不保证更快。

Q6. 下列关于 Warmup 峰值学习率的说法正确的是?

多选题 · mid

  • A.峰值取原训练方案可用的较大学习率← 正确答案
  • B.峰值越高模型精度一定越好
  • C.最低学习率通常设峰值的 1%~5%← 正确答案
  • D.峰值必须从 0 开始计算

答案:AC。峰值应使用常规方案中能稳定收敛的较大学习率;最低学习率取峰值的 1%~5% 是常见实践。B 错在“一定”,D 错在“必须从 0”——从极小值出发即可。

Q7. 为什么大模型训练尤其依赖 Warmup?

单选题 · hard

  • A.大模型参数量少所以需要预热
  • B.大规模随机初始化地形更复杂← 正确答案
  • C.大模型不需要学习率衰减
  • D.大模型只能使用线性策略

答案:B。大模型参数多、损失面更崎岖,初始阶段处于高曲率区域,大学习率的二阶项易引发损失暴涨。Warmup 以小学习率撑过风险区。A 错在参数量多,C 和 D 是错误论断。

Q8. 若训练中遇到 loss 震荡,哪些策略可能有效?

多选题 · hard

  • A.增加预热步数← 正确答案
  • B.调低峰值学习率← 正确答案
  • C.清空优化器动量
  • D.移除所有正则化项

答案:AB。loss 震荡常由初始阶段学习率过大引起,增加预热步数或调低峰值都能抑制。清空动量可能引入新的不连续,移除正则化会让训练更不稳定。

Q9. 以下哪一项是 Warmup 的常见应用场景?

单选题 · easy

  • A.BERT 预训练前 10000 步← 正确答案
  • B.数据归一化
  • C.特征降维
  • D.模型量化压缩

答案:A。BERT 预训练使用约 10000 步 Warmup 是经典实践。数据归一化、特征降维、量化是其他独立技术,与学习率调度无关。

Q10. 关于热身步数占比 5%~10%,下列说法成立的有?

多选题 · extreme

  • A.数据集极小也可按比例设定← 正确答案
  • B.模型规模越大占比可适当提高← 正确答案
  • C.预热步数不影响最终精度
  • D.训练总步数改变时预热步数应随动← 正确答案

答案:ABD。5%~10% 是通用经验,小数据集按总步数等比计算即可;大模型地形复杂,如 BERT 用约 10% 的比例。总步数变化时预热步数也应等比调整。C 明显错误——预热过长过短都会影响精度。