第10课:PyTorch|学习率调度策略全面精讲【训练过程的“自适应巡航”】

文章目录


📖 课前导读

为什么固定的学习率不是最优解?

在第9课中我们学过,学习率决定了参数更新的步长。如果使用固定学习率:

  • 设置太大:初期可能快速下降,但后期会在最优值附近剧烈震荡,无法精确收敛。
  • 设置太小:初期进展极其缓慢,浪费大量时间,且可能陷入局部极小点难以跳出。

理想的学习率变化曲线应该是:前期较大 ,快速接近最优区域;中期逐渐减小 ,开始精细探索;后期很小,在最优值附近微调。就像开车上高速:先猛踩油门加速到接近限速(大学习率),然后松开油门微调速度(中等学习率),最后遇到收费站轻轻点刹(小学习率)。

PyTorch的torch.optim.lr_scheduler提供了丰富的学习率调度策略,让你可以像设置导航一样规划学习率的"行程"。本课将带你掌握所有主流调度器,并学会为不同场景选择最合适的策略。

💡 核心认知:学习率调度器和优化器是"搭档"关系。优化器负责根据当前学习率更新参数,调度器负责在训练过程中修改优化器的学习率。两者配合得好,1+1>2。

学完这一课,你将能够:

  • ✅ 理解学习率衰减的必要性和常见策略
  • ✅ 使用PyTorch内置的StepLR、MultiStepLR、ExponentialLR
  • ✅ 掌握余弦退火(CosineAnnealingLR)及其带重启的变体
  • ✅ 实现学习率预热(Warmup)------大模型训练的标配
  • ✅ 使用ReduceLROnPlateau根据验证集损失自适应调整
  • ✅ 自定义学习率调度器(lambda函数或继承_LRScheduler
  • ✅ 可视化不同调度策略的学习率曲线
  • ✅ 将调度器与优化器正确集成到训练循环中

一、知识原理:学习率调度的数学直觉

1.1 为什么需要学习率衰减?

从最优化理论的角度,使用固定学习率的SGD在强凸函数下可以收敛,但收敛速度受限于学习率的选择。如果学习率太大,最终的收敛半径(与最优解的距离)无法缩小;如果学习率太小,收敛速度线性变慢。因此,需要在训练过程中逐渐减小学习率,以同时获得快速的初始下降和精确的最终收敛。

1.2 学习率调度的常见模式

模式 数学形式 特点
阶梯衰减 每经过一定步数,学习率乘以γ 简单有效,需要预设下降点
指数衰减 lr = lr0 * γ^(epoch) 平滑下降,下降速度先快后慢
多项式衰减 lr = lr0 * (1 - t/T)^p 从lr0降到0,p控制曲线形状
余弦退火 lr = lr_min + 0.5*(lr0-lr_min)*(1+cos(π*t/T)) 平滑下降,末期下降慢
带重启的余弦 周期性地重置学习率 跳出局部极小点
自适应衰减 当验证损失不再下降时,降低学习率 不需要预设步数

1.3 学习率预热(Warmup)的原理

在训练初期,模型参数是随机初始化的,梯度估计可能不稳定,直接用较大的学习率可能导致梯度爆炸。预热策略在前若干个epoch(或step)内,让学习率从0线性增长到预设值,帮助模型平稳启动。这对于Transformer、BERT等大模型训练至关重要。


二、环境搭建与准备

python 复制代码
import torch
import torch.nn as nn
import torch.optim as optim
from torch.optim.lr_scheduler import (StepLR, MultiStepLR, ExponentialLR, 
                                       CosineAnnealingLR, CosineAnnealingWarmRestarts,
                                       ReduceLROnPlateau, LinearLR, ConstantLR,
                                       SequentialLR, ChainedScheduler, LambdaLR)
import matplotlib.pyplot as plt
import numpy as np

print(f"PyTorch版本: {torch.__version__}")

# 定义一个简单的模型用于演示(不需要真实数据)
model = nn.Linear(10, 2)

三、代码实战:PyTorch内置学习率调度器

3.1 StepLR:等间隔阶梯衰减

StepLR每经过step_size个epoch,学习率乘以gamma

python 复制代码
# 创建优化器
optimizer = optim.SGD(model.parameters(), lr=0.1)
# 调度器:每10个epoch,学习率乘以0.1
scheduler = StepLR(optimizer, step_size=10, gamma=0.1)

# 模拟训练20个epoch,记录学习率变化
lrs = []
for epoch in range(20):
    lrs.append(optimizer.param_groups[0]['lr'])
    # 训练一个epoch...(省略实际训练)
    scheduler.step()  # 每个epoch后调用

# 可视化
plt.plot(range(1, 21), lrs, marker='o')
plt.xlabel('Epoch')
plt.ylabel('Learning Rate')
plt.title('StepLR (step_size=10, gamma=0.1)')
plt.grid(True)
plt.show()

参数说明

  • step_size:每隔多少个epoch调整一次
  • gamma:衰减因子
  • last_epoch:最后一个epoch索引,用于恢复训练(默认为-1)

3.2 MultiStepLR:自定义衰减里程碑

与StepLR类似,但你可以指定在哪些epoch进行衰减。

python 复制代码
optimizer = optim.SGD(model.parameters(), lr=0.1)
scheduler = MultiStepLR(optimizer, milestones=[30, 60, 80], gamma=0.1)
# 在第30、60、80个epoch时,学习率乘以0.1

3.3 ExponentialLR:指数衰减

每个epoch学习率乘以gamma,呈指数级下降:lr = lr0 * gamma^epoch

python 复制代码
optimizer = optim.SGD(model.parameters(), lr=0.1)
scheduler = ExponentialLR(optimizer, gamma=0.95)  # 每个epoch下降5%

适用场景:需要平滑连续下降的任务,但注意指数衰减可能导致后期学习率过小。

3.4 CosineAnnealingLR:余弦退火

学习率按照余弦函数从初始值下降到eta_min(默认为0)。

公式:lr = eta_min + (lr0 - eta_min) * (1 + cos(π * epoch / T_max)) / 2

python 复制代码
optimizer = optim.SGD(model.parameters(), lr=0.1)
scheduler = CosineAnnealingLR(optimizer, T_max=50, eta_min=0)
# T_max: 从lr0降到eta_min所需的epoch数(半个周期)

可视化:学习率在50个epoch内平滑地从0.1降到0,呈现余弦曲线。

3.5 CosineAnnealingWarmRestarts:带热重启的余弦退火

这是CosineAnnealing的增强版:每隔T_0个epoch,学习率重置为初始值(热重启),然后继续余弦下降。这有助于跳出局部极小点,常用于深度网络的长时间训练。

python 复制代码
optimizer = optim.SGD(model.parameters(), lr=0.1)
scheduler = CosineAnnealingWarmRestarts(optimizer, T_0=20, T_mult=2, eta_min=1e-5)
# T_0: 第一次重启前的epoch数
# T_mult: 每次重启后周期翻倍(20 -> 40 -> 80 ...)
# eta_min: 最小学习率
python 复制代码
# 模拟100个epoch
lrs = []
optimizer = optim.SGD(model.parameters(), lr=0.1)
scheduler = CosineAnnealingWarmRestarts(optimizer, T_0=20, T_mult=2)
for epoch in range(100):
    lrs.append(optimizer.param_groups[0]['lr'])
    scheduler.step()
plt.plot(range(1, 101), lrs)
plt.xlabel('Epoch')
plt.ylabel('Learning Rate')
plt.title('CosineAnnealingWarmRestarts (T_0=20, T_mult=2)')
plt.show()

3.6 ReduceLROnPlateau:基于验证指标的自适应调整

前面的调度器都是基于epoch的固定计划。ReduceLROnPlateau则根据某个指标(如验证损失)是否停止改善来动态降低学习率。这是一种"反馈式"调度。

python 复制代码
optimizer = optim.SGD(model.parameters(), lr=0.1)
scheduler = ReduceLROnPlateau(optimizer, mode='min', factor=0.1, patience=5, 
                              threshold=1e-4, min_lr=1e-6)

# 在训练循环中,每个epoch结束后传入验证损失
for epoch in range(100):
    val_loss = ...  # 计算验证损失
    scheduler.step(val_loss)  # 根据val_loss决定是否降低学习率

关键参数

  • mode'min'(指标下降时降低LR)或'max'(指标上升时降低LR)
  • factor:每次降低的倍数(新LR = LR * factor)
  • patience:容忍多少个epoch指标没有改善
  • threshold:最小改善阈值
  • min_lr:学习率下限

适用场景:验证集性能是唯一关注点,不需要预设衰减计划(如Kaggle比赛)。

3.7 学习率预热调度器

PyTorch 1.10+ 提供了专门的预热调度器。

LinearLR:线性预热
python 复制代码
# 在前5个epoch内,学习率从0线性增加到0.1
warmup_scheduler = LinearLR(optimizer, start_factor=0.01, end_factor=1.0, total_iters=5)
# start_factor=0.01 表示起始学习率为初始lr的0.01倍
ConstantLR:常数预热
python 复制代码
# 前5个epoch保持一个较小的学习率(初始lr的0.01倍),然后恢复到原lr
constant_scheduler = ConstantLR(optimizer, factor=0.01, total_iters=5)

3.8 组合调度器:SequentialLR 和 ChainedScheduler

有时候你需要先预热,再阶梯衰减,或者先余弦退火,再恒定。可以使用SequentialLR顺序执行多个调度器,或者ChainedScheduler串联它们(每个step调用所有调度器)。

python 复制代码
# 顺序执行:先LinearLR预热5个epoch,再CosineAnnealingLR
optimizer = optim.SGD(model.parameters(), lr=0.1)
scheduler1 = LinearLR(optimizer, start_factor=0.01, end_factor=1.0, total_iters=5)
scheduler2 = CosineAnnealingLR(optimizer, T_max=45, eta_min=1e-5)
# 在5个epoch后切换到scheduler2
scheduler = SequentialLR(optimizer, schedulers=[scheduler1, scheduler2], milestones=[5])

# 链式:每个step同时更新所有调度器(通常用于多个调度器不冲突的情况)
# 例如:指数衰减 + 预热
# scheduler = ChainedScheduler([warmup_scheduler, exp_scheduler])

3.9 自定义LambdaLR

如果内置调度器都不满足需求,可以使用LambdaLR,通过lambda函数定义学习率与epoch的关系。

python 复制代码
# 例1:多项式衰减 lr = lr0 * (1 - epoch/100)^2
lambda_func = lambda epoch: (1 - epoch/100) ** 2
scheduler = LambdaLR(optimizer, lr_lambda=lambda_func)

# 例2:分段函数(epoch<30时线性增长,30~80线性下降,80后恒定)
def custom_lambda(epoch):
    if epoch < 30:
        return epoch / 30  # 0 -> 1
    elif epoch < 80:
        return 1 - (epoch - 30) / 50  # 1 -> 0
    else:
        return 0.01  # 保持小学习率
scheduler = LambdaLR(optimizer, lr_lambda=custom_lambda)

# 例3:周期振荡(模拟SGDR)
lambda_osc = lambda epoch: 0.5 * (1 + np.cos(np.pi * (epoch % 20) / 20))
scheduler = LambdaLR(optimizer, lr_lambda=lambda_osc)

3.10 从检查点恢复训练时的调度器状态

当你保存模型checkpoint并想恢复训练时,必须同时保存和恢复调度器的状态(尤其是那些有内部状态的调度器,如CosineAnnealingWarmRestarts)。

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

# 恢复
checkpoint = torch.load('checkpoint.pth')
model.load_state_dict(checkpoint['model_state_dict'])
optimizer.load_state_dict(checkpoint['optimizer_state_dict'])
scheduler.load_state_dict(checkpoint['scheduler_state_dict'])
epoch = checkpoint['epoch']

四、实战案例:不同调度器在图像分类上的效果对比

我们使用CIFAR-10和一个简单的CNN(不训练真实网络,只模拟学习率变化,但为了展示效果,可以训练少量epoch)。这里重点展示调度器的配置和集成。

python 复制代码
import torch
import torchvision
import torchvision.transforms as transforms
from torch.utils.data import DataLoader
from torchvision.models import resnet18

# 数据准备
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,0.5,0.5), (0.5,0.5,0.5))])
train_set = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
train_loader = DataLoader(train_set, batch_size=64, shuffle=True)

# 模型
model = resnet18(num_classes=10)  # 使用ResNet18演示
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device)

# 定义训练函数,传入调度器,并记录学习率变化
def train_with_scheduler(scheduler, epochs=30, lr=0.1):
    optimizer = optim.SGD(model.parameters(), lr=lr, momentum=0.9, weight_decay=5e-4)
    criterion = nn.CrossEntropyLoss()
    model.train()
    lr_history = []
    for epoch in range(epochs):
        # 记录当前学习率
        current_lr = optimizer.param_groups[0]['lr']
        lr_history.append(current_lr)
        # 一个epoch的训练
        running_loss = 0.0
        for inputs, labels in train_loader:
            inputs, labels = inputs.to(device), labels.to(device)
            optimizer.zero_grad()
            outputs = model(inputs)
            loss = criterion(outputs, labels)
            loss.backward()
            optimizer.step()
            running_loss += loss.item()
        print(f"Epoch {epoch+1}: lr={current_lr:.6f}, loss={running_loss/len(train_loader):.4f}")
        # 更新学习率
        if isinstance(scheduler, ReduceLROnPlateau):
            # 对于ReduceLROnPlateau,需要传入验证损失(这里简化用训练损失)
            scheduler.step(running_loss)
        else:
            scheduler.step()
    return lr_history

# 测试不同调度器(为了节省时间,只演示配置,不实际运行)
# 但下面给出代码模板,你可以自行运行比较

# 1. StepLR
optimizer = optim.SGD(model.parameters(), lr=0.1)
scheduler = StepLR(optimizer, step_size=10, gamma=0.1)
# lrs_step = train_with_scheduler(scheduler, epochs=30)

# 2. MultiStepLR
# scheduler = MultiStepLR(optimizer, milestones=[15, 25], gamma=0.1)

# 3. CosineAnnealingLR
# scheduler = CosineAnnealingLR(optimizer, T_max=30)

# 4. CosineAnnealingWarmRestarts
# scheduler = CosineAnnealingWarmRestarts(optimizer, T_0=10, T_mult=2)

# 5. ReduceLROnPlateau
# scheduler = ReduceLROnPlateau(optimizer, mode='min', factor=0.5, patience=5)

五、学习率调度器与优化器的集成模式

5.1 标准训练循环模板

python 复制代码
def train_loop(model, train_loader, val_loader, optimizer, scheduler, epochs, device):
    criterion = nn.CrossEntropyLoss()
    best_acc = 0.0
    for epoch in range(epochs):
        # 训练
        model.train()
        train_loss = 0.0
        for inputs, labels in train_loader:
            inputs, labels = inputs.to(device), labels.to(device)
            optimizer.zero_grad()
            outputs = model(inputs)
            loss = criterion(outputs, labels)
            loss.backward()
            optimizer.step()
            train_loss += loss.item()
        
        # 验证
        model.eval()
        correct = 0
        total = 0
        with torch.no_grad():
            for inputs, labels in val_loader:
                inputs, labels = inputs.to(device), labels.to(device)
                outputs = model(inputs)
                _, predicted = torch.max(outputs, 1)
                total += labels.size(0)
                correct += (predicted == labels).sum().item()
        val_acc = correct / total
        
        # 调度器更新
        if isinstance(scheduler, ReduceLROnPlateau):
            scheduler.step(val_acc if scheduler.mode == 'max' else train_loss)
        else:
            scheduler.step()
        
        print(f"Epoch {epoch+1}: lr={optimizer.param_groups[0]['lr']:.6f}, val_acc={val_acc:.4f}")

5.2 注意事项:scheduler.step()的位置

  • 基于epoch的调度器 (StepLR、CosineAnnealing等):通常在每个epoch结束后调用scheduler.step()
  • 基于step的调度器(自定义或某些场景):可以在每个batch后调用,但要注意性能开销
  • ReduceLROnPlateau:必须在知道指标值之后调用,通常也是epoch结束后

六、可视化不同调度器的学习率曲线

python 复制代码
def plot_scheduler_lr(scheduler_class, kwargs, epochs=100, lr0=0.1, **sched_kwargs):
    model = nn.Linear(10,2)
    optimizer = optim.SGD(model.parameters(), lr=lr0)
    scheduler = scheduler_class(optimizer, **kwargs)
    lrs = []
    for epoch in range(epochs):
        lrs.append(optimizer.param_groups[0]['lr'])
        scheduler.step()
    plt.plot(range(1, epochs+1), lrs, label=scheduler_class.__name__)
    return lrs

plt.figure(figsize=(12, 8))
# StepLR
plot_scheduler_lr(StepLR, {'step_size': 20, 'gamma': 0.3}, epochs=100)
# MultiStepLR
plot_scheduler_lr(MultiStepLR, {'milestones': [30, 60, 80], 'gamma': 0.2}, epochs=100)
# ExponentialLR
plot_scheduler_lr(ExponentialLR, {'gamma': 0.97}, epochs=100)
# CosineAnnealingLR
plot_scheduler_lr(CosineAnnealingLR, {'T_max': 50}, epochs=100)
# CosineAnnealingWarmRestarts
plot_scheduler_lr(CosineAnnealingWarmRestarts, {'T_0': 20, 'T_mult': 2}, epochs=100)

plt.xlabel('Epoch')
plt.ylabel('Learning Rate')
plt.title('不同学习率调度器对比 (初始lr=0.1)')
plt.legend()
plt.grid(True)
plt.ylim(0, 0.12)
plt.show()

观察结论

  • StepLR:阶梯式下降,有明显平台
  • MultiStepLR:在指定点下降
  • ExponentialLR:平滑指数下降,后期极低
  • CosineAnnealingLR:余弦形平滑下降
  • CosineAnnealingWarmRestarts:周期性重启,学习率多次"跃升"

七、高级技巧与最佳实践

7.1 学习率预热在Transformer中的应用

在训练BERT、GPT等大模型时,标准的做法是:前若干步(通常为总步数的10%或固定几千步)学习率线性增加,之后线性衰减或余弦衰减。

python 复制代码
# 计算总训练步数
total_steps = len(train_loader) * num_epochs
warmup_steps = int(0.1 * total_steps)  # 预热10%

# 使用LambdaLR实现warmup + 余弦衰减
def lr_lambda(step):
    if step < warmup_steps:
        return step / warmup_steps  # 从0线性增加到1
    else:
        # 余弦衰减到0
        progress = (step - warmup_steps) / (total_steps - warmup_steps)
        return 0.5 * (1 + np.cos(np.pi * progress))
scheduler = LambdaLR(optimizer, lr_lambda=lr_lambda)

7.2 使用get_lr()调试调度器

调度器提供了get_lr()方法,可以查看下一次step后将会设定的学习率。

python 复制代码
# 在step之前
print(scheduler.get_lr())
scheduler.step()

7.3 为不同的参数组设置不同的调度策略

如第9课所述,优化器可以有多个参数组。每个参数组可以独立设置学习率,也可以独立应用调度器(但需要使用LambdaLRlr_lambda为每个组分别定义)。

python 复制代码
optimizer = optim.SGD([
    {'params': model.fc1.parameters(), 'lr': 0.01},
    {'params': model.fc2.parameters(), 'lr': 0.001}
], lr=0.1)  # 默认lr会被组内lr覆盖

# 为每个组定义不同的lambda函数
lambda1 = lambda epoch: 0.95 ** epoch
lambda2 = lambda epoch: 0.99 ** epoch
scheduler = LambdaLR(optimizer, lr_lambda=[lambda1, lambda2])

7.4 学习率与Batch Size的关系

当增加Batch Size时,可以相应增加学习率(线性缩放规则)。例如,Batch Size从256增加到512,学习率可从0.1增加到0.2。这一规则对SGD和AdamW都近似适用。

7.5 何时不使用学习率调度器?

  • 小模型、小数据集、短时间训练:固定学习率可能就足够了。
  • 使用Adam等自适应优化器时,调度器的收益可能不如SGD明显,但仍然有效(尤其对Transformer)。
  • 使用1-cycle调度(如OneCycleLR)时,它内部已经包含了学习率调度,不需要额外调度器。

八、难点解析:常见问题与陷阱

8.1 忘记了optimizer.step()scheduler.step()的先后顺序

一般顺序:

python 复制代码
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 如果是基于step的调度器,在这里调用scheduler.step()
# 如果是基于epoch的调度器,在epoch结束后调用

如果基于epoch的调度器放在了optimizer.step()之前,当前epoch的学习率会使用下一epoch的值,导致学习率提前一个epoch下降。

8.2 调度器状态没有随checkpoint保存

恢复训练时如果不加载调度器状态,学习率会从初始值开始,破坏训练进度。

8.3 使用ReduceLROnPlateau时传入错误的指标模式

如果任务是准确率(越高越好),应设置mode='max';如果是损失(越低越好),设置mode='min'。传反了会导致学习率在指标改善时反而降低。

8.4 学习率下降过猛导致训练停滞

当学习率衰减因子gamma太小时(如0.1),学习率可能跳跃式下降,造成损失突然上升。可以尝试更平滑的衰减(如0.9)或使用余弦退火。

8.5 热身阶段过长导致前期浪费

预热步数通常为总步数的5%-10%。预热过长会使模型在低学习率下徘徊太久,影响收敛速度。


九、课后总结

调度器速查表

调度器 特点 关键参数 适用场景
StepLR 等间隔阶梯下降 step_size, gamma 经典CNN训练
MultiStepLR 自定义衰减点 milestones, gamma 已知损失下降点
ExponentialLR 指数平滑下降 gamma 需要连续变化
CosineAnnealingLR 余弦曲线下降 T_max, eta_min 快速收敛、SGD
CosineAnnealingWarmRestarts 带重启的余弦 T_0, T_mult 跳出局部极小,长时间训练
ReduceLROnPlateau 自适应,基于指标 mode, patience, factor 验证集性能是关键
LinearLR 线性预热 start_factor, total_iters 大模型训练开头
LambdaLR 任意自定义函数 lr_lambda 任何特殊需求
OneCycleLR 1周期调度(上升+下降) max_lr, total_steps 训练时间固定,追求极速收敛

决策树

复制代码
是否需要基于验证集性能动态调整?
├── 是 → ReduceLROnPlateau
└── 否 → 是否需要预热(Warmup)?
    ├── 是 → 结合LinearLR + 主调度器(如CosineAnnealingLR)
    └── 否 → 是否有已知的损失下降点?
        ├── 是 → MultiStepLR
        ├── 否 → 训练时间是否固定?
            ├── 是 → CosineAnnealingLR / OneCycleLR
            └── 否 → StepLR 或 ExponentialLR

检查清单

  • 理解不同调度器的基本行为
  • 能根据任务选择调度器(CV用StepLR/Cosine,NLP大模型用warmup+余弦衰减)
  • 知道如何将调度器集成到训练循环中
  • 会保存和恢复调度器状态
  • 能使用ReduceLROnPlateau并正确设置mode和patience
  • 能够通过LambdaLR实现自定义调度策略
  • 学习了学习率可视化的方法,用于调试

十、课后作业

作业1:调度器可视化

使用本课中的可视化代码,绘制以下调度器在200个epoch内的学习率变化曲线(初始lr=0.1):

  • StepLR(step_size=40, gamma=0.5)
  • MultiStepLR(milestones=50, 100, 150, gamma=0.3)
  • ExponentialLR(gamma=0.98)
  • CosineAnnealingLR(T_max=80)
  • CosineAnnealingWarmRestarts(T_0=30, T_mult=1)

作业2:调度器对收敛性能的影响

在CIFAR-10上训练一个简单的CNN(如ResNet-18简化版),比较以下三种调度器下的验证准确率(训练50个epoch):

  • 固定学习率0.01
  • StepLR(step_size=20, gamma=0.1)
  • CosineAnnealingLR(T_max=50)
    记录每个epoch的验证准确率,画出曲线并分析。

作业3:实现自定义调度器

编写一个调度器,使得学习率按照lr = lr0 / (1 + decay_rate * epoch)的规律衰减。分别使用LambdaLR和继承_LRScheduler两种方式实现。

作业4:预热+余弦衰减的组合

实现一个warmup+余弦衰减的调度器:前5个epoch学习率从0线性增加到0.1,之后余弦衰减到0。使用SequentialLRLambdaLR实现,并画出学习率曲线(总共50个epoch)。

作业5:学习率范围测试

编写一个函数,在训练开始前执行学习率范围测试(LR Range Test):从一个极小的学习率(如1e-7)开始,每个batch线性增加学习率直到一个很大的值(如1),记录每个batch的损失。然后画出学习率-损失曲线,找出损失下降最陡峭的区域对应的学习率作为初始学习率。提示:可以修改第9课的lr_range_test函数。


十一、下一课预告

第11课我们将进行第一个完整实战项目:手写数字识别。我们将整合前面10课的所有知识:

  • 数据加载(Dataset、DataLoader)
  • 网络定义(nn.Module)
  • 损失函数、优化器、学习率调度器
  • 完整的训练循环、验证评估、模型保存与加载

学完第11课,你将拥有自己的第一个可运行的PyTorch训练脚本,并理解深度学习项目的全流程。


附录:PyTorch学习率调度器API完整列表

调度器 初始化示例
StepLR StepLR(optimizer, step_size=10, gamma=0.1)
MultiStepLR MultiStepLR(optimizer, milestones=[20,40], gamma=0.1)
ExponentialLR ExponentialLR(optimizer, gamma=0.95)
CosineAnnealingLR CosineAnnealingLR(optimizer, T_max=50)
CosineAnnealingWarmRestarts CosineAnnealingWarmRestarts(optimizer, T_0=10, T_mult=2)
ReduceLROnPlateau ReduceLROnPlateau(optimizer, mode='min', factor=0.1, patience=5)
LinearLR LinearLR(optimizer, start_factor=0.01, total_iters=5)
ConstantLR ConstantLR(optimizer, factor=0.01, total_iters=5)
LambdaLR LambdaLR(optimizer, lr_lambda=lambda epoch: 0.95**epoch)
OneCycleLR OneCycleLR(optimizer, max_lr=0.01, total_steps=1000)
CyclicLR CyclicLR(optimizer, base_lr=0.001, max_lr=0.01, step_size_up=2000)

🔗《精讲25课|PyTorch 从入门到精通》系列课程导航

去订阅

🌟 感谢您耐心阅读到这里!

💡 如果本文对您有所启发欢迎:

👍 点赞📌 收藏 📤 分享给更多需要的伙伴。

🗣️ 期待在评论区看到您的想法, 共同进步。

🔔 关注我,持续获取更多干货内容~

🤗 我们下篇文章见~

相关推荐
一起努力啊~1 小时前
算法题打卡力扣第1658题:将 x 减到 0 的最小操作数(mid)
学习·leetcode
xsd202411181 小时前
无人机航拍生产库区目标检测与墙体裂缝识别:从航线规划到AI量化分析
人工智能·目标检测·无人机
传奇开心果编程1 小时前
【ArkUI 练中学】第1课:从零开始
学习·华为·前端框架
Thomas.Sir1 小时前
第4课:PyTorch|自动微分Autograd机制深度解析【深度学习的“发动机”】
人工智能·pytorch·深度学习
aneasystone本尊1 小时前
学习大模型推理的批处理:Continuous Batching
人工智能
IT_陈寒1 小时前
Vue的响应式让我加班到凌晨,问题竟出在这个不起眼的地方
前端·人工智能·后端
j7~1 小时前
【C++微服务项目开发脚手架】(准备篇)从 0 到跑通:Docker 容器开发环境 + 宿主机用户 + Trae 远程连接 全链路踩坑实战
linux·c++·学习·xshell·docker容器·trae
和裕1 小时前
平口开槽箱 vs 飞机盒 vs 扣底盒:自动化、展示效果与成本核心区别
大数据·运维·网络·人工智能·算法·自动化