赞
踩
学习知识先有框架(至少先知道有啥东西)然后再通过实战(各个东西具体咋用)来填充这个框架。 而这个系列的目的就是在脑海中先建一个Pytorch的基本框架出来。
通过上一次的学习,完成了模型模块和损失函数,对模型的权值初始化和损失函数介绍有了基本认识,接下来主要是进行优化器和学习率调整策略的学习。
我们知道损失函数的作用是衡量模型输出与真实标签的差异,当我们有了这个loss之后,我们就可以通过反向传播机制得到参数的梯度,那么我们如何利用这个梯度进行更新参数使得模型的loss逐渐的降低呢?这个就是优化器干的活了,所以今天开始进入优化器模块,首先学习优化器的概念,然后学习优化器的属性和方法,介绍常用的优化器的原理。 关于优化器,最重要的一个参数就是学习率,这个控制着参数更新的一个步伐, 在模型训练中,对于学习率的调整也是非常关键的,所以最后整理一些关于学习率调整的六种策略。
我们知道了机器学习的五个步骤: 数据 -> 模型 -> 损失 -> 优化器 -> 迭代训练
。 我们通过前向传播的过程,得到了模型输出与真实标签的差异,我们称之为损失, 有了损失后进入反向传播过程得到参数的梯度,优化器要根据我们的这个梯度去更新参数,使得损失不断的降低。 那么优化器是怎么做到的呢? 下面我们从三部分进行展开,首先是优化器的概念,然后是优化器的属性和方法,最后是常用的优化器。
Pytorch的优化器: 管理并更新模型中可学习参数的值, 使得模型输出更接近真实标签。
我们在更新参数的时候一般使用梯度下降的方式去更新, 那么什么是梯度下降呢? 说这个问题之前得先区分几个概念:
我们知道梯度是一个向量,它的方向是导数取得最大值的方向,也就是增长最快的方向,而梯度下降就是沿着梯度的负方向去变化,这样函数的下降也是最快的。所以我们往往采用梯度下降的方式去更新权值,使得函数的下降尽量的快。
Pytorch里面优化器的基本属性
学习优化器具体的方法
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=β∗vt−1+(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=i∑100(1−β)∗βi∗θ100−i
我们发现,距离当前时刻越远的那些 θ \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中是怎么实现的
SGD优化器
学习率是可以控制更新的步伐的。 我们在训练模型的时候,一般开始的时候学习率会比较大,这样可以以一个比较快的速度到达最优点的附近,然后再把学习率降下来, 缓慢的去收敛到最优值。
在模型的训练过程中,调整学习率也是非常重要的,学习率前期要大,后期要小。Pytorch中提供了一个很好的学习率的调整方法,下面我们就来具体学习,学习率该如何进行调整。
主要属性:
主要方法:
看看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=lr∗gamma, 这里的gamma一般是0.1-0.5。 用的时候就是我们指定step_size,比如50, 那么就是50个epoch调整一次学习率,调整的方式就是 l r = l r ∗ g a m m a lr=lr∗gamma lr=lr∗gamma.
2、MultiStepLR(按给定间隔调整学习率)
这里的milestones表示设定调整时刻数, gamma也是调整系数,调整方式依然是 l r = l r ∗ g a m m a lr=lr∗gamma lr=lr∗gamma,, 只不过和上面不同的是,这里的间隔我们可以自己调,构建一个list,比如[50, 125, 150], 放入到milestones中,那么就是50个epoch,125个epoch,150个epoch调整一次学习率。
小结一下:
调整策略就基本完了,那么我们得先有个初始的学习率啊, 下面介绍两种学习率初始化的方式:
今天的内容主要是分为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
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。