pyTorch中的学习率衰减

1 学习率衰减

深度学习模型训练过程中,经过一定的epoch之后,模型的性能趋于饱和,此时降低学习率,在小范围内进一步调整模型的参数,可以进一步提升模型的性能。

经过多年的发展,也出现了多种学习率衰减算法,比如线性衰减、指数衰减、cosine衰减等,下面将pyTorch中提供的学习率衰减算法进行整理。

2 PyTorch中的学习率衰减

pyTorch官方介绍:https://pytorch.org/docs/stable/optim.html

torch.optim.lr_scheduler提供了多种依据训练epoch数量进行学习率衰减的方法。

学习率衰减应该在optimizer更新之后应用,代码写成:

>>> scheduler = ...
>>> for epoch in range(100):
>>>     train(...)
>>>     validate(...)
>>>     scheduler.step()

scheduler.step()执行学习率衰减操作。

pyTorch 1.1.0之前的版本,是在optimizer更新之前进行学习率衰减。之后的版本调整为先进行optimizer更新,再进行学习率衰减。如果在1.1.0之后的版本中,先调用了scheduler.step()再调用optimizer.step(),造成的后果是第一次的学习率衰减并未生效。如果pytorch升级到1.1.0之后的版本无法复现原始的训练结果,那么就需要检查是不是调用scheduler.step()的顺序出错了。

2.1 按照自定义函数进行学习率衰减

torch.optim.lr_scheduler.LambdaLR(optimizer, lr_lambda, last_epoch=-1, verbose=False)

给定一个函数,优化器当前epoch的学习率等于初始学习率乘以该函数的返回值。如果是给定的是一个list,list中包含了多个函数,那么当前epoch各group参数的学习率就等于初始学习率乘以对应参数的返回值。

参数:



        optimizer (Optimizer) – Wrapped optimizer.

        lr_lambda (function or list) – A function which computes a multiplicative factor given an integer parameter epoch, or a list of such functions, one for each group in optimizer.param_groups.

        last_epoch (int) – The index of last epoch. Default: -1.

        verbose (bool) – If True, prints a message to stdout for each update. Default: False.


示例代码:

>>> # Assuming optimizer has two groups.
>>> lambda1 = lambda epoch: epoch // 30
>>> lambda2 = lambda epoch: 0.95 ** epoch
>>> scheduler = LambdaLR(optimizer, lr_lambda=[lambda1, lambda2])
>>> for epoch in range(100):
>>>     train(...)
>>>     validate(...)
>>>     scheduler.step()

2.2 按照自定义因子进行学习率衰减

torch.optim.lr_scheduler.MultiplicativeLR(optimizer, lr_lambda, last_epoch=-1, verbose=False)

指定函数给出学习率衰减的乘性系数,乘以现有学习率得到衰减后的值。

>>> lmbda = lambda epoch: 0.95
>>> scheduler = MultiplicativeLR(optimizer, lr_lambda=lmbda)
>>> for epoch in range(100):
>>>     train(...)
>>>     validate(...)
>>>     scheduler.step()

2.3 间隔N个epoch之后进行衰减

torch.optim.lr_scheduler.StepLR(optimizer, step_size, gamma=0.1, last_epoch=-1, verbose=False)

间隔step_size个epoch后,学习率变为原来的gamma倍。该衰减策略可以和其他衰减策略结合使用。

>>> # Assuming optimizer uses lr = 0.05 for all groups
>>> # lr = 0.05     if epoch < 30
>>> # lr = 0.005    if 30 <= epoch < 60
>>> # lr = 0.0005   if 60 <= epoch < 90
>>> # ...
>>> scheduler = StepLR(optimizer, step_size=30, gamma=0.1)
>>> for epoch in range(100):
>>>     train(...)
>>>     validate(...)
>>>     scheduler.step()

2.4 训练指定的epoch之后进行衰减

torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones, gamma=0.1, last_epoch=-1, verbose=False)

milestones指定衰减的节点,到节点学习率衰减为原来的gamma倍。该衰减策略可以和其他衰减策略结合使用。



>>> # Assuming optimizer uses lr = 0.05 for all groups
>>> # lr = 0.05     if epoch < 30
>>> # lr = 0.005    if 30 <= epoch < 80
>>> # lr = 0.0005   if epoch >= 80
>>> scheduler = MultiStepLR(optimizer, milestones=[30,80], gamma=0.1)
>>> for epoch in range(100):
>>>     train(...)
>>>     validate(...)
>>>     scheduler.step()


2.5 指数衰减

torch.optim.lr_scheduler.ExponentialLR(optimizer, gamma, last_epoch=-1, verbose=False)

每个epoch后,学习率都衰减为原来的gamma倍。

2.6 余弦退火衰减

torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max, eta_min=0, last_epoch=-1, verbose=False)

这是不带热重启的余弦退火衰减。目的是让学习率按照余弦函数的曲线逐渐衰减到最小值

参数:
optimizer:优化器对象;
T_max:训练的epoch总数;
eta_min: 最小学习率,默认为0;

实际执行的计算公式为:
在这里插入图片描述

公式中, η t \eta_t ηt表示第 t t t个epoch的学习率; η m i n \eta_{min} ηmin表示最小学习率,也就是设定的参数eta_min; η m a x \eta_{max} ηmax表示初始学习率; T c u r T_{cur} Tcur表示当前epoch数; T m a x T_{max} Tmax表示总的epoch数量。可以看出,训练伊始, T c u r = 0 , η t = η m a x T_{cur}=0,\eta_t = \eta_{max} Tcur=0,ηt=ηmax。随着训练的进行, T c u r T_{cur} Tcur增大,cos(.)减小, η t \eta_t ηt也随之减小。等到训练接近结束时, T c u r T_{cur} Tcur接近于 T m a x T_{max} Tmax,cos()接近于-1, η t \eta_t ηt越来越接近于 η m i n \eta_{min} ηmin。综合来看,学习率按照余弦函数定义域在 [ 0 , π ] [0,\pi] [0,π]范围内的曲线进行衰减,如下图所示。
在这里插入图片描述
当然,上面的学习率衰减曲线的起始阶段还有一个warmup的过程,这里再描述下学习率warmup的作用:
为什么使用Warmup?
由于刚开始训练时,模型的权重(weights)是随机初始化的,此时若选择一个较大的学习率,可能带来模型的不稳定(振荡),选择Warmup预热学习率的方式,可以使得开始训练的几个epoch或者一些step内学习率较小,在预热的小学习率下,模型可以慢慢趋于稳定,等模型相对稳定后在选择预先设置的学习率进行训练,使得模型收敛速度变得更快,模型效果更佳。一般学习率warmup过程中都是设定训练的前m个epoch进行warmup,按照线性的方式将学习率从0增大到初始学习率。

2.7 带热重启的余弦退火衰减

SGDR: Stochastic Gradient Descent with Warm Restarts论文中提出了带热重启的余弦退火衰减。热重启的必要性如下图所示:
在这里插入图片描述
深度学习中的优化函数是多峰函数,包含了多个局部最优解和一个全局最优解。虽然,在深度学习领域,大家认为没必要去找全局最优解,局部最优解往往也就可以取得较好的处理效果。但是,如果能找到全局最优解还是要找,毕竟大家都想不断提升模型的性能。所以这里也就出现了热重启的想法,所谓的热重启就是在训练一段时间后突然增大学习率,希望模型可以跳出局部最优解并找到通向全局最优解的路径,这种方式也就是带重启的学习率衰减策略。

pyTorch中提供了带重启的余弦退火学习率衰减策略:

torch.optim.lr_scheduler.CosineAnnealingWarmRestarts(optimizer, T_0, T_mult=1, eta_min=0, last_epoch=-1, verbose=False)

参数:

	optimizer:优化器对象;
	T_0:第一次重启时的epoch数值;
	T_mult:第i次重启需要的训练epoch数$T_i = T_{i-1} * T_{mult}$;
	eta_min : 学习率的最小值,默认为0.

公式可以表述为:
在这里插入图片描述
带重启的余弦退火学习率衰减和不带退火的余弦学习率衰减之间的异同点是:

  • 相同点:在一个周期内,学习率都是按照余弦函数的变化方式,从最大值(初始学习率)减小到最小值;
  • 不同点:带重启的学习率衰减策略,进行了一次重启后,学习率又变成了初始学习率,重新进行余弦退火。

带重启的余弦退火学习率衰减曲线为:

如果设置 T 0 = 5 , T m u l t = 2 T_0 = 5,T_{mult} = 2 T0=5,Tmult=2,则第一次衰减用5个epoch,第二次衰减用10个epoch,第三次则需要20个epoch,…,这样则在训练过程中的第5,15,35,…个epoch时学习率再次回到初始值。

T m u l t > 1 T_{mult} > 1 Tmult>1时,衰减周期越来越长; T m u l t = 1 T_{mult} = 1 Tmult=1时,衰减周期是固定的。

在这里插入图片描述在这里插入图片描述
2.6节和2.7节参考了:https://blog.csdn.net/weixin_35848967/article/details/108493217
https://zhuanlan.zhihu.com/p/261134624
https://zhuanlan.zhihu.com/p/34236769

2.8 在训练进入平台期后进行学习率衰减

torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', factor=0.1, patience=10, threshold=0.0001, threshold_mode='rel', cooldown=0, min_lr=0, eps=1e-08, verbose=False)

当某个度量指标停止改善后进行学习率衰减。当学习过程进入平台期后,将学习率减少为原来的 2到10分之一一般可以推动模型的进一步优化。当然不是衡量指标某次不提升之后立即进行学习率衰减,而是在衡量指标经过patience个epoch之后一直没有进一步优化才进行学习率衰减,这样就杜绝了某次偶发的指标未继续提升后立即进行学习率衰减。

参数:
optimizer:优化器对象;
mode:可用取值’min’或’max’,即监督指标的工作模式。如果选择’min’模式,则在监视的指标停止下降时衰减学习率;如果选择‘max’模式,则在监视的指标停止上升时衰减学习率。默认工作模式是‘min’;
factor:学习率衰减的乘性系数,new_lr = lr * factor;
patience:容忍多少个epoch中指标未变化后才进行学习率衰减;
threshold:指标变化的最小变化量;
threshold_mode:阈值是否变化的度量模式,支持‘rel’和‘abs’两种模式,在‘rel’模式下,'max’方式下dynamic_threshold = best * ( 1 + threshold ),'min’方式下,dynamic_threshold = best * ( 1 - threshold );在‘abs’模式下,'max’方式下dynamic_threshold = best + threshold,‘min’方式下dynamic_threshold = best - threshold.
cool_down:进行一次学习率衰减后,多少个epoch内不继续衰减;
min_lr:最小学习率,可以是一个标量值,也可以是由多个标量组成的list;
eps:学习率的最小衰减量,如果衰减前后学习率的差值小于eps,那么就不再进行更新,默认值为1e-8;
verbose:设置为True,学习率衰减时在stdout打印一条消息,默认是False。

示例代码:

>>> optimizer = torch.optim.SGD(model.parameters(), lr=0.1, momentum=0.9)
>>> scheduler = ReduceLROnPlateau(optimizer, 'min')
>>> for epoch in range(10):
>>>     train(...)
>>>     val_loss = validate(...)
>>>     # Note that step should be called after validate()
		#val_loss停止下降时进行学习率衰减
>>>     scheduler.step(val_loss)

2.9 OneCycleLR

TODO

2.10 CyclicLR

TODO

  • 6
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值