PyTorch的lr_scheduler不会自动生效,必须显式调用step();StepLR等在epoch后调用,ReduceLROnPlateau需传入val_loss并设对mode和patience;多optimizer需各自配scheduler;恢复训练时必须保存并加载scheduler.state_dict()。

PyTorch 的 lr_scheduler 不是“自动生效”的——你必须在每个 epoch 或 step 后显式调用 step(),否则学习率根本不会变。
为什么训练中学习率没下降?检查 step() 调用时机
最常见错误:定义了 StepLR 或 ReduceLROnPlateau,但忘了在训练循环里调用 scheduler.step()。尤其注意 ReduceLROnPlateau 需传入 metric(如验证 loss),而其他调度器通常只在 epoch 结束时调用:
-
StepLR、MultiStepLR、ExponentialLR:在每个epoch结束后调用scheduler.step() -
ReduceLROnPlateau:在每个epoch验证完后,用scheduler.step(val_loss) -
CosineAnnealingLR:支持 per-step 调度,若每 batch 调用scheduler.step(),需设置T_max为总 step 数而非 epoch 数
ReduceLROnPlateau 收敛失败的三个典型原因
它不按 epoch 递减,而是根据指标是否“停滞”来决定——这导致行为比其他调度器更隐蔽:
- 验证 loss 没有传给
scheduler.step(),或传了训练 loss(val_loss必须是标量 float) -
mode='min'但你在优化的是准确率(应设mode='max') -
patience=10却只跑了 5 个 epoch,根本没触发衰减;或者factor=0.1太激进,一次衰减太多导致训练崩掉
示例片段:
立即学习“Python免费学习笔记(深入)”;
scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', factor=0.5, patience=3) # ... val_loss = validate(model, val_loader) scheduler.step(val_loss) # ← 这行不能漏,且 val_loss 必须是 Python float
多 optimizer 场景下如何配对 scheduler?
一个模型用多个 optimizer(如 GAN 中生成器和判别器分开优化),就必须为每个 optimizer 单独实例化 scheduler,且各自 step():
- 不能共用一个 scheduler 实例,因为
optimizer.param_groups是绑定的 -
torch.optim.lr_scheduler.OneCycleLR等部分调度器不支持多 optimizer,会报AttributeError: 'list' object has no attribute 'param_groups' - 若用
lr_lambda自定义函数,确保 lambda 返回的是针对该 optimizer 的缩放系数,而非全局值
保存与加载 scheduler 状态时容易丢的东西
只保存 model.state_dict() 和 optimizer.state_dict() 是不够的——scheduler 有自己的内部计数器(如 last_epoch):
- 必须显式保存
scheduler.state_dict(),并在恢复时用scheduler.load_state_dict(...) -
StepLR的last_epoch决定下一步衰减时间点,加载错会导致跳过或重复衰减 -
ReduceLROnPlateau的best、num_bad_epochs等状态也必须恢复,否则从头开始 patience 计数
正确做法:
torch.save({
'model': model.state_dict(),
'optimizer': optimizer.state_dict(),
'scheduler': scheduler.state_dict(), # ← 别漏这一行
}, 'checkpoint.pth')真正麻烦的不是写几行 scheduler 初始化代码,而是它的状态是否被正确推进、同步、持久化——尤其在中断重训、分布式训练或多任务切换时,last_epoch 和 num_bad_epochs 这类隐式状态最容易出错。


















