【详解】模型优化技巧之优化器和学习率调整_1
文章目录
1 torch.optim.SGD
1 | class torch.optim.SGD(params, lr=, momentum=0, dampening=0, weight_decay=0, nesterov=False) |
功能:
可实现 SGD 优化算法,带动量 SGD 优化算法,带 NAG (Nesterov accelerated gradient) 动量 SGD 优化算法,并且均可拥有 weight_decay 项。
参数:
params(iterable)- 参数组 (参数组的概念请查看 3.2 优化器基类:Optimizer),优化器要管理的那部分参数。
lr(float)- 初始学习率,可按需随着训练过程不断调整学习率。
momentum(float)- 动量,通常设置为 0.9,0.8
dampening(float)- dampening for momentum ,暂时不了其功能,在源码中是这样用的:buf.mul_(momentum).add_(1 - dampening, d_p),值得注意的是,若采用 nesterov,dampening 必须为 0.
weight_decay(float)- 权值衰减系数,也就是 L2 正则项的系数
nesterov (bool)- bool 选项,是否使用 NAG (Nesterov accelerated gradient)
注意事项:
pytroch 中使用 SGD 十分需要注意的是,更新公式与其他框架略有不同!
pytorch 中是这样的:
1 | v=ρ?v+g |
其他框架:
1 | v=ρ?v+lr?g |
ρ 是动量,v 是速率,g 是梯度,p 是参数,其实差别就是在 ρ?v 这一项,pytorch 中将此项也乘了一个学习率。
2 torch.optim.ASGD
1 | class torch.optim.ASGD(params, lr=0.01, lambd=0.0001, alpha=0.75, t0=1000000.0, weight_decay=0) |
功能:
ASGD 也成为 SAG,均表示随机平均梯度下降 (Averaged Stochastic Gradient Descent),简单地说 ASGD 就是用空间换时间的一种 SGD,详细可参看论文:http://riejohnson.com/rie/stograd_nips.pdf
参数:
params(iterable) - 参数组 (参数组的概念请查看 3.1 优化器基类:Optimizer),优化器要优化的那些参数。
lr(float) - 初始学习率,可按需随着训练过程不断调整学习率。
lambd(float) - 衰减项,默认值 1e-4。
alpha(float) - power for eta update ,默认值 0.75。
t0(float) - point at which to start averaging,默认值 1e6。
weight_decay(float) - 权值衰减系数,也就是 L2 正则项的系数。
3 torch.optim.Rprop
1 | class torch.optim.Rprop(params, lr=0.01, etas=(0.5, 1.2), step_sizes=(1e-06, 50)) |
功能:
实现 Rprop 优化方法 (弹性反向传播),优化方法原文《Martin Riedmiller und Heinrich Braun: Rprop - A Fast Adaptive Learning Algorithm. Proceedings of the International Symposium on Computer and Information Science VII, 1992》
该优化方法适用于 full-batch,不适用于 mini-batch,因而在 min-batch 大行其道的时代里,很少见到。
4 torch.optim.Adagrad
1 | class torch.optim.Adagrad(params, lr=0.01, lr_decay=0, weight_decay=0, initial_accumulator_value=0) |
功能:
实现 Adagrad 优化方法 (Adaptive Gradient),Adagrad 是一种自适应优化方法,是自适应的为各个参数分配不同的学习率。这个学习率的变化,会受到梯度的大小和迭代次数的影响。梯度越大,学习率越小;梯度越小,学习率越大。缺点是训练后期,学习率过小,因为 Adagrad 累加之前所有的梯度平方作为分母。
详细公式请阅读:Adaptive Subgradient Methods for Online Learning and Stochastic Optimization
John Duchi, Elad Hazan, Yoram Singer; 12(Jul):2121?2159, 2011.(http://www.jmlr.org/papers/volume12/duchi11a/duchi11a.pdf)
5 torch.optim.Adadelta
1 | class torch.optim.Adadelta(params, lr=1.0, rho=0.9, eps=1e-06, weight_decay=0) |
功能:
实现 Adadelta 优化方法。Adadelta 是 Adagrad 的改进。Adadelta 分母中采用距离当前时间点比较近的累计项,这可以避免在训练后期,学习率过小。
详细公式请阅读:https://arxiv.org/pdf/1212.5701.pdf
6 torch.optim.RMSprop
1 | class torch.optim.RMSprop(params, lr=0.01, alpha=0.99, eps=1e-08, weight_decay=0, momentum=0, centered=False) |
功能:
实现 RMSprop 优化方法(Hinton 提出),RMS 是均方根(root meam square)的意思。RMSprop 和 Adadelta 一样,也是对 Adagrad 的一种改进。RMSprop 采用均方根作为分母,可缓解 Adagrad 学习率下降较快的问题。并且引入均方根,可以减少摆动,详细了解可读:http://www.cs.toronto.edu/~tijmen/csc321/slides/lecture_slides_lec6.pdf
7 torch.optim.Adam(AMSGrad)
1 | class torch.optim.Adam(params, lr=0.001, betas=(0.9, 0.999), eps=1e-08, weight_decay=0, amsgrad=False) |
功能:
实现 Adam (Adaptive Moment Estimation)) 优化方法。Adam 是一种自适应学习率的优化方法,Adam 利用梯度的一阶矩估计和二阶矩估计动态的调整学习率。吴老师课上说过,Adam 是结合了 Momentum 和 RMSprop,并进行了偏差修正。
参数:
amsgrad- 是否采用 AMSGrad 优化方法,asmgrad 优化方法是针对 Adam 的改进,通过添加额外的约束,使学习率始终为正值。(AMSGrad,ICLR-2018 Best-Pper 之一,《On the convergence of Adam and Beyond》)。
详细了解 Adam 可阅读,Adam: A Method for Stochastic Optimization (https://arxiv.org/abs/1412.6980)。
8 torch.optim.Adamax
1 | class torch.optim.Adamax(params, lr=0.002, betas=(0.9, 0.999), eps=1e-08, weight_decay=0) |
功能:
实现 Adamax 优化方法。Adamax 是对 Adam 增加了一个学习率上限的概念,所以也称之为 Adamax。
详细了解可阅读,Adam: A Method for Stochastic Optimization (https://arxiv.org/abs/1412.6980)(没错,就是 Adam 论文中提出了 Adamax)。
9 torch.optim.SparseAdam
1 | class torch.optim.SparseAdam(params, lr=0.001, betas=(0.9, 0.999), eps=1e-08) |
功能:
针对稀疏张量的一种 “阉割版” Adam 优化方法。
only moments that show up in the gradient get updated, and only those portions of the gradient get applied to the parameters
10 torch.optim.LBFGS
1 | class torch.optim.LBFGS(params, lr=1, max_iter=20, max_eval=None, tolerance_grad=1e-05, tolerance_change=1e-09, history_size=100, line_search_fn=None) |
功能:
实现 L-BFGS(Limited-memory Broyden–Fletcher–Goldfarb–Shanno)优化方法。L-BFGS 属于拟牛顿算法。L-BFGS 是对 BFGS 的改进,特点就是节省内存。
优化器中最重要的一个参数就是学习率,合理的学习率可以使优化器快速收敛。一般在训练初期给予较大的学习率,随着训练的进行,学习率逐渐减小。学习率什么时候减小,减小多少,这就涉及到学习率调整方法。
PyTorch 中提供了六种方法供大家使用,下面将一一介绍,最后对学习率调整方法进行总结。
1 lr_scheduler.StepLR
1 | class torch.optim.lr_scheduler.StepLR ( optimizer , step_size , gamma=0.1 , last_epoch=-1 ) |
功能:
等间隔调整学习率,调整倍数为 gamma 倍,调整间隔为 step_size。间隔单位是 step。需要注意的是,step 通常是指 epoch,不要弄成 iteration 了。
参数:
- 学习率下降间隔数,若为 30,则会在 30、60、90… 个 step 时,将学习率调整为 lr*gamma。
- 学习率调整倍数,默认为 0.1 倍,即下降 10 倍。
- 上一个 epoch 数,这个变量用来指示学习率是否需要调整。当 last_epoch 符合设定的间隔时,就会对学习率进行调整。当为 - 1 时,学习率设置为初始 值。
2 lr_scheduler.MultiStepLR
1 | class torch.optim.lr_scheduler.MultiStepLR ( optimizer , milestones , gamma=0.1 , last_epoch=-1 ) |
功能:
按设定的间隔调整学习率。这个方法适合后期调试使用,观察 loss 曲线,为每个实验定制学习率调整时机。
参数:
- 一个 list,每一个元素代表何时调整学习率,list 元素必须是递增的。如 milestones=[30,80,120]
- 学习率调整倍数,默认为 0.1 倍,即下降 10 倍。
- 上一个 epoch 数,这个变量用来指示学习率是否需要调整。当 last_epoch 符合设定的间隔时,就会对学习率进行调整。当为 - 1 时,学习率设置为初始值。
3 lr_scheduler.ExponentialLR
1 | class torch.optim.lr_scheduler.ExponentialLR ( optimizer , gamma , last_epoch=-1 ) |
功能:
按指数衰减调整学习率,调整公式: lr=lr * gammaepoch
参数:
- 学习率调整倍数的底,指数为 epoch,即 gammaepoch
- 上一个 epoch 数,这个变量用来指示学习率是否需要调整。当 last_epoch 符合设定的间隔时,就会对学习率进行调整。当为 - 1 时,学习率设置为初始值。
4 lr_scheduler.CosineAnnealingLR
1 | class torch.optim.lr_scheduler.CosineAnnealingLR ( optimizer , T_max , eta_min=0 , last_epoch=-1 ) |
以余弦函数为周期,并在每个周期最大值时重新设置学习率。具体如下图所示
详细请阅读论文《 SGDR: Stochastic Gradient Descent with Warm Restarts》(ICLR-2017): https://arxiv.org/abs/1608.03983
参数:
- 一次学习率周期的迭代次数,即 T_max 个 epoch 之后重新设置学习率。
- 最小学习率,即在一个周期中,学习率最小会下降到 eta_min,默认值为 0。
学习率调整公式为:
可以看出是以初始学习率为最大学习率,以 2*Tmax 为周期,在一个周期内先下降,后上升。
5 lr_scheduler.ReduceLROnPlateau
1 | class torch.optim.lr_scheduler.ReduceLROnPlateau ( optimizer , mode='min' ,factor=0.1 , patience=10 , verbose=False , threshold=0.0001 , threshold_mode='rel' , cooldown=0 , min_lr=0 , eps=1e-08 ) |
功能:
当某指标不再变化(下降或升高),调整学习率,这是非常实用的学习率调整策略。
例如,当验证集的 loss 不再下降时,进行学习率调整;或者监测验证集的 accuracy,当 accuracy 不再上升时,则调整学习率。
参数:
- 模式选择,有 min 和 max 两种模式,min 表示当指标不再降低 (如监测 loss),max 表示当指标不再升高 (如监测 accuracy)。
- 学习率调整倍数 (等同于其它方法的 gamma),即学习率更新为 lr=lr *factor
- 直译 ——“耐心”,即忍受该指标多少个 step 不变化,当忍无可忍时,调整学习率。
- 是否打印学习率信息, print (‘Epoch {:5d}: reducing learning rate’ ’ of group {} to {:.4e}.’.format (epoch, i, new_lr))
- Threshold for measuring the new optimum ,配合 threshold_mode 使用。
- 选择判断指标是否达最优的模式,有两种模式,rel 和 abs。
当 threshold_mode==rel,并且 mode==max 时, dynamic_threshold=best * (1 +threshold) ;
当 threshold_mode==rel,并且 mode==min 时, dynamic_threshold=best * (1 -threshold) ;
当 threshold_mode==abs,并且 mode==max 时, dynamic_threshold=best + threshold ;
当 threshold_mode==abs,并且 mode==min 时, dynamic_threshold=best - threshold
cooldown (int)- “ 冷却时间 “ ,当调整学习率之后,让学习率调整策略冷静一下,让模型再训练一段时间,再重启监测模式。
min_lr (float or list)- 学习率下限,可为 float ,或者 list ,当有多个参数组时,可用 list 进行设置。
eps (float)- 学习率衰减的最小值,当学习率变化小于 eps 时,则不调整学习率。
6 lr_scheduler.LambdaLR
1 | class torch.optim.lr_scheduler.LambdaLR ( optimizer , lr_lambda , last_epoch=-1 ) |
功能:
为不同参数组设定不同学习率调整策略。调整规则为,lr=base_lr *lmbda (self.last_epoch) 。
参数:
- 一个计算学习率调整倍数的函数,输入通常为 step,当有多个参数组时,设为 list。
- 上一个 epoch 数,这个变量用来指示学习率是否需要调整。当 last_epoch 符合设定的间隔时,就会对学习率进行调整。当为 - 1 时,学习率设置为初始值。
1 | 例如: |
为什么第一个参数组的学习率会是 0 呢? 来看看学习率是如何计算的。
第一个参数组的初始学习率设置为 0.001, lambda1=lambda epoch: epoch // 3,
第 1 个 epoch 时,由 lr=base_lr * lmbda (self.last_epoch),可知道 lr=0.001 *
(0//3) ,又因为 1//3 等于 0,所以导致学习率为 0。
第二个参数组的学习率变化,就很容易看啦,初始为 0.1,lr=0.1 * 0.95^epoch ,当 epoch 为 0 时,lr=0.1 ,epoch 为 1 时,lr=0.1*0.95。
学习率调整小结
PyTorch 提供了六种学习率调整方法,可分为三大类,分别是
- 有序调整;
- 自适应调整;
- 自定义调整。
第一类,依一定规律有序进行调整,这一类是最常用的,分别是等间隔下降 (Step),按需设定下降间隔 (MultiStep),指数下降 (Exponential) 和 CosineAnnealing。这四种方法的调整时机都是人为可控的,也是训练时常用到的。
第二类,依训练状况伺机调整,这就是 ReduceLROnPlateau 方法。该法通过监测某一指标的变化情况,当该指标不再怎么变化的时候,就是调整学习率的时机,因而属于自适应的调整。
第三类,自定义调整,Lambda。Lambda 方法提供的调整策略十分灵活,我们可以为不同的层设定不同的学习率调整方法,这在 fine-tune 中十分有用,我们不仅可为不同的层设定不同的学习率,还可以为其设定不同的学习率调整策略,简直不能更棒!