想象你第一天学开车。教练绝不会让你一上车就猛踩油门冲上高速。你得先在空场地里低速绕圈,熟悉方向盘手感、刹车距离,等肌肉记住了基本操作,才慢慢提速上公路,最后才能平稳地巡航在高速上。深度学习训练里的 Warmup(学习率预热) 就是同一个道理:训练刚开始时,模型就像一个刚摸方向盘的新手,什么都不懂。如果此时直接给它一个很大的学习率(相当于猛踩油门),它很容易“开沟里”——损失值剧烈震荡甚至变成 NaN(梯度爆炸)。所以聪明的做法是:前几百步只给很小的学习率,让模型慢慢“找感觉”,再逐步把学习率升到正常水平,然后才开始衰减。这就是 Warmup 存在的意义:训练初期,慢就是快。
理解 Warmup 能让你在训练 Transformer、BERT 等大模型时少踩梯度爆炸的坑,训练损失曲线更平滑,模型收敛更稳定——这是从“调参直觉”走向“训练工程”的必备技能。
可视化演示
展示线性与余弦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$ 还没达到预热步数 $T_{\text{warm}}$ 时,学习率从最小值 $\eta_{\text{min}}$ 开始爬升。
- 比例系数$\dfrac{t}{T_{\text{warm}}}$ 表示训练进度,当 $t=0$ 时系数为 0,当 $t=T_{\text{warm}}$ 时系数为 1,学习率刚好到达峰值。
- 衰减段预热结束后,学习率交给衰减策略按总步数 $T$ 逐步降低,直到训练结束。
为什么要预热
新手最怕什么?不是开得慢,而是开得快。速度一上来,遇到突发情况就手忙脚乱,方向盘一打,车子直接失控。模型也一样。刚初始化的神经网络,权重都是随机数,参数分布完全没规律。此时如果学习率太大,每个参数的更新步长都很大,梯度信号就像脱缰的野马——可能跑向完全错误的方向,损失值剧烈震荡,甚至梯度爆炸到 NaN。
还有一个更隐蔽的问题叫“提前拟合坏方向”。训练早期,模型对数据的判断完全是盲目的。如果给它大学习率,它会狠狠记住初始几步碰巧遇到的错误规律,后面再想纠正就难了。这就是为什么训练初期要用小学习率:让模型先“看清楚”数据的大致分布,再开始大步优化。
损失函数的图像是一座山谷,模型要从山顶滑到谷底。预热期是让你先站在山顶环顾四周,把地形看清楚;没有预热直接大学习率,相当于蒙着眼往山下跳——可能直接跳过山谷摔到对面的山上。
所以,预热期用小学习率,本质是把 $\eta_t$ 压小,让二阶项这个“搅局者”没机会发力。等模型走到地形平缓的区域,再加大步伐冲刺。
- 损失变化展开把损失函数在参数 $\theta_t$ 附近做二阶泰勒展开,近似估计下一步损失会变成多少。
- 一阶项$\eta_t \nabla L(\theta_t) \cdot g$ 是梯度下降的“常规操作”,只要顺着梯度反方向走,损失就会下降。
- 二阶项$\dfrac{\eta_t^2}{2} g^T H g$ 是曲率修正项。如果地形(Hessian 矩阵 $H$)崎岖不平,这一项会让损失不降反升。
线性Warmup
线性 Warmup 是最朴素的预热方式:学习率从 0(或一个极小值)出发,每一步增加固定的量,匀速上升到峰值。就像学车时的“每十分钟加 5 迈”——节奏均匀,容易掌握。
它的公式很简单,就是前面分段函数里预热段公式:
在 PyTorch 中,实现代码长这样:
这个策略的好处是行为可预测:你清楚每一步学习率是多少,调试方便。坏处是结束预热那一刻,学习率曲线有一个“折角”,从上升突然切换成衰减,如果衰减策略不匹配,这个折角可能引起损失一个小抖动。不过对于中小规模模型,线性 Warmup 完全够用,大多数情况下你已经看不到这个抖动对最终精度的影响。
直线加速的优点是直观,缺点是太“生硬”。就像学车时教练说“上 60 迈”,你一脚油门直接踩到 60,车身会顿一下。对于追求极致训练曲线的人来说,这个“顿”也想省掉——这就有了下一种更平滑的策略。
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$ 从 0 走向 $T_{\text{warm}}$ 时,$\cos(\dfrac{\pi t}{T_{\text{warm}}})$ 从 1 走到 -1,学习率从 0 平滑升到峰值。
- 升余弦因子$1 - \cos(\pi t/T_{\text{warm}})$ 恒为非负,除以 2 后取值范围是 0 到 1,恰好充当“进度条”。
- 衰减降余弦$t$ 从 $T_{\text{warm}}$ 走向 $T$ 时,余弦从 1 滑到 -1,学习率从峰值平滑走向最小值。
参数怎么设
教练说“先开 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 演示
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}")
def cosine_lr(step, warmup_steps, total_steps, peak_lr, min_lr)核心调度函数,先升后降,返回第step步该用的学习率。return min_lr + (peak_lr - min_lr) * (step + 1) / warmup_steps线性预热公式,步数越多学习率越高。min_lr + 0.5 * (peak_lr - min_lr) * (1 + math.cos(...))余弦衰减公式,输出从 1 平滑滑向 0。grad = math.sqrt(loss) * 0.5 + random.uniform(-0.6, 0.6) * lr * 10学术上的噪声模拟,学习率越大梯度噪声越大,大学习率天然更容易震荡。loss -= lr * grad模拟参数更新的效果,学习率太小则收敛慢。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 阶段学习率的变化趋势是什么?
- A.从低到高逐渐爬升← 正确答案
- B.从高到低逐渐降低
- C.一直保持固定值
- D.随机的上下波动
答案:A。Warmup 的“预热”含义就是训练初期学习率从较小值逐步上升到峰值,对应选项 A。选项 B 是衰减策略,C 是固定学习率,D 是退化配置。
Q2. 下列哪项是训练开始时使用大学习率最直接的风险?
- A.模型过拟合
- B.梯度爆炸或发散← 正确答案
- C.数据增强失效
- D.显存不足
答案:B。初始参数随机分布不稳定,大学习率会让梯度信号失控,导致 loss 震荡甚至变成 NaN,这就是梯度爆炸/发散。过拟合是训练后期问题,和数据增强、显存无关。
Q3. 假设总训练步数为 100000,预热步数取多少最合理?
- A.0 步
- B.500 步
- C.6000 步← 正确答案
- D.95000 步
答案:C。预热步数通常取总步数的 5%~10%,100000 的 5%~10% 是 5000~10000 步,选项 C 的 6000 落在此区间。0 步等于没预热,95000 步会让训练几乎无法推进。
Q4. 线性 Warmup 中,学习率到达峰值时对应的训练进度系数是多少?
- 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 的主要优势是什么?
- A.学习率峰值更高
- B.训练速度一定更快
- C.曲线平滑无锐角← 正确答案
- D.不需要设置最低学习率
答案:C。余弦函数在升温和降温阶段都平滑过渡,避免线性策略在切换点产生的“折角”,损失曲线更丝滑。峰值由外部设定,速度不保证更快。
Q6. 下列关于 Warmup 峰值学习率的说法正确的是?
- A.峰值取原训练方案可用的较大学习率← 正确答案
- B.峰值越高模型精度一定越好
- C.最低学习率通常设峰值的 1%~5%← 正确答案
- D.峰值必须从 0 开始计算
答案:AC。峰值应使用常规方案中能稳定收敛的较大学习率;最低学习率取峰值的 1%~5% 是常见实践。B 错在“一定”,D 错在“必须从 0”——从极小值出发即可。
Q7. 为什么大模型训练尤其依赖 Warmup?
- A.大模型参数量少所以需要预热
- B.大规模随机初始化地形更复杂← 正确答案
- C.大模型不需要学习率衰减
- D.大模型只能使用线性策略
答案:B。大模型参数多、损失面更崎岖,初始阶段处于高曲率区域,大学习率的二阶项易引发损失暴涨。Warmup 以小学习率撑过风险区。A 错在参数量多,C 和 D 是错误论断。
Q8. 若训练中遇到 loss 震荡,哪些策略可能有效?
- A.增加预热步数← 正确答案
- B.调低峰值学习率← 正确答案
- C.清空优化器动量
- D.移除所有正则化项
答案:AB。loss 震荡常由初始阶段学习率过大引起,增加预热步数或调低峰值都能抑制。清空动量可能引入新的不连续,移除正则化会让训练更不稳定。
Q9. 以下哪一项是 Warmup 的常见应用场景?
- A.BERT 预训练前 10000 步← 正确答案
- B.数据归一化
- C.特征降维
- D.模型量化压缩
答案:A。BERT 预训练使用约 10000 步 Warmup 是经典实践。数据归一化、特征降维、量化是其他独立技术,与学习率调度无关。
Q10. 关于热身步数占比 5%~10%,下列说法成立的有?
- A.数据集极小也可按比例设定← 正确答案
- B.模型规模越大占比可适当提高← 正确答案
- C.预热步数不影响最终精度
- D.训练总步数改变时预热步数应随动← 正确答案
答案:ABD。5%~10% 是通用经验,小数据集按总步数等比计算即可;大模型地形复杂,如 BERT 用约 10% 的比例。总步数变化时预热步数也应等比调整。C 明显错误——预热过长过短都会影响精度。