学习率预热 Warmup:稳定训练初期的关键步骤

FreeGuideOnline 最新 2026-06-21

学习率预热 Warmup:稳定训练初期的关键步骤

在训练深度神经网络时,学习率是最关键的超参数之一。如果初始学习率设置不当,模型可能在训练初期就陷入震荡甚至发散。学习率预热(Learning Rate Warmup)是一种简单而有效的策略,它通过让学习率从一个很小的值逐步增加到预设的初始学习率,帮助模型平稳度过训练的起始阶段,从而提升最终性能。

为什么需要学习率预热

训练初期的“脆弱性”

模型参数通常采用随机初始化,此时网络的输出分布极不稳定,梯度方向也充满噪声。如果直接使用较大的学习率,参数更新步长过大,容易使损失函数产生剧烈波动,甚至直接跳出合理区域,导致训练失败。尤其在批量归一化(Batch Normalization)层中,初期的统计量估计不准确,大学习率会加剧这种偏差。

从实验角度观察

大量实验表明,有无预热对训练曲线的影响十分显著。没有预热时,损失值在最初几百步可能先上升再下降,或者出现剧烈抖动;加入预热后,损失平稳下降,验证集准确率也往往更高。特别是在Transformer、BERT等大规模模型中,预热几乎是标配技巧。

学习率预热的核心思想

学习率预热并不是一种复杂的优化算法,而是一个调度策略。它在训练的初始阶段(比如前N个训练步或前几个epoch),让学习率从接近0的极小值线性(或采用其它方式)增长到设定的初始学习率。之后,再接上常规的学习率衰减策略(如余弦退火、阶梯下降等)。

打个比方:你启动一辆赛车,不会直接把油门踩到底,而是从低速缓缓加速,等车身稳定后再逐步提速。预热就是为优化器提供这样一个“缓冲启动”的机制。

常见的预热方式

线性预热(Linear Warmup)

最经典、最常用的预热方式。在预热阶段,学习率按照线性函数增加:

lr(t) = base_lr * (t / warmup_steps)  当 t < warmup_steps

其中 base_lr 是预定的初始学习率,warmup_steps 是预热步数。PyTorch、TensorFlow等框架都内置了线性预热调度器。

示例:假设初始学习率为 0.01,预热步数为 1000 步,那么第500步的学习率就是 0.005。

指数增长预热(Exponential Warmup)

学习率以指数形式增长,初期增长更慢,后期更快,但相对较少使用。

lr(t) = base_lr * exp( -c * (1 - t / warmup_steps) )

其中 c 控制增长速度。这种方法更关注最初始阶段的稳定性,但需要调校额外参数。

常数预热(Constant Warmup)

在预热阶段保持一个较小的学习率,比如 base_lr * 0.01,然后直接跳到 base_lr。实现简单,但突变可能带来轻微不稳定,一般用于极短预热或特殊场景。

实际应用中的超参数选择

预热步数(Warmup Steps)

预热步数是关键超参数。通常取:

  • 总训练步数的 1%~5%(常见于CV任务)
  • 固定步数,如 4000、8000、10000(在NLP预训练任务中)
  • 对于小型模型和简单任务,几百步就足够

经验法则:观察无预热时损失曲线的波动情况。如果前几百步剧烈振荡,则适当增加预热步数。也可从训练步数的 2% 开始尝试。

起始学习率

预热开始时,学习率通常设为 0 或者 base_lr * 1e-3。设置为 0 是最稳妥的做法。对于带梯度累积的混合精度训练,起始可以为 0;对于学习率极小的场景(如微调),甚至可以直接以 base_lr 的 0.1 倍开始。

与学习率衰减的衔接

预热结束后,必须无缝衔接到后续的学习率计划。常见的组合有:

  • 线性预热 + 余弦退火:CV、Transformer预训练中最流行
  • 线性预热 + 阶梯衰减:经典CNN训练
  • 线性预热 + 常量:微调时偶尔使用

衔接处应避免学习率突变,确保调度函数连续。

在主流框架中实现预热

PyTorch

PyTorch提供了 torch.optim.lr_scheduler.LinearLR 等调度器,但更方便的是使用 transformers 库的 get_linear_schedule_with_warmup 或自定义组合调度器。

from torch.optim.lr_scheduler import LambdaLR

def warmup_lambda(current_step, warmup_steps, base_lr_ratio=0.0):
    if current_step < warmup_steps:
        return float(current_step) / float(max(1, warmup_steps))
    return 1.0  # 超出预热后保持原学习率,再外接主调度器

scheduler = LambdaLR(optimizer, lr_lambda=warmup_lambda)

结合主衰减(如余弦)时,可以使用 SequentialLR 或自定义函数将预热和衰减合并为同一个 Lambda 函数。

Hugging Face Transformers

内置了丰富的调度器,直接指定 warmup_stepswarmup_ratio

from transformers import get_cosine_schedule_with_warmup

scheduler = get_cosine_schedule_with_warmup(
    optimizer,
    num_warmup_steps=500,
    num_training_steps=total_steps
)

TensorFlow/Keras

Keras 提供 tf.keras.optimizers.schedules.LinearWarmup(在 tf-addons 或后续版本中),也可自定义 LearningRateSchedule 实现任意预热策略。

常见误区与注意事项

  1. 预热步数过多:预热过长会让模型长时间处于小学习率状态,浪费计算资源,并可能导致寻找平坦极小值的过程延迟。应平衡稳定性和效率。
  2. 预热时优化器的动量:动量优化器(如Adam、SGD with momentum)在预热阶段动量参数也需要处理。通常保持动量参数正常更新即可,但部分实践会“冻结”动量或使用校正因子(如RAdam)。对于大多数场景,不做特殊处理也没问题。
  3. 预热与梯度裁剪:预热阶段如果同时使用梯度裁剪,应该设置合适的阈值,避免将本已较小的梯度再过度修剪,这样会抵消预热效果。
  4. 验证集性能波动:预热不影响验证集评价(此时模型只前向传播),但训练初期验证指标可能抖动剧烈,不必惊慌,关键是训练损失能否平稳下降。

总结

学习率预热通过“由小到大”的缓启动策略,有效保护了随机初始化的脆弱参数,防止初期训练发散或不稳定。它简单、计算开销极小,已经成为现代深度学习训练的标准步骤之一,尤其在Transformer、BERT、ViT等大模型训练中几乎是必备技巧。将预热与合适的学习率衰减策略搭配,你可以用更少的调参成本,获得更稳定、更高性能的训练结果。