本文目录导读:

学习率调度(Learning Rate Scheduling)是深度学习训练中非常关键的一环,它的核心思想是:在训练过程中动态地调整学习率,而不是使用一个固定值。
一个好的学习率调度策略,可以显著提升模型的收敛速度、最终精度,并帮助模型逃离局部极小值或鞍点。
为什么需要学习率调度?
想象一下我们正在下山(寻找损失函数的最小值):
- 学习率太大:步长太大,容易在山谷两侧来回震荡,甚至直接跳出山谷(错过最优点),导致损失无法收敛。
- 学习率太小:步长太小,虽然能稳步下降,但训练过程非常缓慢,而且很容易陷入局部的“小坑”里(局部极小值)出不来。
一个理想的策略是:
- 训练初期:使用较大的学习率,快速接近最优解区域。
- 训练中后期:逐渐减小学习率,在最优解附近进行精细的微调,避免震荡。
主流的学习率调度策略
下面介绍几种最常用、效果也最好的策略。
分段常数衰减
这是最简单的策略之一,人为设定几个“里程碑”步数(Epoch),到达后学习率直接乘以一个衰减因子(如0.1)。
-
原理:手动控制学习率在特定阶段下降。
-
代码示例(PyTorch):
import torch.optim.lr_scheduler as lr_scheduler # 假设 optimizer 是之前定义好的 # milestones:在第30、60、80个Epoch时触发衰减 # gamma:衰减因子,新的lr = 旧的lr * 0.1 scheduler = lr_scheduler.MultiStepLR(optimizer, milestones=[30, 60, 80], gamma=0.1) for epoch in range(100): train(...) validate(...) scheduler.step() # 每个epoch结束后调用,更新学习率 -
优点:简单、直观,效果稳定。
-
缺点:需要手动调整milestones,不够自适应。
指数衰减
学习率在每个迭代或每个Epoch后,按指数函数衰减。
- 公式:
lr = lr_initial * gamma ^ epoch - 代码示例(PyTorch):
# gamma:通常设为0.9-0.99,接近1则衰减慢 scheduler = lr_scheduler.ExponentialLR(optimizer, gamma=0.95)
- 优点:曲线平滑,易于控制衰减速度。
- 缺点:衰减速度固定,可能过早衰减导致模型收敛变慢。
余弦退火
这是一种非常流行且高效的策略,学习率按照半个余弦函数的周期来下降。
- 原理:从初始学习率开始,像余弦曲线一样平滑地下降到接近0。
- 代码示例(PyTorch):
# T_max:半个余弦周期的长度,例如设为总Epochs数,则学习率在结束时降到最低。 scheduler = lr_scheduler.CosineAnnealingLR(optimizer, T_max=100)
- 优点:衰减过程非常平滑,在很多视觉任务中效果优于分段衰减。
- 缺点:如果T_max设置不当,可能在训练结束时学习率降得太低。
带重启的余弦退火
这是余弦退火的进阶版,它会在学习率降到最低点后,突然将学习率重置到一个较高的值,然后重新开始一个余弦周期。
- 原理:这种“重启”操作能让模型跳出当前的局部极小值,探索新的更优解空间。
- 代码示例(PyTorch):
# T_0:第一个周期的长度(Epoch数) # T_mult:每次重启后,周期长度乘以该系数(通常设为2) scheduler = lr_scheduler.CosineAnnealingWarmRestarts(optimizer, T_0=20, T_mult=2)
- 优点:非常有效,尤其适用于复杂、非凸的损失函数。
- 缺点:超参数(T_0, T_mult)需要调试。
循环学习率
学习率在一个预设的上下限之间循环变化,而不是单调下降。
- 原理:通过周期性的增大和减小学习率,帮助模型逃离局部极小值。
- 优点:有时能获得比单调下降更好的效果。
- 缺点:属于比较激进的方法,需要小心调节边界值。
高级变体 & 自适应调度器
除了上述基于“轮数”的调度,还有基于“指标”的自适应调度器:
- ReduceLROnPlateau(PyTorch):
- 原理:监控验证集的损失,当损失连续多个Epoch(
patience参数)没有下降时,就自动降低学习率。 - 优点:完全自适应,工程师不需要预设衰减步数,这是很多实战场景的首选。
- 代码示例:
scheduler = lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', factor=0.1, patience=5) for epoch in range(100): val_loss = train_and_validate(...) scheduler.step(val_loss) # 传入监控指标
- 原理:监控验证集的损失,当损失连续多个Epoch(
总结与选择建议
| 策略名称 | 核心特点 | 适用场景 | 推荐指数 |
|---|---|---|---|
| 分段常数衰减 | 简单、稳定、可解释性强 | 大多数标准任务,尤其是CV(图像)任务 | ⭐⭐⭐⭐ |
| 指数衰减 | 平滑、可控 | 对收敛速度要求不敏感的任务 | ⭐⭐⭐ |
| 余弦退火 | 平滑、流行、效果好 | 现代CNN(卷积神经网络)和Transformer训练 | ⭐⭐⭐⭐⭐ |
| 带重启的余弦退火 | 强探索能力、更优解 | 复杂任务、训练时间短、追求极致精度 | ⭐⭐⭐⭐ |
| ReduceLROnPlateau | 完全自适应、省心 | 数据量不大、难以选择milestones、快速实验 | ⭐⭐⭐⭐⭐ |
一个实用的工作流:
- 新手或快速实验: 优先尝试
ReduceLROnPlateau,设置patience=3或5,factor=0.1,它非常稳健。 - CV(图像)任务(如ResNet, EfficientNet): 经典用法是
分段常数衰减(如 30, 60, 90),如果追求更好效果,可以改用余弦退火。 - Transformer类模型(如BERT, ViT, GPT): 通常使用一种更精细的调度器——Warmup + 余弦衰减,先使用很小的学习率预热
warmup_steps步,让模型稳定,然后再用余弦衰减下降,PyTorch 提供了CosineAnnealingWarmRestarts或可以自定义实现。
最关键的一点: 无论选择哪种调度器,监控验证集的损失/准确率 都是判断学习率是否合适的金标准,如果验证损失在持续震荡或上升,说明学习率可能太大了。