"Warmup Scheduler"通常是指深度学习训练中,一种在训练初期使用较低学习率进行"预热"(Warmup),然后再按照预定策略(如余弦退火、阶梯下降等)衰减学习率的方法。
这常用于稳定训练初期,尤其是使用大Batch Size、训练Transformer类模型(如BERT、ViT)或进行迁移学习微调时。
核心原理与作用
- 稳定训练:模型权重在初始化时是随机的。训练初期直接使用较大的学习率可能导致梯度爆炸或不稳定的剧烈更新。Warmup给模型一个"适应"数据分布和梯度方向的时间。
- 防止过拟合:初期的小学习率有助于模型先探索一个平滑的损失区域,找到更优的优化路径。
- 对大Batch Size尤其有效:大Batch Size意味着每次更新的梯度估计更准确、噪声更小,理论上可以用更大的学习率。但初始阶段直接用大LR可能不稳定,Warmup提供了一个平滑过渡。
常见Warmup策略
- 线性Warmup
最常见的策略。在开始的 N 个Steps或Epochs内,学习率从0(或一个很小的值)线性增加到预设的初始学习率。
• 公式:current_lr = base_lr * (current_step / warmup_steps)
• 示例:base_lr = 5e-4, warmup_steps = 1000,则在第500步时,学习率为 5e-4 * (500/1000) = 2.5e-4。
- 指数Warmup
学习率从0开始指数增长到初始学习率,增长较线性更快。
- 常数Warmup
在Warmup阶段保持一个固定的较小学习率,Warmup结束后直接跳到设定的初始学习率。
配合后续衰减策略的典型流程
一个完整的学习率调度计划通常是 "Warmup阶段" + "主衰减阶段"。
例如:Warmup + 余弦退火 (Cosine Annealing)
- 前 T_{warmup} 步:线性Warmup。
lr_t = base_lr * (t / T_warmup) - 后续 T_{total} - T_{warmup} 步:余弦退火衰减到最小学习率。
lr_t = lr_min + 0.5 * (base_lr - lr_min) * (1 + cos(π * (t - T_warmup) / (T_total - T_warmup)))
代码示例(PyTorch)
线性Warmup + 余弦退火
import torch.optim as optim
from torch.optim.lr_scheduler import LambdaLR, CosineAnnealingLR
def get_cosine_schedule_with_warmup(optimizer, num_warmup_steps, num_training_steps, num_cycles=0.5, last_epoch=-1):
"""
创建一个调度器:先线性Warmup,再余弦衰减。
"""
def lr_lambda(current_step):
if current_step < num_warmup_steps:
线性增长
return float(current_step) / float(max(1, num_warmup_steps))
余弦衰减
progress = float(current_step - num_warmup_steps) / float(max(1, num_training_steps - num_warmup_steps))
return max(0.0, 0.5 * (1.0 + math.cos(math.pi * float(num_cycles) * 2.0 * progress)))
return LambdaLR(optimizer, lr_lambda, last_epoch)
使用示例
optimizer = optim.AdamW(model.parameters(), lr=5e-4)
scheduler = get_cosine_schedule_with_warmup(optimizer,
num_warmup_steps=500,
num_training_steps=total_training_steps)
每个训练step后调用
for step, batch in enumerate(dataloader):
loss = ...
loss.backward()
optimizer.step()
scheduler.step() # 更新学习率
使用Transformers库
Hugging Face的Transformers库内置了完善的Warmup调度器。
from transformers import get_linear_schedule_with_warmup, get_cosine_schedule_with_warmup
线性Warmup + 线性衰减
scheduler = get_linear_schedule_with_warmup(
optimizer,
num_warmup_steps=500,
num_training_steps=total_training_steps
)
或者,线性Warmup + 余弦衰减
scheduler = get_cosine_schedule_with_warmup(
optimizer,
num_warmup_steps=500,
num_training_steps=total_training_steps,
num_cycles=0.5 # 余弦周期数
)
超参数设置经验
• Warmup Steps/Epochs:通常设置为总训练步数的 5%~10%。例如,训练10000步,Warmup可以设500-1000步。对于大规模预训练(如BERT),比例可能更低(如1%)。
• 起始学习率:Warmup开始的LR通常设为0,或 base_lr * 0.1。
• Base LR:需要根据任务、模型和Batch Size单独调试。
为什么需要Warmup?一个直观比喻
想象一下你要推一个很重的雪球上山(优化过程)。
• 没有Warmup:一开始就用全力猛推,雪球可能碎裂(训练不稳定)或冲错方向(陷入局部最优)。
• 有Warmup:先轻轻推,感受雪球的重量和路况(让模型适应数据和梯度),等它平稳滚动起来后,再逐渐加大力度(提高学习率),最后在接近山顶时收力(学习率衰减)。
希望这个详细的解释对您有帮助!如果您有特定的框架(如TensorFlow、PyTorch Lightning)或具体的使用场景,我可以提供更针对性的示例。