学习率衰减策略(Learning Rate Scheduler)

在深度学习训练过程中,学习率(Learning Rate)是一个至关重要的超参数。

它决定了模型参数每次更新的步幅:

  • 学习率太大:可能跳过最优点,训练不稳定甚至发散

  • 学习率太小:收敛速度慢,训练时间过长

因此,我们通常不会让学习率始终保持不变,而是采用一种更有效的方法:

学习率衰减(Learning Rate Decay)策略

一、为什么需要学习率衰减?

训练初期:

  • 模型距离最优解较远

  • 需要较大的学习率快速下降

训练后期:

  • 模型接近最优解

  • 需要较小学习率精细调整

所以学习率衰减的核心思想是:

先快后慢,逐步减小学习率,提高收敛效果

二、PyTorch 中的学习率调度器

PyTorch 提供了 torch.optim.lr_scheduler 模块,用于动态调整学习率。

典型的调度器结构为:

optimizer = torch.optim.SGD([w], lr=0.1, momentum=0.9)
scheduler = torch.optim.lr_scheduler.ExponentialLR(optimizer, gamma=0.95)

训练过程中,每个 epoch 调用:

scheduler.step()

即可更新学习率。

三、常见学习率衰减策略

3.1 StepLR:等间隔衰减策略

思想

每隔固定 epoch,将学习率乘以一个衰减系数:

$$ lr = lr \times \gamma $$
PyTorch 实现

scheduler = torch.optim.lr_scheduler.StepLR(
    optimizer,
    step_size=50,
    gamma=0.5
)
  • step_size=50:每 50 个 epoch 衰减一次

  • gamma=0.5:学习率减半

StepLR 优缺点

优点

  • 简单易用

  • 适合规律训练任务

缺点

  • 衰减时刻固定,不够灵活

学习率变化如下所示:

3.2 MultiStepLR:指定节点衰减策略

思想

StepLR为基础,在指定的 epoch 节点进行衰减:

比如:

  • 第 50 轮衰减一次

  • 第 125 轮再衰减

  • 第 160 轮再次衰减

Pytorch 实现

milestones = [50, 125, 160]
scheduler = torch.optim.lr_scheduler.MultiStepLR(
    optimizer,
    milestones=milestones,
    gamma=0.5
)

优点

  • 更灵活

  • 可根据训练曲线手动调整节点

学习率变化如下图所示:

3.3 ExponentialLR:指数衰减策略

思想

每一轮训练都按指数形式衰减:

$$ lr = lr \times \gamma $$
Pytorch 实现

scheduler = torch.optim.lr_scheduler.ExponentialLR(
    optimizer,
    gamma=0.95
)

每个 epoch 学习率都会变成:

$$l_r = l_r \times 0.95$$

优点

  • 平滑衰减

  • 适合长期训练任务

缺点

  • 衰减过快可能导致后期学习率过小

学习率变化如下图所示:

3.4 CosineAnnealingLR:余弦退火学习率策略

在训练大模型(如 Transformer、BERT、ViT)时,指数衰减或 Step 衰减有时会显得过于生硬。

因此,实践中非常常用一种更加平滑的策略:

余弦退火学习率衰减(Cosine Annealing)

思想

余弦退火的学习率变化类似一个余弦曲线:

  • 前期下降较慢

  • 中期下降较快

  • 后期下降趋于平缓

学习率的变化公式为:

$$ lr_t = lr_{min} + \frac{1}{2}(lr_{max} - lr_{min})(1 + \cos(\frac{t}{T}\pi)) $$

其中:

  • $lr_{max}$​:初始学习率

  • $lr_{min}$​:最低学习率

  • $T$:总衰减周期

  • $t$:当前 epoch

PyTorch 实现

scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(
    optimizer,
    T_max=200,
    eta_min=1e-5
)
  • T_max=200:余弦周期长度(一般设为总 epoch)

  • eta_min=1e-5:学习率的最小值

优点

✅ 学习率变化更加平滑
✅ 后期训练更稳定
✅ 大模型训练效果更好

学习率变化曲线如下:

3.5 Warmup:学习率预热策略

很多人会发现一个问题:

模型训练刚开始时,如果学习率过大,loss 会剧烈震荡甚至直接发散。

为了解决这个问题,引入 Warmup 策略。

Warmup核心思想是:

训练初期不直接使用大学习率,而是从一个很小的学习率开始逐步升高。

比如:

  • 第 0 epoch:lr = 0.0001

  • 第 1 epoch:lr = 0.001

  • 第 5 epoch:lr = 0.01

  • 之后再进入正常衰减阶段

这种策略特别适合:

  • 大 batch 训练

  • Transformer 网络

  • 训练不稳定的深层模型

Warmup 的学习率变化

最常见的 Warmup 是线性增长:

$$ lr_t = lr_{max} \cdot \frac{t}{T_{warmup}} $$

其中:

  • $T_{warmup}$​:预热轮数

  • $lr_{max}$​:目标学习率

示例

from torch.optim.lr_scheduler import LambdaLR

warmup_epochs = 5

def warmup_lambda(epoch):
    if epoch < warmup_epochs:
        return (epoch + 1) / warmup_epochs
    return 1

scheduler = LambdaLR(optimizer, lr_lambda=warmup_lambda)

它实现的是 Warmup 学习率预热

训练刚开始的前 warmup_epochs=5 个 epoch,让学习率从小到大逐步变大;
第 5 个 epoch 之后,学习率保持不变(乘数固定为 1)。

举个具体的例子,假如优化器的学习率设置为0.1:

optimizer = torch.optim.SGD(model.parameters(), lr=0.1)

那么$lr_{max}$=0.1

Warmup阶段 5 个 epoch 的倍率分别是:

epochwarmup_lambda(epoch)实际 lr = 0.1 * 倍率
0(0+1)/5 = 0.20.02
10.40.04
20.60.06
30.80.08
41.00.10
510.10
610.10

画出来的图:

3.6 Warmup + CosineAnnealing

实际工程中最常用组合:

Warmup + CosineAnnealing

假设流程:

  1. 前 5 个 epoch Warmup

  2. 后续使用余弦退火衰减

    # 训练的总轮次
    epochs = 200

    # Warmup + CosineAnnealing(最佳实践)
    warmup_epochs = 5

    warmup_scheduler = torch.optim.lr_scheduler.LambdaLR(
        optimizer,
        lr_lambda=lambda epoch: (epoch + 1) / warmup_epochs
    )

    cosine_scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(
        optimizer,
        T_max=epochs - warmup_epochs
    )

    scheduler = torch.optim.lr_scheduler.SequentialLR(
        optimizer,
        schedulers=[warmup_scheduler, cosine_scheduler],
        milestones=[warmup_epochs]
    )

学习率变化如图所示:

四、总结:学习率衰减策略全景对比

策略特点常用场景
StepLR固定间隔衰减简单任务 baseline
MultiStepLR指定节点衰减人工控制训练节奏
ExponentialLR指数平滑下降长期训练任务
CosineAnnealingLR ⭐平滑退火下降大模型训练首选
Warmup ⭐初期逐步升高Transformer 必备
Warmup + Cosine ⭐⭐⭐最佳组合方案工业级训练标准配置

更多推荐