应统一通过调度器接口调整学习率,避免直接修改param_groups['lr']导致调度逻辑失效;正确调用scheduler.step()并注意时机,临时微调需同步更新所有参数组的lr。

PyTorch里改学习率,别直接动optimizer.param_groups[0]['lr']
直接赋值虽然能生效,但会绕过所有调度器逻辑,下次scheduler.step()可能覆盖或冲突。尤其用ReduceLROnPlateau或带warmup的调度器时,手动改容易导致lr跳变、不收敛甚至NaN。正确做法是统一走调度器接口,或按规范更新param_groups。
用torch.optim.lr_scheduler动态调整最稳妥
几乎所有常见策略都有对应类,比如衰减、余弦退火、plateau检测。关键是初始化后,在每个epoch或step调用scheduler.step()——注意调用时机:
-
StepLR、MultiStepLR:每epoch调一次scheduler.step() -
ReduceLROnPlateau:必须传入metric,scheduler.step(val_loss) -
CosineAnnealingLR:默认按epoch,若想每batch调,需把T_max设为总batch数,并在每个batch后scheduler.step()
示例:lr_scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.5),之后训练循环里for epoch in range(epochs): ... scheduler.step()即可。
需要临时微调lr?用param_groups但要批量同步
比如验证发现当前lr太大,想立刻压到一半,又不想重置scheduler状态。这时可以安全操作:
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
立即学习“Python免费学习笔记(深入)”;
- 遍历
optimizer.param_groups,对每个group更新'lr'键 - 确保所有group的lr按相同比例缩放,避免不同层更新不一致
- 如果用了
AdamW等带weight_decay的优化器,'weight_decay'不要顺手一起改,除非你明确知道影响
代码片段:
for param_group in optimizer.param_groups:
param_group['lr'] *= 0.5
自定义调度逻辑时,小心last_epoch和_get_lr的耦合
继承torch.optim.lr_scheduler._LRScheduler写自己的调度器,最容易出错的是last_epoch没对齐。它控制内部计数,一旦手动修改last_epoch(比如从checkpoint恢复时),必须同时调用self._step_count = last_epoch + 1,否则_get_lr()返回的lr会错乱。更简单的方式是:加载checkpoint后,先用scheduler.step()跳过已训练的epoch数,而不是硬设last_epoch。
多参数组、混合精度训练、梯度累积这些场景下,lr调整的时序和粒度会更敏感,别只盯着数值变化,得看实际更新步数和scheduler内部计数是否匹配。

















