在前面的内容 Pytorch深入浅出(七)之优化器(Optimizer)以及Pytorch进阶训练技巧(二)之梯度层面的优化策略中,我们分别解决了 “怎么更新” 和 “如何稳住梯度” 的问题。
但在真实训练中,即便优化器选得对,梯度也稳定,模型依然可能出现前期不降反升、后期收敛缓慢或验证集剧烈震荡的情况。这时,问题通常出在 “更新的节奏”。
本篇介绍几种学习率(LR)调度策略,帮助精准控制训练节奏。
- Warmup
- 按阶段衰减(Step / MultiStep)
- 余弦退火(Cosine Annealing)
- 自适应调度(ReduceLROnPlateau)
一、Warmup(学习率预热)
1. 为什么需要 Warmup?
在训练初期,模型参数处于随机初始化状态,梯度方向极其不稳定。如果一开始就使用较大的学习率,容易导致:
- Loss 瞬间发散:初始梯度过大直接把模型“带偏”。
- 训练崩溃:在 Transformer 或大 Batch 训练中极其常见。
2. 核心思想
先礼后兵:学习率从小到大,逐步进入正常训练区间。 Warmup 并不是“衰减”策略,而是一种训练初期的启动调度,通常与后续的衰减策略组合使用。 最常见的是线性 Warmup:在训练的前
N
N
N 个 Step(或在少量 Epoch 内按 Step 线性增长),让学习率从一个极小值线性增长到设定的初始学习率。
3. PyTorch 中的典型实现方式(LambdaLR)
optimizer = torch.optim.AdamW(model.parameters(), lr=1e-3)
warmup_steps = 1000
# 定义线性增长逻辑
lr_lambda = lambda step: min(1.0, step / warmup_steps)
scheduler = torch.optim.lr_scheduler.LambdaLR(optimizer, lr_lambda)
# ——– 训练循环(按 Step 更新) ——–
for images, labels in train_loader:
# Forward & Backward …
optimizer.step()
scheduler.step() # Warmup 通常是 Step 级的,每一步都更新步幅
optimizer.zero_grad()
👉 形象比喻:就像冷车启动。不能一打火就踩死油门,得先让发动机怠速热一热,转速稳了再加速。
二、阶段性衰减(Step / MultiStep)
1. 为什么需要阶段性衰减?
随着训练进行,模型逐渐接近最优解区域。此时大步长会导致在“谷底”反复横跳,无法精准降落。
- 前期:需要大步走,快速收敛。
- 后期:需要换小步,精细微调。
2. 核心思想
在预设的时间点(Step 或 Epoch),将学习率乘以一个衰减因子 γ 常见形式是 StepLR:固定间隔衰减;MultiStepLR:指定若干关键节点衰减
3. PyTorch 中的标准用法
StepLR
# 每 30 个 Epoch,学习率缩小为原来的 1/10
scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=30, gamma=0.1)
for epoch in range(100):
train_one_epoch(...)
scheduler.step() # 阶段性衰减通常在每个 Epoch 结束时更新
MultiStepLR
# 或者指定里程碑点:在第 30, 80, 120 Epoch 衰减
scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=[30, 80, 120], gamma=0.1)
for epoch in range(100):
train_one_epoch(...)
scheduler.step() # 阶段性衰减通常在每个 Epoch 结束时更新
👉 形象比喻:就像下山换挡。坡度陡时(初期)需要快速滑行,接近平地(后期)时要换低档慢行,防止刹不住车撞到山头。
三、余弦退火(Cosine Annealing)
1. 为什么需要余弦退火?
相比“离散式”的阶段突发衰减,余弦退火提供了一种连续、平滑的节奏控制方式。
余弦退火是目前 SOTA 模型(如 ResNet, Transformer)的标配,它让学习率按照余弦曲线平滑下降。实际工程中常与 Warmup 组合使用,形成 Warmup + Cosine 的两阶段调度策略。
2. 核心思想
利用余弦函数的单调递减段,让学习率平滑、优雅地从最大值降到最小值。
3. PyTorch 中的标准用法
# T_max 是下降周期,一般设为总 Epoch 数
scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=100, eta_min=1e-6)
for epoch in range(100):
train_one_epoch(...)
scheduler.step()
👉 形象比喻:就像飞机的降落过程。不是一降到底,而是平滑地减速并接触跑道,体验极其丝滑。
四、自适应调度(ReduceLROnPlateau)
1. 为什么需要自适应调度?
有时我们无法提前预知模型什么时候会“学不动”。
- 提前降速可能导致收敛不足。
- 降速太晚则浪费计算资源。
2. 核心思想
指标导向。监控验证集的 Loss 或 Accuracy。如果指标在一段时间内(Patience)不再改善,自动降低学习率。
3. PyTorch 标准用法
scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(
optimizer,
mode='min', # 监控 Loss 时选 min,监控 Acc 时选 max
factor=0.1, # 缩放因子
patience=5, # 容忍 5 个 Epoch 没进步就降速
verbose=True # 打印降速日志
)
for epoch in range(100):
val_loss = validate(...)
scheduler.step(val_loss) # 注意:这里必须传入监控的指标
👉 形象比喻:就像一个贴身教练。当你训练遇到瓶颈(Plateau)且尝试了 patience 次都没突破时,他才会要求你放慢步调,重新寻找突破口。
💡 总结:训练节奏配置
不同调度器的更新粒度不同:Warmup 通常按 Step 更新,Step/Cosine 多按 Epoch 更新,而 Plateau 则由验证指标触发。
| Warmup | 大模型、AdamW、大 Batch | 防止训练初期崩溃 |
| Cosine Annealing | 绝大多数分类、检测任务 | 追求极限精度,过程丝滑平稳 |
| Step / MultiStep | 数据规模小、经典 CNN | 逻辑简单,实验可复现性极强 |
| ReduceLROnPlateau | 调参经验不足、指标震荡 | 指标驱动、减少手动调参,但依赖验证指标质量 |
最终实战建议:
1️⃣ 在现代模型中,最强的组合通常是:Linear Warmup (前 5 Epoch) + Cosine Annealing (后期)。这套组合拳几乎能搞定 90% 的计算机视觉和 NLP 任务。 2️⃣ ReduceLROnPlateau 更稳,但对指标质量和验证频率较敏感,使用时仍需注意验证噪声。
网硕互联帮助中心






评论前必须登录!
注册