当前位置:   article > 正文

系统学习Pytorch笔记六:优化器和学习率调整策略_optim.adamax sgd

optim.adamax sgd

优化器和学习率调整策略

背景

学习知识先有框架(至少先知道有啥东西)然后再通过实战(各个东西具体咋用)来填充这个框架。 而这个系列的目的就是在脑海中先建一个Pytorch的基本框架出来。

通过上一次的学习,完成了模型模块和损失函数,对模型的权值初始化和损失函数介绍有了基本认识,接下来主要是进行优化器和学习率调整策略的学习。

我们知道损失函数的作用是衡量模型输出与真实标签的差异,当我们有了这个loss之后,我们就可以通过反向传播机制得到参数的梯度,那么我们如何利用这个梯度进行更新参数使得模型的loss逐渐的降低呢?这个就是优化器干的活了,所以今天开始进入优化器模块,首先学习优化器的概念,然后学习优化器的属性和方法,介绍常用的优化器的原理。 关于优化器,最重要的一个参数就是学习率,这个控制着参数更新的一个步伐, 在模型训练中,对于学习率的调整也是非常关键的,所以最后整理一些关于学习率调整的六种策略。

优化器

我们知道了机器学习的五个步骤: 数据 -> 模型 -> 损失 -> 优化器 -> 迭代训练。 我们通过前向传播的过程,得到了模型输出与真实标签的差异,我们称之为损失, 有了损失后进入反向传播过程得到参数的梯度,优化器要根据我们的这个梯度去更新参数,使得损失不断的降低。 那么优化器是怎么做到的呢? 下面我们从三部分进行展开,首先是优化器的概念,然后是优化器的属性和方法,最后是常用的优化器。

什么是优化器

Pytorch的优化器: 管理并更新模型中可学习参数的值, 使得模型输出更接近真实标签。

我们在更新参数的时候一般使用梯度下降的方式去更新, 那么什么是梯度下降呢? 说这个问题之前得先区分几个概念:

  • 导数: 函数在指定坐标轴上的变化率
  • 方向导数: 指定方向上的变化率
  • 梯度: 一个向量, 方向为方向导数取得最大值的方向

我们知道梯度是一个向量,它的方向是导数取得最大值的方向,也就是增长最快的方向,而梯度下降就是沿着梯度的负方向去变化,这样函数的下降也是最快的。所以我们往往采用梯度下降的方式去更新权值,使得函数的下降尽量的快。

优化器基本属性和方法

Pytorch里面优化器的基本属性
在这里插入图片描述

  • defaults: 优化器超参数,里面会存储一些学习率, momentum的值,衰减系数等
  • state: 参数的缓存, 如momentum的缓存(使用前几次梯度进行平均)
  • param_groups: 管理的参数组, 这是个列表,每一个元素是一个字典,在字典中有key,key里面的值才是我们真正的参数(这个很重要, 进行参数管理)

优化器里面的基本方法

在这里插入图片描述

  • zero_grad(): 清空所管理参数的梯度, 这里注意Pytorch有一个特性就是张量梯度不自动清零
  • step(): 执行一步更新
  • add_param_group(): 添加参数组, 我们知道优化器管理很多参数,这些参数是可以分组的,我们对不同组的参数可以设置不同的超参数, 比如模型finetune中,我们希望前面特征提取的那些层学习率小一些,而后面我们新加的层学习率大一些更新快一点,就可以用这个方法。
  • state_dict(): 获取优化器当前状态信息字典
  • load_state_dict(): 加载状态信息字典,这两个方法用于模型断点的一个续训练, 所以我们在模型训练的时候,一般多少个epoch之后就要保存当前的状态信息。

学习优化器具体的方法
1、step(): 一次梯度下降更新参数

在这里插入图片描述

2、zero_grad(): 将梯度清零

在这里插入图片描述
3、add_param_group(): 添加参数组
在这里插入图片描述

4、state_dict()和load_state_dict()
这两个方法用于保存和加载优化器的一个状态信息,通常用在断点的续训练, 比如我们训练一个模型,训练了10次停电了, 那么再来电的时候我们就得需要从头开始训练,但是如果有了这两个方法,我们就可以再训练的时候接着上次的次数继续, 所以这两个也非常实用。

state_dict()
在这里插入图片描述
state_dict()方法里面保存了我们优化器的各种状态信息,我们通过torch.save就可以保存这些状态到文件(.pkl), 这样假设此时停电了。 好,我们就可以通过load_state_dict()来导入这个状态信息,让优化器在这个基础上进行训练
在这里插入图片描述

优化器基本概念

介绍这些优化器之前,得先学习两个非常重要的概念:学习率和动量。

学习率

在梯度下降过程中,学习率起到了控制参数更新的一个步伐的作用。

随着迭代次数的增加,损失反而越增越大, 就是因为这个步子太大了,跳过了我们的最优值。所以这时候我们想让他这个跨度小一些,就得需要一个参数来控制我们的这个跨度,这个就是学习率。

在这里插入图片描述
上面的图像,loss是不断上升的,这说明这个跨度是有问题的,所以下面我们尝试改小一点学习率

在这里插入图片描述

当loss上升不降的时候,有可能是学习率的问题,所以我们一般会尝试一个小的学习率。 慢慢的去进行优化。学习率一般是我们需要调的一个非常重要的超参数, 我们一般是给定一个范围,然后画出loss的变化曲线,看看哪学习率比较好,当然下面也会重点学习学习率的调整策略。
在这里插入图片描述

动量

Momentum:结合当前梯度与上一次更新信息, 用于当前更新。考虑了上一次的更新信息,相当于加了一个惯性,使得经过局部最优解时不容易卡住,即更有可能达到全局最优解。

这个动量是怎么作用于我们的更新的呢?先学习一个概念叫做指数加权平均。

指数加权平均在时间序列中经常用于求取平均值的一个方法,它的思想是这样,我们要求取当前时刻的平均值,距离当前时刻越近的那些参数值,它的参考性越大,所占的权重就越大,这个权重是随时间间隔的增大呈指数下降,所以叫做指数滑动平均。公式如下

v t = β ∗ v t − 1 + ( 1 − β ) ∗ θ t ​ v_{t} =β∗v_{t−1} +(1−β)∗θ_{t}​ vt=βvt1+(1β)θt


v t v_{t} vt是当前时刻的一个平均值,这个平均值有两项构成,一项是当前时刻的参数值 θ t \theta_{t} θt , 所占的权重是 1 − β 1-\beta 1β, 这个 β \beta β是个参数。 另一项是上一时刻的一个平均值, 权重是 β \beta β

假设我想求第100天温度的一个平均值,那么根据上面的公式

v 100 = β ∗ v 99 + ( 1 − β ) ∗ θ 100 = ∑ i 100 ( 1 − β ) ∗ β i ∗ θ 100 − i ​​ v_{100}=β∗v_{99}+(1−β)∗θ_{100} =∑_{i}^{100}(1−β)∗β^i∗θ _{100−i}​ ​ v100=βv99+(1β)θ100=i100(1β)βiθ100i​​

我们发现,距离当前时刻越远的那些 θ \theta θ值,它的权重是越来越小的,因为 β \beta β小于1, 所以间隔越远,小于1的这些数连乘,权重越来越小,而且是呈指数下降,因为这里是 β i \beta ^i βi , 下面通过代码看一下这个权重,也就是 ( 1 − β ) ∗ β i (1-\beta)*\beta^i (1β)βi是怎么变化的

在这里插入图片描述

距离当前时刻越远,对当前时刻的一个平均值影响就越小。距离当前时刻越近,对当前时刻的一个平均值影响越大,这就是指数加权平均的思想了。
下面看下不同的超参数 β \beta β来观察一下这个权重的变化曲线:
在这里插入图片描述

可以发现,beta越小,就会发现它关注前面一段时刻的距离就越短,比如这个0.8, 会发现往前关注20天基本上后面的权重都是0了,意思就是说这时候是平均的过去20天的温度, 而0.98这个,会发现,关注过去的天数会非常长,也就是说这时候平均的过去50天的温度。所以beta在这里控制着记忆周期的长短,或者平均过去多少天的数据,这个天数就是 1 1 − β \frac{1}{1-\beta} 1β1, 通常beta设置为0.9, 物理意义就是关注过去10天左右的一个温度。

可以发现,如果这个β很高, 比如0.98, 最终得到的温度变化曲线就会平缓一些,因为多平均了几天的温度, 缺点就是曲线进一步右移, 因为现在平均的温度值更多, 要平均更多的值, 指数加权平均公式,在温度变化时,适应的更缓慢一些,所以会出现一些延迟,因为如果β=0.98,这就相当于给前一天加了太多的权重,只有0.02当日温度的权重,所以温度变化时,温度上下起伏,当β变大时,指数加权平均值适应的更缓慢一些, 换了0.5之后,由于只平均两天的温度值,平均的数据太少,曲线会有很大的噪声,更有可能出现异常值,但这个曲线能够快速适应温度的变化。 所以这个β过大过小,都会带来问题。 一般取0.9.

看看我们的Momentum了,其实所谓的Momentum梯度下降基本的想法是计算梯度的指数加权平均数,并利用该梯度更新权重, 我们看看在Pytorch中是怎么实现的

在这里插入图片描述

常用优化器介绍

  • optim.SGD: 随机梯度下降法是最初的、也是最常用的优化器,
  • optim.Adagrad: 自适应学习率梯度下降法
  • optim.RMSprop:Adagrad的改进
  • optim.Adadelta: Adagrad的改进
  • optim.Adam: RMSprop结合Momentum
  • optim.Adamax: Adam增加学习率上限
  • optim.SparseAdam: 稀疏版的Adam
  • optim.ASGD:随机平均梯度下降
  • optim.Rprop: 弹性反向传播
  • optim.LBFGS: BFGS的改进

SGD优化器

在这里插入图片描述

  • param: 管理的参数组
  • lr: 初始学习率
  • momentum:动量系数, beta
  • weight_decay: L2正则化系数
  • nesterov: 是否采用NAG

学习率调整策略

为什么要调整学习率

学习率是可以控制更新的步伐的。 我们在训练模型的时候,一般开始的时候学习率会比较大,这样可以以一个比较快的速度到达最优点的附近,然后再把学习率降下来, 缓慢的去收敛到最优值。

在这里插入图片描述
在模型的训练过程中,调整学习率也是非常重要的,学习率前期要大,后期要小。Pytorch中提供了一个很好的学习率的调整方法,下面我们就来具体学习,学习率该如何进行调整。

Pytorch的学习率调整策略

在这里插入图片描述

主要属性:

  • optimizer: 关联的优化器, 得需要先关联一个优化器,然后再去改动学习率
  • last_epoch: 记录epoch数, 学习率调整以epoch为周期
  • base_lrs: 记录初始学习率

在这里插入图片描述
主要方法:

  • step(): 更新下一个epoch的学习率, 这个是和用户对接
  • get_lr(): 虚函数, 计算下一个epoch的学习率, 这是更新过程中的一个步骤

看看LRScheduler的构建和使用

在这里插入图片描述
1、父类的这个__init__怎么去构建一个最基本的Scheduler

在这里插入图片描述
2、调用step()方法更新学习率

在这里插入图片描述
进入了_LRScheduler的step函数
在这里插入图片描述
发现跳到了我们的StepLR这个类里面,因为我们说过,这个get_lr在基类里面是个虚函数,我们后面编写的Scheduler要继承这个基类,并且要覆盖这个get_lr函数,把怎么减学习率通过这个函数告诉程序:
在这里插入图片描述

关于优化器的定义和使用的内部运行原理稍微总结下,首先在定义优化器的时候,完成优化器的初始化工作, 主要有关联优化器(self.optimizer属性), 然后初始化last_epoch和base_lrs(记录原始的学习率,后面get_lr方法会用到)。 然后就是用Scheduler,我们是直接用的step()方法进行更新下一个epoch的学习率(这个千万要注意放到epoch的for循环里面而不要放到batch的循环里面 ),而这个内部是在_Scheduler类的step()方法里面调用了get_lr()方法, 而这个方法需要我们写Scheduler的时候自己覆盖,告诉程序按照什么样的方式去更新学习率,这样程序根据具体方式去计算出下一个epoch的学习率,然后直接更新进优化器的_param_groups()里面去。

Pytorch提供的几种学习率调整策略

可参考pytorch文档https://pytorch.org/docs/stable/optim.html?highlight=optimizer#torch.optim.Optimizer

在这里插入图片描述
在这里插入图片描述

1、StepLR(等间隔调整学习率)

step_size表示调整间隔数, gamma表示调整系数, 调整方式就是 l r = l r ∗ g a m m a lr=lr∗gamma lr=lrgamma, 这里的gamma一般是0.1-0.5。 用的时候就是我们指定step_size,比如50, 那么就是50个epoch调整一次学习率,调整的方式就是 l r = l r ∗ g a m m a lr=lr∗gamma lr=lrgamma.

2、MultiStepLR(按给定间隔调整学习率)

这里的milestones表示设定调整时刻数, gamma也是调整系数,调整方式依然是 l r = l r ∗ g a m m a lr=lr∗gamma lr=lrgamma,, 只不过和上面不同的是,这里的间隔我们可以自己调,构建一个list,比如[50, 125, 150], 放入到milestones中,那么就是50个epoch,125个epoch,150个epoch调整一次学习率。

小结一下:

  • 有序调整: Step、MultiStep、 Exponential和CosineAnnealing, 这些得事先知道学习率大体需要在多少个epoch之后调整的时候用
  • 自适应调整: ReduceLROnPleateau, 这个非常实用,可以监控某个参数,根据参数的变化情况自适应调整
  • 自定义调整:Lambda, 这个在模型的迁移中或者多个参数组不同学习策略的时候实用

调整策略就基本完了,那么我们得先有个初始的学习率啊, 下面介绍两种学习率初始化的方式:

  • 设置较小数:0.01, 0.001, 0.0001
  • 搜索最大学习率: 看论文《Cyclical Learning Rates for Training Neural Networks》, 这个就是先让学习率从0开始慢慢的增大,然后观察acc, 看看啥时候训练准确率开始下降了,就把初始学习率定为那个数

总结

今天的内容主要是分为2大块, 第一块就是优化器模块,学习了优化器的基本属性和方法,并通过代码调试的方式了解了优化器的初始化和使用原理。 然后学习了常用的优化器,介绍了两个非常关键的概念学习率动量

然后学习了学习率调整策略的相关知识,学习了为什么要调整学习率以及pytorch中常见的学习率调整策略。

关于Pytorch的优化器,到这里就基本结束, 我们的逻辑就是按照机器学习的那五大步骤进行的查看, 数据模块 -> 模型模块 -> 损失函数 -> 优化器 -> 迭代训练等,后面进入迭代训练部分。

参考:
[1]: https://zhongqiang.blog.csdn.net/article/details/105612559
[2]: https://pytorch.org/docs/stable/torch.html
[3]: https://blog.csdn.net/weixin_45653897/article/details/130195505

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/在线问答5/article/detail/902810
推荐阅读
相关标签
  

闽ICP备14008679号