学习率衰减策略 带预热的余弦退火学习率调度(Cosine Annealing with Warmup)

学习率衰减策略 带预热的余弦退火学习率调度(Cosine Annealing with Warmup)

flyfish

import math
import matplotlib.pyplot as plt

# ===================== 超参数配置 =====================
# 解冻训练阶段的总训练轮次
UNFREEZE_EPOCHS = 15
# 学习率预热阶段的持续轮次
WARMUP_EPOCHS = 2
# 预热结束后达到的目标初始学习率
INIT_LR_UNFREEZE = 5e-5
# 余弦退火过程中学习率的下限值
ETA_MIN = 1e-6

# 计算有效预热轮数,避免传入负数导致逻辑异常
warmup_epochs = max(WARMUP_EPOCHS, 0)
# 计算余弦退火阶段的有效轮数(总轮数减去预热轮数),保证至少为1轮
cos_epochs = max(UNFREEZE_EPOCHS - warmup_epochs, 1)

# ===================== 逐轮计算学习率 =====================
lr_list = []       # 存储每一轮对应的学习率
epoch_list = list(range(UNFREEZE_EPOCHS))  # 生成所有训练轮次的序号

for epoch in epoch_list:
    # 预热阶段:学习率从0线性上升到目标初始值
    if warmup_epochs > 0 and epoch < warmup_epochs:
        current_lr = INIT_LR_UNFREEZE * (epoch + 1) / warmup_epochs
    
    # 余弦退火阶段:学习率从目标值平滑下降到最小值
    else:
        # 计算当前轮次在余弦退火阶段中的相对位置
        cos_pos = epoch - warmup_epochs
        # 标准余弦退火公式:在[0, π]区间内通过余弦函数实现平滑衰减
        current_lr = ETA_MIN + 0.5 * (INIT_LR_UNFREEZE - ETA_MIN) * (
            1 + math.cos(math.pi * cos_pos / cos_epochs)
        )
    
    lr_list.append(current_lr)
    # 格式化打印每一轮的学习率结果
    print(f"Epoch {epoch+1:2d}  学习率: {current_lr:.2e}")

# ===================== 绘制学习率曲线 =====================
# 设置中文字体,解决图表中文显示乱码问题
plt.rcParams['font.sans-serif'] = ['SimHei']
# 解决负号显示异常的问题
plt.rcParams['axes.unicode_minus'] = False

# 创建画布,设置尺寸和分辨率
plt.figure(figsize=(10, 5), dpi=120)
# 绘制学习率折线
plt.plot(epoch_list, lr_list, linewidth=2, color='#1f77b4', label='学习率曲线')

# 用半透明色块标注预热阶段区域
plt.axvspan(-0.5, warmup_epochs-0.5, color='#ff7f0e', alpha=0.15, label='预热阶段(线性上升)')
# 用半透明色块标注余弦退火阶段区域
plt.axvspan(warmup_epochs-0.5, UNFREEZE_EPOCHS-0.5, color='#2ca02c', alpha=0.15, label='余弦退火阶段(平滑下降)')

# 在每个轮次位置添加散点标记,突出显示每轮的具体学习率
plt.scatter(epoch_list, lr_list, color='#1f77b4', s=30, zorder=5)

# 设置图表标题与坐标轴标签
plt.title('学习率变化曲线(预热+余弦退火)', fontsize=13)
plt.xlabel('Epoch(训练轮次)', fontsize=11)
plt.ylabel('学习率 (Learning Rate)', fontsize=11)

# 添加网格线、图例,优化布局并显示图表
plt.grid(alpha=0.3, linestyle='--')
plt.legend(fontsize=10)
plt.tight_layout()
plt.show()

在这里插入图片描述

学习率

学习率(Learning Rate,简称 LR)是深度学习训练中的超参数之一,它控制着模型参数每次更新的步长大小

可以把模型训练理解为下山找最低点:
模型根据损失计算出梯度(下山的方向),然后用参数 = 参数 - 学习率 × 梯度来更新参数。
学习率太大:步长迈得太猛,容易在山谷附近来回震荡,甚至直接迈过最低点,导致训练发散、精度飙升后暴跌。
学习率太小:步长挪得太慢,训练收敛速度极慢,还容易卡在半山腰的局部最优里出不来。

简单说:学习率决定了模型学得快不快和学得稳不稳,它的调度策略直接影响最终模型的精度和训练效率。

学习率预热(Warmup)

学习率预热,就是训练刚开始的前几轮,让学习率从 0 开始,线性地逐步上升到设定的初始目标学习率,对应代码里前 2 个 Epoch 的逻辑。

为什么要做预热?
  1. 解决初始化阶段的梯度不稳定
    模型训练初期(尤其是微调解冻场景),权重要么是随机初始化,要么是预训练权重刚适配新数据,梯度的方向非常不准、方差很大。如果一上来就用满额学习率,参数会剧烈波动,很容易把初始权重冲坏,导致训练震荡甚至直接不收敛。

  2. 保护预训练权重(适配微调场景)
    代码是解冻阶段训练,模型 backbone 已经有预训练学到的通用知识。预热可以让模型先用小学习率慢慢适应新数据集,避免一开始大步更新就毁掉预训练积累的特征。

  3. 适配大 batch / 大模型训练
    batch 越大、模型越大,初期梯度的不确定性越强,预热几乎是标准操作,能显著提升训练的稳定性和最终精度。

余弦退火(Cosine Annealing)

余弦退火是预热结束后使用的一种学习率衰减策略:让学习率按照余弦函数的曲线,从初始目标值平滑、连续地下降到设定的最小值(ETA_MIN)。

对应代码里的公式:

current_lr = ETA_MIN + 0.5 * (INIT_LR_UNFREEZE - ETA_MIN) * (
    1 + math.cos(math.pi * cos_pos / cos_epochs)
)

它利用了余弦函数在 [0, π] 区间从 1 平滑降到 -1 的特性,让学习率从最大值顺滑地过渡到最小值,全程没有突变。

为什么要用余弦退火?
  1. 下降平滑,无突变震荡
    对比传统的阶梯式下降(比如每 5 轮学习率减半),余弦退火是连续平滑的曲线,不会因为学习率突然跳变导致模型损失剧烈震荡,训练过程更平稳。

  2. 衰减节奏符合训练规律
    训练前期:学习率高、下降慢,模型可以大步更新,快速收敛,还能跳出局部最优;
    训练中期:学习率下降速度加快,推动模型快速向最优解靠近;
    训练后期:学习率降到很低、下降再次放缓,对参数进行精细微调,让模型收敛到更精准的局部最小值。

  3. 泛化能力更优
    大量实验证明,余弦退火这种平滑衰减的方式,最终训练出的模型泛化能力(在测试集上的表现)通常优于生硬的阶梯衰减。

预热 + 余弦退火搭配使用

预热管开局稳:解决训练初期梯度不稳定、权重易被冲坏的问题,让模型平稳进入训练状态;
余弦退火管收尾好:在模型稳定训练后,用平滑的衰减节奏保证收敛速度,同时让最终收敛的精度更高、泛化性更好。

Epoch  1  学习率: 2.50e-05
Epoch  2  学习率: 5.00e-05
Epoch  3  学习率: 5.00e-05
Epoch  4  学习率: 4.93e-05
Epoch  5  学习率: 4.72e-05
Epoch  6  学习率: 4.38e-05
Epoch  7  学习率: 3.94e-05
Epoch  8  学习率: 3.42e-05
Epoch  9  学习率: 2.85e-05
Epoch 10  学习率: 2.25e-05
Epoch 11  学习率: 1.68e-05
Epoch 12  学习率: 1.16e-05
Epoch 13  学习率: 7.16e-06
Epoch 14  学习率: 3.81e-06
Epoch 15  学习率: 1.71e-06
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

二分掌柜的

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值