Fastai中fit_one_cycle分epoch训练后,如何调整学习率?
fit_one_cycle时,每个epoch后如何调整学习率? 我现在尝试分阶段运行fit_one_cycle函数,每次跑完一个epoch就保存模型、加载后再启动新的epoch,代码如下:
learn = language_model_learner(data, AWD_LSTM, drop_mult=0.5, pretrained=False).to_fp16() learn.load('/content/gdrive/My Drive/Language Model/language_model') learn.load_encoder('/content/gdrive/My Drive/Language Model/model_encoder'); lr = 1e-3 lr *= bs/48 # Scale learning rate by batch size learn.unfreeze() learn.fit_one_cycle(1, lr, moms=(0.8,0.7)) learn.save('/content/gdrive/My Drive/Language Model/language_model') learn.save_encoder('/content/gdrive/My Drive/Language Model/model_encoder')
想请教下,在每个epoch结束后,我应当如何调整学习率?
其实分阶段用fit_one_cycle时调整学习率,核心是要贴合这个调度器的特性——它本身就是余弦退火式的学习率变化,每个cycle(你这里每个cycle是1个epoch)会从初始lr降到lr_max的1/10左右,再小幅回升。结合你拆分训练的场景,给你几个实用的调整方案:
1. 延续上一轮的学习率节奏
如果你想保持fit_one_cycle原生的余弦退火逻辑,不想手动干预太多,可以在每次训练结束后获取当前的学习率,作为下一轮的初始lr:
# 跑完一个epoch后,获取当前优化器的学习率 current_lr = learn.opt.hypers[-1]['lr'] # 下次训练时传入这个lr learn.fit_one_cycle(1, current_lr, moms=(0.8,0.7))
这种方式会让每个小cycle的学习率变化幅度逐步收窄,适合训练后期的精细调参。
2. 固定比例逐步降LR(最常用的策略)
如果你的模型在训练后期出现验证集指标停滞、甚至过拟合的情况,最直接的方法就是按固定比例降低学习率,比如每次乘以0.5或0.7:
# 第一个epoch训练完成后 lr *= 0.7 # 继续下一轮训练 learn.fit_one_cycle(1, lr, moms=(0.8,0.7))
这个方法简单易操作,调整幅度可以根据训练状态灵活改:如果验证集指标还在快速提升,就少降一点;如果已经停滞,就多降一些(比如乘以0.3)。
3. 根据验证集指标动态调整
更精准的方式是盯着验证集的核心指标(比如语言模型的困惑度、损失值)来调整:
- 如果验证集损失持续下降,说明模型还在学习,可以保持当前lr甚至小幅提升(不推荐轻易提lr,风险较高)
- 如果验证集损失连续2-3个epoch没有下降,甚至上升,就把lr降到原来的1/5或1/10
你可以在每次保存模型前记录验证指标,下次加载后对比再做决策:
# 第一次训练后记录验证损失 prev_val_loss = learn.validate()[0] # 加载模型后,先获取当前验证损失 current_val_loss = learn.validate()[0] # 如果损失上升超过2%,就降低学习率 if current_val_loss >= prev_val_loss * 1.02: lr *= 0.5
4. 模拟完整多epoch的fit_one_cycle节奏
如果你原本计划跑N个epoch的完整fit_one_cycle,现在拆分成N次单epoch训练,可以参考完整cycle的余弦曲线来设置lr:比如第一次用初始lr,第二次用初始lr的0.8,第三次0.6,逐步降低,对应完整cycle里的下降阶段。这个需要你对OneCycleScheduler的逻辑有一定了解,直接看fastai源码里的调度实现就能明白细节。
最后提醒下,不管用哪种方法,都要结合训练时的损失变化和验证集指标来调整——调参从来不是死板的规则,而是看数据说话的活~
内容的提问来源于stack exchange,提问作者Hossein

