PyTorch Optimizer 与 Scheduler 指南

PyTorch Optimizer 与 Scheduler 指南


📑 目录

  1. 背景与动机
  2. 核心概念与定义
  3. [Optimizer 深入理解](#Optimizer 深入理解)
  4. [Scheduler 深入理解](#Scheduler 深入理解)
  5. [Optimizer 与 Scheduler 的关系](#Optimizer 与 Scheduler 的关系)
  6. [常用 Scheduler 详解](#常用 Scheduler 详解)
  7. 训练循环集成
  8. [PyTorch Lightning 集成](#PyTorch Lightning 集成)
  9. 高级技巧与策略
  10. 常见问题与最佳实践
  11. 扩展阅读与进阶方向

1. 背景与动机

1.1 为什么需要学习率调度?

在深度学习训练中,学习率(Learning Rate) 是最重要的超参数之一。

问题场景

固定学习率的局限

python 复制代码
# 使用固定学习率训练
optimizer = torch.optim.SGD(model.parameters(), lr=0.1)

# 问题:
# 1. 训练初期:学习率太大 → 震荡、不稳定
# 2. 训练后期:学习率太大 → 难以收敛到最优点
# 3. 全程使用:无法适应训练的不同阶段

训练曲线示意

复制代码
Loss
 │
 │  固定学习率(lr=0.1)
 │    ╱╲  ╱╲  ╱╲  ╱╲
 │   ╱  ╲╱  ╲╱  ╲╱  ╲  ← 后期震荡,难以收敛
 │  ╱
 │ ╱
 │╱
 └────────────────────> Epochs
 
 │  动态学习率(使用 Scheduler)
 │  ╱╲
 │ ╱  ╲___________  ← 后期学习率降低,平滑收敛
 │╱
 └────────────────────> Epochs

1.2 Scheduler 的核心价值

优势 说明
加速收敛 初期大学习率快速下降 loss
提升性能 后期小学习率精细调优
避免震荡 动态调整避免参数更新过大
泛化能力 特定策略(如余弦退火)提升泛化
自动化 无需手动调整学习率

1.3 实际案例

ImageNet 训练典型策略

python 复制代码
# ResNet 训练方案(论文标准)
optimizer = SGD(model.parameters(), lr=0.1, momentum=0.9)
scheduler = MultiStepLR(optimizer, milestones=[30, 60, 90], gamma=0.1)

# 学习率变化:
# Epoch 0-29:   lr = 0.1
# Epoch 30-59:  lr = 0.01   (降低 10 倍)
# Epoch 60-89:  lr = 0.001  (再降低 10 倍)
# Epoch 90+:    lr = 0.0001

2. 核心概念与定义

2.1 什么是 Optimizer?

Optimizer(优化器) 是根据损失函数的梯度来更新模型参数的算法。

核心任务

复制代码
参数更新公式(简化版):
θ_new = θ_old - lr × gradient

其中:
- θ: 模型参数
- lr: 学习率
- gradient: 梯度(损失函数对参数的偏导数)

常见 Optimizer

  • SGD: 随机梯度下降
  • Adam: 自适应学习率优化器
  • AdamW: 修正权重衰减的 Adam
  • RMSprop: 自适应学习率方法

2.2 什么是 Scheduler?

Scheduler(学习率调度器) 是动态调整 Optimizer 学习率的策略。

核心任务

复制代码
在训练过程中,根据预定规则调整学习率:
lr(epoch) = f(initial_lr, epoch, ...)

常见策略:
- 阶梯式衰减(StepLR)
- 指数衰减(ExponentialLR)
- 余弦退火(CosineAnnealingLR)
- 基于指标(ReduceLROnPlateau)

2.3 两者的关系

复制代码
关系模型:

┌─────────────────────────────────────┐
│         Training Loop               │
│                                     │
│  ┌──────────────┐                  │
│  │   Model      │                  │
│  └──────┬───────┘                  │
│         │                          │
│         ▼                          │
│  ┌──────────────┐                  │
│  │ Loss & Grad  │                  │
│  └──────┬───────┘                  │
│         │                          │
│         ▼                          │
│  ┌──────────────┐                  │
│  │  Optimizer   │ ◄─────┐          │
│  │  (更新参数)   │       │          │
│  └──────┬───────┘       │          │
│         │            读取/修改 lr   │
│         │               │          │
│  ┌──────▼──────────────┴──┐        │
│  │     Scheduler          │        │
│  │  (调整学习率)          │        │
│  └────────────────────────┘        │
│                                     │
└─────────────────────────────────────┘

关键点:
1. Scheduler 不直接更新参数
2. Scheduler 通过修改 Optimizer 的学习率来影响训练
3. 一个 Optimizer 可以配合多个 Scheduler(链式调度)

3. Optimizer 深入理解

3.1 Optimizer 的内部结构

python 复制代码
import torch.optim as optim

# 创建 Optimizer
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)

# 查看内部结构
print(optimizer.state_dict())
# 输出:
# {
#   'state': {},  # 优化器状态(如动量)
#   'param_groups': [
#       {
#           'lr': 0.01,
#           'momentum': 0.9,
#           'params': [参数ID列表],
#           ...
#       }
#   ]
# }

关键组成部分

组件 作用 示例
param_groups 参数组列表,每组有独立的超参数 不同层使用不同学习率
lr 学习率 0.01
state 优化器内部状态 Adam 的一阶、二阶动量
params 要优化的参数 model.parameters()

3.2 param_groups 详解

param_groups 是 Scheduler 修改学习率的核心

python 复制代码
# 单个参数组
optimizer = optim.Adam(model.parameters(), lr=0.001)
print(len(optimizer.param_groups))  # 输出: 1

# 访问学习率
current_lr = optimizer.param_groups[0]['lr']
print(f"当前学习率: {current_lr}")

# 手动修改学习率(Scheduler 就是这样做的)
optimizer.param_groups[0]['lr'] = 0.0001

多参数组示例(不同层不同学习率):

python 复制代码
optimizer = optim.SGD([
    {'params': model.base.parameters(), 'lr': 1e-3},  # 参数组 0
    {'params': model.classifier.parameters(), 'lr': 1e-2}  # 参数组 1
], momentum=0.9)

print(len(optimizer.param_groups))  # 输出: 2

# Scheduler 会同时调整两个参数组的学习率

3.3 常用 Optimizer 对比

Optimizer 特点 适用场景 学习率敏感度
SGD 简单、稳定 CV 任务、需要最佳性能 高(需精细调参)
SGD + Momentum 加速收敛、减少震荡 大部分任务
Adam 自适应学习率、快速收敛 NLP、快速原型
AdamW 修正权重衰减 Transformer 模型
RMSprop 适应不同梯度尺度 RNN、强化学习

4. Scheduler 深入理解

4.1 Scheduler 的工作原理

核心机制 :通过修改 optimizer.param_groups[i]['lr'] 来调整学习率。

python 复制代码
# Scheduler 的简化实现
class SimpleScheduler:
    def __init__(self, optimizer, gamma=0.1):
        self.optimizer = optimizer
        self.gamma = gamma
    
    def step(self):
        """每次调用时降低学习率"""
        for param_group in self.optimizer.param_groups:
            param_group['lr'] *= self.gamma
            print(f"学习率更新为: {param_group['lr']}")

# 使用
optimizer = optim.SGD(model.parameters(), lr=0.1)
scheduler = SimpleScheduler(optimizer, gamma=0.1)

scheduler.step()  # lr: 0.1 → 0.01
scheduler.step()  # lr: 0.01 → 0.001

4.2 Scheduler 的分类

复制代码
Scheduler 分类
│
├─ 基于 Epoch 的调度
│  ├─ StepLR (阶梯式)
│  ├─ MultiStepLR (多阶梯)
│  ├─ ExponentialLR (指数衰减)
│  ├─ CosineAnnealingLR (余弦退火)
│  └─ PolynomialLR (多项式)
│
├─ 基于指标的调度
│  └─ ReduceLROnPlateau (性能停滞时降低)
│
├─ 循环调度
│  ├─ CyclicLR (周期性变化)
│  └─ OneCycleLR (单周期策略)
│
└─ 链式调度
   └─ ChainedScheduler (组合多个 Scheduler)

4.3 调用时机

Scheduler 类型 调用位置 调用时机 示例
基于 Epoch epoch 结束后 scheduler.step() StepLR, CosineAnnealingLR
基于 Step 每个 batch 后 scheduler.step() OneCycleLR
基于指标 validation 后 scheduler.step(metric) ReduceLROnPlateau

5. Optimizer 与 Scheduler 的关系

5.1 依赖关系

python 复制代码
# Scheduler 依赖于 Optimizer
optimizer = optim.Adam(model.parameters(), lr=0.001)
scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.1)
                                      # ↑ 必须传入 optimizer

# Scheduler 保存了对 Optimizer 的引用
print(scheduler.optimizer is optimizer)  # True

5.2 协作流程

python 复制代码
# 完整训练循环
for epoch in range(num_epochs):
    # 1. 训练阶段
    for batch in train_loader:
        optimizer.zero_grad()        # 清零梯度
        output = model(batch)
        loss = criterion(output, target)
        loss.backward()              # 计算梯度
        optimizer.step()             # 更新参数(使用当前 lr)
    
    # 2. 验证阶段
    val_loss = validate(model, val_loader)
    
    # 3. 学习率调度
    scheduler.step()                 # 调整学习率(for next epoch)
    
    # 4. 日志记录
    current_lr = optimizer.param_groups[0]['lr']
    print(f"Epoch {epoch}, LR: {current_lr}, Val Loss: {val_loss}")

5.3 数据流向

复制代码
训练迭代中的数据流:

Epoch N:
  Train:  optimizer.step() with lr=0.01
  Val:    compute val_loss
  Update: scheduler.step() → lr 变为 0.001
  
Epoch N+1:
  Train:  optimizer.step() with lr=0.001  ← 使用新学习率
  ...

5.4 关键原理

Scheduler 如何修改学习率

python 复制代码
# 查看 PyTorch 源码(简化版)
class StepLR:
    def __init__(self, optimizer, step_size, gamma=0.1):
        self.optimizer = optimizer
        self.step_size = step_size
        self.gamma = gamma
        self.last_epoch = 0
        
        # 保存初始学习率
        self.base_lrs = [group['lr'] for group in optimizer.param_groups]
    
    def step(self):
        self.last_epoch += 1
        
        # 计算新学习率
        if self.last_epoch % self.step_size == 0:
            for i, param_group in enumerate(self.optimizer.param_groups):
                # 直接修改 optimizer 的 lr
                param_group['lr'] = self.base_lrs[i] * (self.gamma ** (self.last_epoch // self.step_size))

6. 常用 Scheduler 详解

6.1 StepLR - 阶梯式衰减

原理:每隔固定 epoch 数,学习率乘以 gamma。

python 复制代码
from torch.optim.lr_scheduler import StepLR

optimizer = optim.SGD(model.parameters(), lr=0.1)
scheduler = StepLR(
    optimizer,
    step_size=10,    # 每 10 个 epoch 降低一次
    gamma=0.1        # 每次降为原来的 0.1 倍
)

# 学习率变化:
# Epoch 0-9:   lr = 0.1
# Epoch 10-19: lr = 0.01
# Epoch 20-29: lr = 0.001
# Epoch 30+:   lr = 0.0001

可视化

复制代码
lr
0.1 │████████████
    │
0.01│            ████████████
    │
0.001           │            ████████████
    └────────────┴────────────┴────────────> Epoch
         10           20           30

适用场景

  • 训练周期较长的任务
  • 需要明确的学习率下降节点

6.2 MultiStepLR - 多阶梯衰减

原理:在指定的 epoch 降低学习率。

python 复制代码
from torch.optim.lr_scheduler import MultiStepLR

scheduler = MultiStepLR(
    optimizer,
    milestones=[30, 60, 90],  # 在这些 epoch 降低
    gamma=0.1
)

# 学习率变化:
# Epoch 0-29:  lr = 0.1
# Epoch 30-59: lr = 0.01
# Epoch 60-89: lr = 0.001
# Epoch 90+:   lr = 0.0001

适用场景

  • 复现论文配置(如 ResNet 训练)
  • 需要灵活控制降低时机

6.3 ExponentialLR - 指数衰减

原理:每个 epoch 学习率乘以 gamma。

python 复制代码
from torch.optim.lr_scheduler import ExponentialLR

scheduler = ExponentialLR(optimizer, gamma=0.95)

# 学习率变化:
# Epoch 0: lr = 0.1
# Epoch 1: lr = 0.1 × 0.95 = 0.095
# Epoch 2: lr = 0.095 × 0.95 = 0.09025
# ...
# Epoch n: lr = 0.1 × (0.95^n)

可视化

复制代码
lr
0.1 │╲
    │ ╲___
    │     ╲___
    │         ╲___
0.0 └─────────────────> Epoch

适用场景

  • 需要平滑衰减
  • 长期训练任务

6.4 CosineAnnealingLR - 余弦退火

原理:学习率按余弦函数变化。

python 复制代码
from torch.optim.lr_scheduler import CosineAnnealingLR

scheduler = CosineAnnealingLR(
    optimizer,
    T_max=100,       # 周期长度(epoch 数)
    eta_min=1e-6     # 最小学习率
)

# 学习率公式:
# lr(epoch) = eta_min + (lr_initial - eta_min) * (1 + cos(π × epoch / T_max)) / 2

可视化

复制代码
lr
0.1 │╲       ╱
    │ ╲     ╱
    │  ╲   ╱
    │   ╲ ╱
0.0 └────▼─────────> Epoch
         T_max

适用场景

  • Transformer 训练(BERT、GPT)
  • 需要在训练末期探索更好的局部最优
  • 周期性任务

优势

  • 平滑过渡
  • 后期缓慢下降利于收敛

6.5 ReduceLROnPlateau - 基于指标自适应

原理:当监控指标停滞时降低学习率。

python 复制代码
from torch.optim.lr_scheduler import ReduceLROnPlateau

scheduler = ReduceLROnPlateau(
    optimizer,
    mode='min',          # 'min' 或 'max'
    factor=0.1,          # 降低倍数
    patience=10,         # 容忍多少 epoch 不改善
    threshold=1e-4,      # 改善的最小阈值
    verbose=True
)

# 使用方式不同:需要传入指标
for epoch in range(num_epochs):
    train(...)
    val_loss = validate(...)
    scheduler.step(val_loss)  # ← 传入验证指标

工作逻辑

复制代码
Epoch 1-10:  val_loss 持续下降 → lr 保持 0.1
Epoch 11-20: val_loss 停滞不降 → 等待(patience)
Epoch 21:    超过 patience → lr 降为 0.01
...

适用场景

  • 不确定何时降低学习率
  • 基于验证集性能自适应
  • 调试阶段

6.6 OneCycleLR - 单周期策略

原理:学习率先增后减,配合动量变化。

python 复制代码
from torch.optim.lr_scheduler import OneCycleLR

scheduler = OneCycleLR(
    optimizer,
    max_lr=0.1,              # 最大学习率
    total_steps=len(train_loader) * num_epochs,  # 总步数
    pct_start=0.3,           # 增长阶段占比(30%)
    anneal_strategy='cos',   # 'cos' 或 'linear'
    div_factor=25,           # 初始 lr = max_lr / div_factor
    final_div_factor=1e4     # 最终 lr = max_lr / final_div_factor
)

# 在每个 batch 后调用
for epoch in range(num_epochs):
    for batch in train_loader:
        optimizer.zero_grad()
        loss = ...
        loss.backward()
        optimizer.step()
        scheduler.step()  # ← 每个 step 调用

学习率曲线

复制代码
lr
    │      ╱╲
0.1 │     ╱  ╲
    │    ╱    ╲
    │   ╱      ╲___
    │  ╱           ╲___
    │ ╱                ╲___
0.0 └────────────────────────> Steps
      增长  峰值     衰减
      30%   点      70%

适用场景

  • 快速收敛(fastai 推荐)
  • 训练周期较短的任务
  • 配合较大 batch size

6.7 CyclicLR - 周期性学习率

原理:学习率在 base_lr 和 max_lr 之间周期性变化。

python 复制代码
from torch.optim.lr_scheduler import CyclicLR

scheduler = CyclicLR(
    optimizer,
    base_lr=0.001,
    max_lr=0.1,
    step_size_up=2000,     # 上升阶段步数
    mode='triangular',     # 'triangular', 'triangular2', 'exp_range'
)

# 每个 batch 后调用
for batch in train_loader:
    ...
    scheduler.step()

模式对比

复制代码
triangular (三角波):
    ╱╲  ╱╲  ╱╲
   ╱  ╲╱  ╲╱  ╲

triangular2 (递减三角):
    ╱╲  ╱╲ ╱
   ╱  ╲╱  ▼

exp_range (指数):
    ╱╲ ╱╲╱
   ╱  ▼

适用场景

  • 避免陷入局部最优
  • 探索不同学习率区间

6.8 Scheduler 对比表

Scheduler 调用时机 主要参数 适用场景 学习率变化
StepLR epoch 结束 step_size, gamma 简单任务 阶梯式
MultiStepLR epoch 结束 milestones, gamma 论文复现 多阶梯
ExponentialLR epoch 结束 gamma 长期训练 指数衰减
CosineAnnealingLR epoch 结束 T_max, eta_min Transformer 余弦曲线
ReduceLROnPlateau validation 后 patience, factor 自适应场景 基于指标
OneCycleLR 每个 batch max_lr, total_steps 快速收敛 单周期
CyclicLR 每个 batch base_lr, max_lr 探索最优 周期性

7. 训练循环集成

7.1 基础训练循环(基于 Epoch 的 Scheduler)

python 复制代码
import torch
import torch.nn as nn
import torch.optim as optim
from torch.optim.lr_scheduler import CosineAnnealingLR

# 1. 准备模型、优化器、调度器
model = MyModel()
optimizer = optim.Adam(model.parameters(), lr=0.001)
scheduler = CosineAnnealingLR(optimizer, T_max=100)

criterion = nn.CrossEntropyLoss()

# 2. 训练循环
num_epochs = 100
for epoch in range(num_epochs):
    # ========== 训练阶段 ==========
    model.train()
    train_loss = 0.0
    
    for batch_idx, (data, target) in enumerate(train_loader):
        # 前向传播
        output = model(data)
        loss = criterion(output, target)
        
        # 反向传播
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        
        train_loss += loss.item()
    
    avg_train_loss = train_loss / len(train_loader)
    
    # ========== 验证阶段 ==========
    model.eval()
    val_loss = 0.0
    
    with torch.no_grad():
        for data, target in val_loader:
            output = model(data)
            loss = criterion(output, target)
            val_loss += loss.item()
    
    avg_val_loss = val_loss / len(val_loader)
    
    # ========== 学习率调度 ==========
    scheduler.step()  # 调整学习率
    
    # ========== 日志记录 ==========
    current_lr = optimizer.param_groups[0]['lr']
    print(f"Epoch {epoch+1}/{num_epochs}")
    print(f"  Train Loss: {avg_train_loss:.4f}")
    print(f"  Val Loss: {avg_val_loss:.4f}")
    print(f"  Learning Rate: {current_lr:.6f}")

7.2 使用 ReduceLROnPlateau

python 复制代码
from torch.optim.lr_scheduler import ReduceLROnPlateau

optimizer = optim.Adam(model.parameters(), lr=0.001)
scheduler = ReduceLROnPlateau(
    optimizer, 
    mode='min', 
    factor=0.5, 
    patience=5,
    verbose=True
)

for epoch in range(num_epochs):
    # 训练
    train_loss = train_epoch(model, train_loader, optimizer, criterion)
    
    # 验证
    val_loss = validate(model, val_loader, criterion)
    
    # 学习率调度(传入验证指标)
    scheduler.step(val_loss)  # ← 关键:传入 metric
    
    # 日志
    current_lr = optimizer.param_groups[0]['lr']
    print(f"Epoch {epoch}, Val Loss: {val_loss:.4f}, LR: {current_lr:.6f}")

7.3 使用 OneCycleLR(基于 Step)

python 复制代码
from torch.optim.lr_scheduler import OneCycleLR

# 计算总步数
total_steps = len(train_loader) * num_epochs

optimizer = optim.SGD(model.parameters(), lr=0.1, momentum=0.9)
scheduler = OneCycleLR(
    optimizer,
    max_lr=0.1,
    total_steps=total_steps,
    pct_start=0.3
)

for epoch in range(num_epochs):
    model.train()
    
    for batch_idx, (data, target) in enumerate(train_loader):
        optimizer.zero_grad()
        output = model(data)
        loss = criterion(output, target)
        loss.backward()
        optimizer.step()
        
        # 每个 batch 后调用
        scheduler.step()  # ← 关键:每步调用
        
        # 可选:打印当前学习率
        if batch_idx % 100 == 0:
            current_lr = optimizer.param_groups[0]['lr']
            print(f"Epoch {epoch}, Batch {batch_idx}, LR: {current_lr:.6f}")

7.4 链式 Scheduler(组合多个策略)

python 复制代码
from torch.optim.lr_scheduler import SequentialLR, LinearLR, CosineAnnealingLR

# 前 10 个 epoch 线性增长(warmup),之后余弦退火
scheduler1 = LinearLR(optimizer, start_factor=0.1, total_iters=10)
scheduler2 = CosineAnnealingLR(optimizer, T_max=90)

scheduler = SequentialLR(
    optimizer,
    schedulers=[scheduler1, scheduler2],
    milestones=[10]  # 在 epoch 10 切换
)

for epoch in range(100):
    train(...)
    scheduler.step()

7.5 完整示例:ResNet 训练配置

python 复制代码
import torch
import torch.nn as nn
import torch.optim as optim
from torch.optim.lr_scheduler import MultiStepLR
from torchvision.models import resnet50

# 1. 模型和数据
model = resnet50(pretrained=False, num_classes=10)
train_loader = ...  # 你的数据加载器
val_loader = ...

# 2. 优化器配置(ImageNet 标准)
optimizer = optim.SGD(
    model.parameters(),
    lr=0.1,
    momentum=0.9,
    weight_decay=1e-4
)

# 3. 学习率调度器(ImageNet 标准)
scheduler = MultiStepLR(
    optimizer,
    milestones=[30, 60, 90],
    gamma=0.1
)

# 4. 损失函数
criterion = nn.CrossEntropyLoss()

# 5. 训练循环
num_epochs = 100
best_acc = 0.0

for epoch in range(num_epochs):
    # 训练
    model.train()
    for data, target in train_loader:
        optimizer.zero_grad()
        output = model(data)
        loss = criterion(output, target)
        loss.backward()
        optimizer.step()
    
    # 验证
    model.eval()
    correct = 0
    total = 0
    with torch.no_grad():
        for data, target in val_loader:
            output = model(data)
            _, predicted = output.max(1)
            total += target.size(0)
            correct += predicted.eq(target).sum().item()
    
    acc = 100. * correct / total
    
    # 学习率调度
    scheduler.step()
    
    # 保存最佳模型
    if acc > best_acc:
        best_acc = acc
        torch.save(model.state_dict(), 'best_model.pth')
    
    # 日志
    current_lr = optimizer.param_groups[0]['lr']
    print(f"Epoch {epoch+1}/{num_epochs}")
    print(f"  Accuracy: {acc:.2f}%")
    print(f"  Best Accuracy: {best_acc:.2f}%")
    print(f"  Learning Rate: {current_lr}")

8. PyTorch Lightning 集成

8.1 基础配置方法

在 PyTorch Lightning 中,通过 configure_optimizers() 方法返回 Optimizer 和 Scheduler。

python 复制代码
import pytorch_lightning as pl
import torch.optim as optim
from torch.optim.lr_scheduler import CosineAnnealingLR

class MyLightningModel(pl.LightningModule):
    def __init__(self, lr=0.001):
        super().__init__()
        self.lr = lr
        self.model = ...  # 你的模型
    
    def configure_optimizers(self):
        # 方式1:仅返回 optimizer
        optimizer = optim.Adam(self.parameters(), lr=self.lr)
        return optimizer
    
    # 其他方法:training_step, validation_step, etc.

8.2 配置 Optimizer + Scheduler

python 复制代码
class MyLightningModel(pl.LightningModule):
    def configure_optimizers(self):
        optimizer = optim.Adam(self.parameters(), lr=0.001)
        scheduler = CosineAnnealingLR(optimizer, T_max=100)
        
        # 返回字典格式
        return {
            'optimizer': optimizer,
            'lr_scheduler': {
                'scheduler': scheduler,
                'interval': 'epoch',  # 'epoch' 或 'step'
                'frequency': 1,       # 每隔多少 interval 调用一次
                'monitor': 'val_loss',  # 用于 ReduceLROnPlateau
            }
        }

8.3 完整配置选项

python 复制代码
def configure_optimizers(self):
    optimizer = optim.SGD(self.parameters(), lr=0.1, momentum=0.9)
    scheduler = MultiStepLR(optimizer, milestones=[30, 60], gamma=0.1)
    
    return {
        'optimizer': optimizer,
        'lr_scheduler': {
            'scheduler': scheduler,
            
            # 调用时机
            'interval': 'epoch',      # 'epoch' 或 'step'
            'frequency': 1,           # 每 N 个 interval 调用一次
            
            # 用于 ReduceLROnPlateau
            'monitor': 'val_loss',    # 监控的指标
            'strict': True,           # 如果 monitor 不存在是否报错
            
            # 其他
            'name': 'my_scheduler',   # TensorBoard 中显示的名称
        }
    }

8.4 使用 ReduceLROnPlateau

python 复制代码
from torch.optim.lr_scheduler import ReduceLROnPlateau

class MyModel(pl.LightningModule):
    def configure_optimizers(self):
        optimizer = optim.Adam(self.parameters(), lr=0.001)
        scheduler = ReduceLROnPlateau(
            optimizer, 
            mode='min', 
            factor=0.5, 
            patience=10
        )
        
        return {
            'optimizer': optimizer,
            'lr_scheduler': {
                'scheduler': scheduler,
                'monitor': 'val_loss',  # 关键:必须指定 monitor
                'interval': 'epoch',
            }
        }
    
    def validation_step(self, batch, batch_idx):
        # 确保记录了 val_loss
        loss = ...
        self.log('val_loss', loss)  # ← 必须记录
        return loss

8.5 使用 OneCycleLR

python 复制代码
from torch.optim.lr_scheduler import OneCycleLR

class MyModel(pl.LightningModule):
    def __init__(self, total_steps):
        super().__init__()
        self.total_steps = total_steps
    
    def configure_optimizers(self):
        optimizer = optim.SGD(self.parameters(), lr=0.1, momentum=0.9)
        scheduler = OneCycleLR(
            optimizer,
            max_lr=0.1,
            total_steps=self.total_steps,
        )
        
        return {
            'optimizer': optimizer,
            'lr_scheduler': {
                'scheduler': scheduler,
                'interval': 'step',  # 关键:每个 step 调用
            }
        }

# 使用时计算 total_steps
total_steps = len(train_loader) * num_epochs
model = MyModel(total_steps=total_steps)
trainer = pl.Trainer(max_epochs=num_epochs)

8.6 多个 Optimizer 和 Scheduler

python 复制代码
class MyGAN(pl.LightningModule):
    def configure_optimizers(self):
        # 生成器优化器
        opt_g = optim.Adam(self.generator.parameters(), lr=0.0002)
        # 判别器优化器
        opt_d = optim.Adam(self.discriminator.parameters(), lr=0.0002)
        
        # 生成器调度器
        sch_g = CosineAnnealingLR(opt_g, T_max=100)
        # 判别器调度器
        sch_d = CosineAnnealingLR(opt_d, T_max=100)
        
        return [opt_g, opt_d], [sch_g, sch_d]

8.7 自动记录学习率

PyTorch Lightning 会自动记录学习率到日志(需要配合 LearningRateMonitor):

python 复制代码
from pytorch_lightning.callbacks import LearningRateMonitor

# 创建 Callback
lr_monitor = LearningRateMonitor(logging_interval='epoch')

# 训练
trainer = pl.Trainer(
    max_epochs=100,
    callbacks=[lr_monitor]
)
trainer.fit(model)

# 学习率会自动记录到 TensorBoard/WandB

8.8 完整 Lightning 示例

python 复制代码
import pytorch_lightning as pl
import torch
import torch.nn as nn
import torch.optim as optim
from torch.optim.lr_scheduler import CosineAnnealingLR
from pytorch_lightning.callbacks import ModelCheckpoint, LearningRateMonitor

class MyClassifier(pl.LightningModule):
    def __init__(self, input_dim, num_classes, lr=0.001):
        super().__init__()
        self.save_hyperparameters()
        
        self.model = nn.Sequential(
            nn.Linear(input_dim, 128),
            nn.ReLU(),
            nn.Linear(128, num_classes)
        )
        self.criterion = nn.CrossEntropyLoss()
    
    def forward(self, x):
        return self.model(x)
    
    def training_step(self, batch, batch_idx):
        x, y = batch
        y_hat = self(x)
        loss = self.criterion(y_hat, y)
        
        # 记录指标
        self.log('train_loss', loss, on_step=False, on_epoch=True)
        return loss
    
    def validation_step(self, batch, batch_idx):
        x, y = batch
        y_hat = self(x)
        loss = self.criterion(y_hat, y)
        
        acc = (y_hat.argmax(dim=1) == y).float().mean()
        
        # 记录指标
        self.log('val_loss', loss, prog_bar=True)
        self.log('val_acc', acc, prog_bar=True)
    
    def configure_optimizers(self):
        optimizer = optim.Adam(self.parameters(), lr=self.hparams.lr)
        scheduler = CosineAnnealingLR(optimizer, T_max=100)
        
        return {
            'optimizer': optimizer,
            'lr_scheduler': {
                'scheduler': scheduler,
                'interval': 'epoch',
            }
        }

# 使用
model = MyClassifier(input_dim=784, num_classes=10, lr=0.001)

trainer = pl.Trainer(
    max_epochs=100,
    callbacks=[
        ModelCheckpoint(monitor='val_loss', mode='min'),
        LearningRateMonitor(logging_interval='epoch'),
    ],
)

trainer.fit(model, train_loader, val_loader)

9. 高级技巧与策略

9.1 Warmup 策略

概念:训练初期使用较小的学习率,逐步增加到目标值,避免初期梯度过大导致不稳定。

方法 1:使用 LinearLR + SequentialLR
python 复制代码
from torch.optim.lr_scheduler import LinearLR, CosineAnnealingLR, SequentialLR

optimizer = optim.Adam(model.parameters(), lr=0.001)

# Warmup: 前 5 个 epoch 从 0.0001 线性增长到 0.001
warmup_scheduler = LinearLR(
    optimizer,
    start_factor=0.1,  # 初始 lr = 0.001 × 0.1 = 0.0001
    total_iters=5      # 5 个 epoch
)

# 主调度器
main_scheduler = CosineAnnealingLR(optimizer, T_max=95)

# 组合
scheduler = SequentialLR(
    optimizer,
    schedulers=[warmup_scheduler, main_scheduler],
    milestones=[5]  # 在 epoch 5 切换
)

# 使用
for epoch in range(100):
    train(...)
    scheduler.step()
方法 2:自定义 Warmup Scheduler
python 复制代码
class WarmupScheduler:
    """带 Warmup 的调度器"""
    
    def __init__(self, optimizer, warmup_epochs, base_scheduler):
        self.optimizer = optimizer
        self.warmup_epochs = warmup_epochs
        self.base_scheduler = base_scheduler
        self.current_epoch = 0
        
        # 保存初始学习率
        self.base_lrs = [group['lr'] for group in optimizer.param_groups]
    
    def step(self):
        if self.current_epoch < self.warmup_epochs:
            # Warmup 阶段:线性增长
            warmup_factor = (self.current_epoch + 1) / self.warmup_epochs
            for i, param_group in enumerate(self.optimizer.param_groups):
                param_group['lr'] = self.base_lrs[i] * warmup_factor
        else:
            # 主调度阶段
            self.base_scheduler.step()
        
        self.current_epoch += 1

# 使用
optimizer = optim.Adam(model.parameters(), lr=0.001)
base_scheduler = CosineAnnealingLR(optimizer, T_max=95)
scheduler = WarmupScheduler(optimizer, warmup_epochs=5, base_scheduler=base_scheduler)

for epoch in range(100):
    train(...)
    scheduler.step()
PyTorch Lightning 中的 Warmup
python 复制代码
from torch.optim.lr_scheduler import LambdaLR

class MyModel(pl.LightningModule):
    def configure_optimizers(self):
        optimizer = optim.Adam(self.parameters(), lr=0.001)
        
        # 使用 LambdaLR 实现 Warmup + Cosine
        def lr_lambda(epoch):
            warmup_epochs = 5
            max_epochs = 100
            
            if epoch < warmup_epochs:
                # Warmup
                return (epoch + 1) / warmup_epochs
            else:
                # Cosine Annealing
                progress = (epoch - warmup_epochs) / (max_epochs - warmup_epochs)
                return 0.5 * (1 + math.cos(math.pi * progress))
        
        scheduler = LambdaLR(optimizer, lr_lambda)
        
        return {'optimizer': optimizer, 'lr_scheduler': scheduler}

9.2 不同层不同学习率

概念:对模型不同部分使用不同的学习率(常用于迁移学习)。

python 复制代码
# 场景:微调预训练模型
import torchvision.models as models

model = models.resnet50(pretrained=True)

# 冻结早期层,仅微调后期层
for param in model.layer1.parameters():
    param.requires_grad = False
for param in model.layer2.parameters():
    param.requires_grad = False

# 不同层使用不同学习率
optimizer = optim.SGD([
    {'params': model.layer3.parameters(), 'lr': 1e-4},  # 小学习率
    {'params': model.layer4.parameters(), 'lr': 1e-3},  # 中等学习率
    {'params': model.fc.parameters(), 'lr': 1e-2}       # 大学习率
], momentum=0.9)

# Scheduler 会同时调整所有参数组的学习率
scheduler = StepLR(optimizer, step_size=10, gamma=0.1)

# 查看各组学习率
for i, param_group in enumerate(optimizer.param_groups):
    print(f"参数组 {i} 学习率: {param_group['lr']}")

PyTorch Lightning 中的实现

python 复制代码
class FineTuneModel(pl.LightningModule):
    def __init__(self):
        super().__init__()
        self.backbone = models.resnet50(pretrained=True)
        self.classifier = nn.Linear(2048, 10)
    
    def configure_optimizers(self):
        # 不同部分使用不同学习率
        optimizer = optim.Adam([
            {'params': self.backbone.parameters(), 'lr': 1e-4},
            {'params': self.classifier.parameters(), 'lr': 1e-3}
        ])
        
        scheduler = CosineAnnealingLR(optimizer, T_max=100)
        
        return {'optimizer': optimizer, 'lr_scheduler': scheduler}

9.3 梯度累积与学习率

当使用梯度累积时,可能需要调整学习率:

python 复制代码
# 等效 batch size = batch_size × accumulate_grad_batches
# 建议按比例调整学习率

accumulate_grad_batches = 4
base_lr = 0.001

# 调整学习率(线性缩放规则)
adjusted_lr = base_lr * accumulate_grad_batches

optimizer = optim.Adam(model.parameters(), lr=adjusted_lr)

在 PyTorch Lightning 中

python 复制代码
trainer = pl.Trainer(
    accumulate_grad_batches=4,  # 每 4 个 batch 更新一次
)

# 模型中相应调整学习率
class MyModel(pl.LightningModule):
    def configure_optimizers(self):
        # 考虑梯度累积的学习率
        accumulate = self.trainer.accumulate_grad_batches
        adjusted_lr = self.hparams.lr * accumulate
        
        optimizer = optim.Adam(self.parameters(), lr=adjusted_lr)
        # ...

9.4 学习率查找器(LR Finder)

概念:通过逐步增加学习率找到最优初始值。

python 复制代码
from torch_lr_finder import LRFinder

# 创建模型和优化器
model = MyModel()
optimizer = optim.Adam(model.parameters(), lr=1e-7)
criterion = nn.CrossEntropyLoss()

# LR Finder
lr_finder = LRFinder(model, optimizer, criterion)
lr_finder.range_test(train_loader, start_lr=1e-7, end_lr=10, num_iter=100)

# 绘制曲线
lr_finder.plot()  # 查看 loss vs lr 曲线

# 选择最优学习率(通常选择下降最快的点)
best_lr = lr_finder.history['lr'][lr_finder.history['loss'].index(min(lr_finder.history['loss']))]
print(f"建议学习率: {best_lr}")

# 重置模型
lr_finder.reset()

在 PyTorch Lightning 中

python 复制代码
from pytorch_lightning.tuner import Tuner

model = MyModel()
trainer = pl.Trainer()

# 自动查找学习率
tuner = Tuner(trainer)
lr_finder = tuner.lr_find(model, train_loader)

# 查看结果
fig = lr_finder.plot(suggest=True)
fig.show()

# 更新模型学习率
model.hparams.lr = lr_finder.suggestion()

9.5 周期性重启(Cosine Annealing with Warm Restarts)

python 复制代码
from torch.optim.lr_scheduler import CosineAnnealingWarmRestarts

optimizer = optim.SGD(model.parameters(), lr=0.1)
scheduler = CosineAnnealingWarmRestarts(
    optimizer,
    T_0=10,      # 第一个周期的长度
    T_mult=2,    # 每次重启后周期长度乘以的倍数
    eta_min=1e-6 # 最小学习率
)

# 学习率变化:
# Epoch 0-9:   第一个周期(余弦下降)
# Epoch 10-29: 第二个周期(长度 × 2 = 20)
# Epoch 30-69: 第三个周期(长度 × 2 = 40)

学习率曲线

复制代码
lr
    │╲    ╱╲        ╱╲
0.1 │ ╲  ╱  ╲      ╱  ╲
    │  ╲╱    ╲    ╱    ╲
    │   ▼     ╲  ╱      ╲___
    │          ╲╱
0.0 └────────────────────────────> Epoch
       10      30         70
       ↑       ↑          ↑
      重启    重启        重启

10. 常见问题与最佳实践

10.1 常见错误

错误 1:Scheduler 调用时机错误
python 复制代码
# ❌ 错误:在 optimizer.step() 之前调用
optimizer.step()
scheduler.step()  # 正确位置

scheduler.step()  # ❌ 错误位置
optimizer.step()

# ✅ 正确顺序
for epoch in range(num_epochs):
    for batch in train_loader:
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()  # 先更新参数
    scheduler.step()      # 再调整学习率
错误 2:忘记调用 scheduler.step()
python 复制代码
# ❌ 错误:创建了 Scheduler 但忘记调用
scheduler = StepLR(optimizer, step_size=10)

for epoch in range(num_epochs):
    train(...)
    # 忘记调用 scheduler.step()

# 结果:学习率始终不变
错误 3:ReduceLROnPlateau 没有传入 metric
python 复制代码
# ❌ 错误
scheduler = ReduceLROnPlateau(optimizer, mode='min')
scheduler.step()  # 缺少参数

# ✅ 正确
val_loss = validate(...)
scheduler.step(val_loss)
错误 4:OneCycleLR 使用错误的调用频率
python 复制代码
# ❌ 错误:OneCycleLR 应该每个 batch 调用,而非每个 epoch
scheduler = OneCycleLR(optimizer, max_lr=0.1, total_steps=total_steps)

for epoch in range(num_epochs):
    train(...)
    scheduler.step()  # ❌ 错误:应该在 batch 循环内

# ✅ 正确
for epoch in range(num_epochs):
    for batch in train_loader:
        ...
        optimizer.step()
        scheduler.step()  # ✅ 每个 batch 调用
错误 5:修改学习率后没有更新 Scheduler
python 复制代码
# ❌ 错误:手动修改学习率会导致 Scheduler 失效
optimizer.param_groups[0]['lr'] = 0.0001  # 手动修改
scheduler.step()  # Scheduler 基于旧的 base_lr 计算

# ✅ 正确:重新创建 Scheduler
optimizer.param_groups[0]['lr'] = 0.0001
scheduler = StepLR(optimizer, step_size=10)

10.2 调试技巧

技巧 1:打印学习率变化
python 复制代码
class LRLogger:
    """记录学习率变化"""
    def __init__(self, optimizer):
        self.optimizer = optimizer
        self.lr_history = []
    
    def log(self, epoch):
        lr = self.optimizer.param_groups[0]['lr']
        self.lr_history.append(lr)
        print(f"Epoch {epoch}, LR: {lr:.6f}")
    
    def plot(self):
        import matplotlib.pyplot as plt
        plt.plot(self.lr_history)
        plt.xlabel('Epoch')
        plt.ylabel('Learning Rate')
        plt.title('Learning Rate Schedule')
        plt.show()

# 使用
logger = LRLogger(optimizer)

for epoch in range(num_epochs):
    train(...)
    scheduler.step()
    logger.log(epoch)

logger.plot()
技巧 2:验证 Scheduler 配置
python 复制代码
def verify_scheduler(optimizer, scheduler, num_epochs=20):
    """验证 Scheduler 行为"""
    print("验证学习率调度:")
    print("-" * 50)
    
    for epoch in range(num_epochs):
        lr = optimizer.param_groups[0]['lr']
        print(f"Epoch {epoch:3d}: LR = {lr:.6f}")
        scheduler.step()

# 使用
optimizer = optim.SGD(model.parameters(), lr=0.1)
scheduler = StepLR(optimizer, step_size=5, gamma=0.1)
verify_scheduler(optimizer, scheduler)
技巧 3:使用 TensorBoard 可视化
python 复制代码
from torch.utils.tensorboard import SummaryWriter

writer = SummaryWriter('runs/lr_schedule')

for epoch in range(num_epochs):
    train(...)
    
    # 记录学习率
    lr = optimizer.param_groups[0]['lr']
    writer.add_scalar('Learning Rate', lr, epoch)
    
    scheduler.step()

writer.close()

10.3 最佳实践

✅ 推荐做法

1. 明确调用时机

python 复制代码
# 基于 Epoch 的 Scheduler
for epoch in range(num_epochs):
    train_one_epoch(...)
    validate(...)
    scheduler.step()  # epoch 结束后

# 基于 Step 的 Scheduler
for epoch in range(num_epochs):
    for batch in train_loader:
        optimizer.step()
        scheduler.step()  # 每个 batch 后

2. 记录学习率到日志

python 复制代码
# PyTorch Lightning 自动记录
from pytorch_lightning.callbacks import LearningRateMonitor
trainer = pl.Trainer(callbacks=[LearningRateMonitor()])

# 手动记录
self.log('learning_rate', optimizer.param_groups[0]['lr'])

3. 保存和恢复 Scheduler 状态

python 复制代码
# 保存
checkpoint = {
    'model': model.state_dict(),
    'optimizer': optimizer.state_dict(),
    'scheduler': scheduler.state_dict(),  # 保存 Scheduler 状态
    'epoch': epoch,
}
torch.save(checkpoint, 'checkpoint.pth')

# 加载
checkpoint = torch.load('checkpoint.pth')
model.load_state_dict(checkpoint['model'])
optimizer.load_state_dict(checkpoint['optimizer'])
scheduler.load_state_dict(checkpoint['scheduler'])

4. 使用 Warmup

python 复制代码
# 大模型训练建议使用 Warmup
warmup_scheduler = LinearLR(optimizer, start_factor=0.1, total_iters=5)
main_scheduler = CosineAnnealingLR(optimizer, T_max=95)
scheduler = SequentialLR(optimizer, [warmup_scheduler, main_scheduler], milestones=[5])

5. 文档化配置

python 复制代码
# 在代码中明确注释 Scheduler 配置
optimizer = optim.Adam(model.parameters(), lr=0.001)
scheduler = CosineAnnealingLR(
    optimizer,
    T_max=100,  # 训练 100 个 epoch
    eta_min=1e-6  # 最小学习率
)
# 学习率从 0.001 余弦退火到 1e-6
❌ 避免的做法

1. 混用不兼容的 Scheduler

python 复制代码
# ❌ 错误:同时使用多个 Scheduler(未使用 ChainedScheduler)
scheduler1 = StepLR(optimizer, step_size=10)
scheduler2 = ExponentialLR(optimizer, gamma=0.9)

for epoch in range(num_epochs):
    scheduler1.step()
    scheduler2.step()  # 会相互干扰

2. 在错误的地方修改学习率

python 复制代码
# ❌ 错误:在训练循环内手动修改
for epoch in range(num_epochs):
    for batch in train_loader:
        optimizer.param_groups[0]['lr'] *= 0.99  # 每个 batch 都修改

3. 忽略 Scheduler 的返回值

python 复制代码
# 某些 Scheduler 可能返回有用信息
# 虽然大多数情况下可以忽略,但了解返回值有助于调试

10.4 性能优化

技巧 1:避免频繁创建 Scheduler

python 复制代码
# ❌ 低效
for epoch in range(num_epochs):
    scheduler = StepLR(optimizer, step_size=10)  # 每次都创建
    scheduler.step()

# ✅ 高效
scheduler = StepLR(optimizer, step_size=10)  # 创建一次
for epoch in range(num_epochs):
    scheduler.step()

技巧 2:使用 Scheduler 的 state_dict 减少内存

python 复制代码
# 如果只保存检查点,不需要完整 Scheduler 对象
scheduler_state = scheduler.state_dict()  # 仅状态字典

10.5 常见场景推荐

场景 推荐 Scheduler 配置建议
CV 分类(ResNet 风格) MultiStepLR milestones=[30, 60, 90], gamma=0.1
Transformer 训练 CosineAnnealingLR + Warmup T_max=max_epochs, warmup=5-10%
迁移学习/微调 ReduceLROnPlateau patience=5-10, factor=0.5
快速原型开发 OneCycleLR max_lr=1e-3, pct_start=0.3
长期训练(>100 epochs) CosineAnnealingWarmRestarts T_0=10, T_mult=2
调试阶段 StepLR step_size=5, gamma=0.1(简单可控)

11. 扩展阅读与进阶方向

11.1 官方文档

11.2 经典论文

学习率调度相关论文
  1. Cyclical Learning Rates for Training Neural Networks

    • 作者: Leslie N. Smith
    • 介绍: CyclicLR 的原理和应用
  2. SGDR: Stochastic Gradient Descent with Warm Restarts

    • 作者: Ilya Loshchilov, Frank Hutter
    • 介绍: CosineAnnealingWarmRestarts
  3. Super-Convergence: Very Fast Training of Neural Networks Using Large Learning Rates

    • 作者: Leslie N. Smith, Nicholay Topin
    • 介绍: OneCycleLR(1cycle policy)
  4. Decoupled Weight Decay Regularization

    • 作者: Ilya Loshchilov, Frank Hutter
    • 介绍: AdamW 优化器

11.3 高级主题

11.3.1 自定义 Scheduler
python 复制代码
from torch.optim.lr_scheduler import _LRScheduler

class CustomScheduler(_LRScheduler):
    """自定义学习率调度器"""
    
    def __init__(self, optimizer, max_epochs, last_epoch=-1):
        self.max_epochs = max_epochs
        super().__init__(optimizer, last_epoch)
    
    def get_lr(self):
        """计算当前学习率"""
        # 自定义调度逻辑
        progress = self.last_epoch / self.max_epochs
        
        # 示例:平方根衰减
        factor = (1 - progress) ** 0.5
        
        return [base_lr * factor for base_lr in self.base_lrs]

# 使用
optimizer = optim.Adam(model.parameters(), lr=0.001)
scheduler = CustomScheduler(optimizer, max_epochs=100)
11.3.2 集成外部库

使用 transformers 的 Scheduler:

python 复制代码
from transformers import get_cosine_schedule_with_warmup

optimizer = optim.AdamW(model.parameters(), lr=5e-5)
scheduler = get_cosine_schedule_with_warmup(
    optimizer,
    num_warmup_steps=500,
    num_training_steps=10000
)

使用 timm 的 Scheduler:

python 复制代码
from timm.scheduler import CosineLRScheduler

scheduler = CosineLRScheduler(
    optimizer,
    t_initial=100,
    warmup_t=5,
    warmup_lr_init=1e-6,
)

11.4 实战项目推荐

  1. 复现 ImageNet 训练:使用标准的 MultiStepLR 配置
  2. 训练 BERT/GPT:实现 Warmup + Cosine Annealing
  3. 对比实验:在同一任务上对比不同 Scheduler 的效果
  4. 超参数搜索:使用 Optuna/Ray Tune 自动搜索最优 Scheduler 配置

11.5 相关工具

  • TensorBoard: 可视化学习率曲线
  • WandB: 实验追踪,对比不同 Scheduler
  • Optuna: 超参数优化,包括 Scheduler 参数
  • Ray Tune: 分布式超参数搜索

📌 总结

核心要点回顾

  1. Optimizer 与 Scheduler 的关系:

    • Optimizer 负责更新参数
    • Scheduler 负责调整 Optimizer 的学习率
    • Scheduler 通过修改 optimizer.param_groups[i]['lr'] 实现
  2. 关键概念:

    • param_groups: Optimizer 的参数组,存储学习率等超参数
    • 调用时机: 基于 epoch/step/metric 的不同调度策略
    • Warmup: 训练初期逐步增加学习率的策略
  3. 常用 Scheduler:

    • StepLR/MultiStepLR: 阶梯式衰减(CV 常用)
    • CosineAnnealingLR: 余弦退火(Transformer 常用)
    • ReduceLROnPlateau: 自适应调整(调试友好)
    • OneCycleLR: 快速收敛(fastai 推荐)
  4. PyTorch Lightning 集成:

    • 通过 configure_optimizers() 返回配置
    • 使用 LearningRateMonitor 自动记录
  5. 最佳实践:

    • 明确调用时机(epoch vs step)
    • 使用 Warmup 提升稳定性
    • 记录学习率到日志
    • 保存 Scheduler 状态到检查点

Optimizer + Scheduler 快速参考

基础模板:

python 复制代码
optimizer = optim.Adam(model.parameters(), lr=0.001)
scheduler = CosineAnnealingLR(optimizer, T_max=100)

for epoch in range(num_epochs):
    train_one_epoch(model, train_loader, optimizer)
    validate(model, val_loader)
    scheduler.step()

PyTorch Lightning 模板:

python 复制代码
def configure_optimizers(self):
    optimizer = optim.Adam(self.parameters(), lr=0.001)
    scheduler = CosineAnnealingLR(optimizer, T_max=100)
    return {'optimizer': optimizer, 'lr_scheduler': scheduler}

常用配置:

python 复制代码
# CV 任务
optimizer = optim.SGD(model.parameters(), lr=0.1, momentum=0.9)
scheduler = MultiStepLR(optimizer, milestones=[30, 60, 90], gamma=0.1)

# Transformer
optimizer = optim.AdamW(model.parameters(), lr=5e-5)
scheduler = CosineAnnealingLR(optimizer, T_max=100)

# 快速收敛
optimizer = optim.SGD(model.parameters(), lr=0.1, momentum=0.9)
scheduler = OneCycleLR(optimizer, max_lr=0.1, total_steps=total_steps)

相关推荐
Suahi2 小时前
【HuggingFace LLM】经典NLP Tasks数据流转
人工智能·自然语言处理
西***63472 小时前
破局信息孤岛 赋能城市智治——分布式可视化系统驱动智慧城市指挥中心升级
人工智能·分布式·智慧城市
zhaodiandiandian2 小时前
AI智能体重构产业生态,从效率革命到体验升级
人工智能·microsoft
weixin_409383122 小时前
强化lora训练 这次好点 下次在训练数据增加正常对话
人工智能·深度学习·机器学习·qwen
喜欢吃豆2 小时前
大语言模型混合专家(MoE)架构深度技术综述
人工智能·语言模型·架构·moe
老蒋新思维2 小时前
创客匠人:当知识IP遇上系统化AI,变现效率如何实现阶跃式突破?
大数据·网络·人工智能·网络协议·tcp/ip·重构·创客匠人
Franklin2 小时前
如何解决git HEAD detached 分离头指针问题
git·python·pycharm
有一个好名字2 小时前
Spring AI 工具调用(Tool Calling):解锁智能应用新能力
java·人工智能·spring
Das12 小时前
【计算机视觉】07_几何变换
人工智能·计算机视觉