本篇博文主要介绍代码中一些常用的辅助功能的写法;
一 学习率动态调整
https://blog.csdn.net/sinat_36618660/article/details/99650804
https://www.freesion.com/article/6236443466/
https://blog.csdn.net/qq_20622615/article/details/83150963
这篇文章解释的很清楚了,而且底下的评论也补充了:学习率预热策略是针对自适应优化器,如Adam和RMSProp。并不适用于CLR和SGDR这类的学习率调整策略,后者的学习速率是周期性增加和衰减。
1.1 介绍
从直观上看,学习速率的优化可以分为两个阶段:
1.刚开始训练时,参数都是随机初始化的,如果学习率较大可能导致波动较大,模型不稳定,因此需要从小往大变化;该阶段称为预热阶段warmup;
2.训练较长时间后,模型已经有了较高的准确率,此时再不适合大范围的调整,应该小范围调整便于收敛,因此需要从大往下变化;
1.2 实现
学习速率的调整,在pytorch中使用的是调度器scheduler。调度器调在训练过程中调整学习速率,是用训练step来度量训练的进度,而不是用epoch。
说白了,就是先知道总共要训练多少个step,然后拍脑袋前X个step作为预热阶段,从小增大到预设的lr。然后在后Y个step内,从大到小递减lr。从大到小、从小到大,按照什么方式变化?线性、指数、三角函数,变化方式要自己写函数。
进一步地,所谓动态调整学习速率其实就是自己写函数控制学习速率,变化的方式完全由自己控制,只不过是经验上按照step的进度来调整,经验上按照先小后大再先大后小的方式,自己想瞎调也是可以的。scheduler并没有多神秘,只不过是按照自定义函数设置optimizer中的lr参数而已。
参考:https://github.com/ThanhDucPham/Graph-Convolutional-Networks-with-Argument-Aware-Pooling-for-Event-Detection
线性上升、线性下降的实现方式如下:(详细见上述链接)
# 定义scheduler的调整策略:warmup阶段线性增大,warmup后线性减小
def get_linear_schedule_with_warmup(optimizer, num_warmup_steps, num_training_steps, last_epoch=-1):
def lr_lambda(current_step):
if current_step < num_warmup_steps:
return float(current_step) / float(max(1, num_warmup_steps))
return max(0.0, float(num_training_steps - current_step) / float(max(1, num_training_steps - num_warmup_steps)))
return LambdaLR(optimizer, lr_lambda, last_epoch)
# 创建scheduler
# 训练过程总step数
total_steps = len(train_loader) * config.num_epoch
# 调度器,动态调整学习速率,warmup_steps为预热阶段step数,total_steps为训练总step数
scheduler = get_linear_schedule_with_warmup(optimizer, num_warmup_steps=warmup_steps, num_training_steps=total_steps)
# 使用scheduler:scheduler是依赖于step总数的,与当前step无关,在训练过程中并不需要记录step
for epoch in range(0, num_epoch):
...
loss.backward()
optimizer.step()
# 调整学习速率
scheduler.step()
二 早停法
2.1 介绍
从直观上看,当模型从某个epoch开始,长时间效果不再上升,可以考虑回退到该点重新训练。
2.2 实现
参考:https://github.com/ThanhDucPham/Graph-Convolutional-Networks-with-Argument-Aware-Pooling-for-Event-Detection
restart_used = 10
epoch_improve = 0
# 早停法
for epoch in range(0, num_epoch):