📚 课程目录

第22课:学习率调度

📖 本课概述

学习率是训练最重要的超参数,好的调度策略可以显著提升模型性能。本课深入各种学习率调度策略和实战技巧。

📊 一、学习率调度的重要性

训练初期:大学习率快速探索

训练中期:逐渐降低,精细调优

训练后期:小学习率,收敛到最优点附近

📅 二、常见调度策略

2.1 StepLR

每step_size个epoch,lr乘以gamma

lr = lr₀ × gamma^(epoch // step_size)

2.2 CosineAnnealing

lr = lr_min + 0.5(lr_max - lr_min)(1 + cos(πt/T))

平滑下降,被证明效果好于StepLR

2.3 Warmup + Cosine Decay

前N步线性增加:lr = lr₀ × t/N

之后余弦衰减:lr = lr_min + 0.5(lr_max-lr_min)(1+cos(π(t-N)/(T-N)))

Transformer训练的标准策略

2.4 OneCycleLR

先增后减的超收敛策略

lr: 低→高→低→极低

Super-convergence:用更少epoch达到更好效果

2.5 PyTorch实现


import torch
import torch.nn as nn
import math

# 学习率调度对比
torch.manual_seed(42)
model = nn.Sequential(nn.Linear(10, 64), nn.ReLU(), nn.Linear(64, 2))
X = torch.randn(200, 10)
y = torch.randint(0, 2, (200,))
loss_fn = nn.CrossEntropyLoss()

# 不同调度策略
schedulers = {
    "Constant": lambda opt: None,
    "StepLR(5,0.5)": lambda opt: torch.optim.lr_scheduler.StepLR(opt, 5, 0.5),
    "CosineAnnealing": lambda opt: torch.optim.lr_scheduler.CosineAnnealingLR(opt, T_max=20),
    "ExpLR(0.9)": lambda opt: torch.optim.lr_scheduler.ExponentialLR(opt, 0.9),
    "OneCycleLR": lambda opt: torch.optim.lr_scheduler.OneCycleLR(opt, max_lr=0.1, total_steps=20),
}

for name, sched_fn in schedulers.items():
    torch.manual_seed(42)
    model_new = nn.Sequential(nn.Linear(10, 64), nn.ReLU(), nn.Linear(64, 2))
    opt = torch.optim.SGD(model_new.parameters(), lr=0.01)
    sched = sched_fn(opt)
    
    lrs = []
    losses = []
    for epoch in range(20):
        opt.zero_grad()
        loss = loss_fn(model_new(X), y)
        loss.backward()
        opt.step()
        if sched is not None:
            sched.step()
        lrs.append(opt.param_groups[0]['lr'])
        losses.append(loss.item())
    
    print(f"{name:>20}: loss={losses[0]:.4f}→{losses[-1]:.4f}, lr={lrs[0]:.6f}→{lrs[-1]:.6f}")

# Warmup实现
class WarmupCosineScheduler:
    def __init__(self, optimizer, warmup_steps, total_steps, lr_max, lr_min=0):
        self.optimizer = optimizer
        self.warmup_steps = warmup_steps
        self.total_steps = total_steps
        self.lr_max = lr_max
        self.lr_min = lr_min
        self.step_count = 0
    
    def step(self):
        self.step_count += 1
        if self.step_count <= self.warmup_steps:
            lr = self.lr_max * self.step_count / self.warmup_steps
        else:
            progress = (self.step_count - self.warmup_steps) / (self.total_steps - self.warmup_steps)
            lr = self.lr_min + 0.5 * (self.lr_max - self.lr_min) * (1 + math.cos(math.pi * progress))
        for param_group in self.optimizer.param_groups:
            param_group['lr'] = lr

# Warmup效果
print("\n=== Warmup + Cosine Decay ===")
torch.manual_seed(42)
model_warmup = nn.Sequential(nn.Linear(10, 64), nn.ReLU(), nn.Linear(64, 2))
opt = torch.optim.SGD(model_warmup.parameters(), lr=0.0)
sched = WarmupCosineScheduler(opt, warmup_steps=5, total_steps=50, lr_max=0.01)

lrs = []
for step in range(50):
    opt.zero_grad()
    loss = loss_fn(model_warmup(X), y)
    loss.backward()
    opt.step()
    sched.step()
    lrs.append(opt.param_groups[0]['lr'])

print(f"LR变化: {lrs[0]:.6f}(step0) → {max(lrs):.6f}(peak) → {lrs[-1]:.6f}(end)")
warmup_lrs = lrs[:6]
print(f"Warmup阶段: {' → '.join([f'{lr:.6f}' for lr in warmup_lrs])}")
🟢 运行结果 ✅验证通过 Constant: loss=0.7136→0.6997, lr=0.010000→0.010000 StepLR(5,0.5): loss=0.7136→0.7053, lr=0.010000→0.000625 CosineAnnealing: loss=0.7136→0.7045, lr=0.009938→0.000000 ExpLR(0.9): loss=0.7136→0.7058, lr=0.009000→0.001216 OneCycleLR: loss=0.7136→0.6567, lr=0.013167→0.001254 === Warmup + Cosine Decay === LR变化: 0.002000(step0) → 0.010000(peak) → 0.000000(end) Warmup阶段: 0.002000 → 0.004000 → 0.006000 → 0.008000 → 0.010000 → 0.009988

🔬 深入拓展

核心要点回顾

本课的核心知识点构成了训练技巧学习的重要一环。让我们从更高维度审视这些知识之间的关系:

常见陷阱与最佳实践

⚠️ 初学者常犯的错误:

💡 最佳实践:

与前后课程的联系

深度学习是一个整体——每一课的知识都不是孤立的:

📖 延伸阅读

💡 继续深入的学习路径:

📝 练习

练习1:自定义调度器

实现余弦重启(Cosine Annealing with Warm Restarts)调度器。

练习2:学习率Finder

实现LR Range Test,找到最优初始学习率。

练习3:调度器组合

实现Warmup + Cosine Decay + 梯度累积的组合策略。

💡 学习率调度实践

调度器选择

常见错误与解决方案

⚠️ 需要避免的典型错误:

  1. 不了解模型假设就盲目使用
  2. 没有建立基线就追求复杂方法
  3. 忽视数据质量和预处理
  4. 过度调参而不理解原理
  5. 只看训练指标忽略验证指标

性能优化建议

💡 提升模型性能的系统方法:

  1. 确保数据管道正确且高效
  2. 建立简单但正确的基线模型
  3. 分析基线的错误类型
  4. 针对性地改进(数据/模型/训练)
  5. 持续迭代,每步验证

🔬 深度拓展:从理论到实践

核心概念网络

理解本课内容需要将其置于更大的知识网络中。每个核心概念都不是孤立的,它们相互关联、相互支撑:

关键洞察与直觉

建立正确的直觉比记住公式更重要:

1. 维度直觉:高维空间中,数据分布与低维直觉截然不同(维度诅咒)

2. 信息瓶颈:神经网络逐层压缩信息,保留任务相关的、丢弃无关的

3. 流形假设:高维数据实际分布在低维流形上,学习即发现流形结构

4. 偏差-方差权衡:简单模型欠拟合(高偏差),复杂模型过拟合(高方差)

与其他课程的关联

本课作为训练技巧阶段的核心内容,与前后课程紧密关联:

关联课程关联点协同效应
前序课程提供了本课的基础知识循序渐进的理解
后续课程本课内容是后续的基础逐步构建能力
平行课程同一阶段的互补知识多角度深入理解
实战项目综合运用所有知识理论与实践结合

面试常见问题

💡 准备面试时,确保能回答以下问题:

  1. 用简单语言解释本课核心概念
  2. 画出关键算法/结构的流程图
  3. 比较不同方法的优缺点
  4. 举出实际应用场景
  5. 讨论常见误解和注意事项

进阶学习路径

掌握本课内容后,可以通过以下方式继续深入:

📅

成就解锁:调度工程师

学习率调度让训练更稳定更高效——时机的艺术!