深度学习基础知识(七)--- 各种优化方法

2020-02-18 16:07:24 浏览数 (1)

深度学习常用的优化方法

参考资料:《Deep Learning》、pytorch 文档

深度学习中,优化算法的 目标函数 通常是一个基于训练集的损失函数,优化的目标在于降低训练误差。

这意味着用训练集上的 经验分布 代替 真实分布

最小化这种平均训练误差的训练过程,被称为经验风险最小化(empirical risk minimization)

1.Stochastic Gradient Descent

虽然是讲随机梯度下降,但是还是也介绍一下 梯度下降的3兄弟

●批量梯度下降(Batch Gradient Descent):使用整个训练集的样本,通常是能到达局部最小点的。

●随机梯度下降(Stochastic Gradient Descent):每次只使用单个样本,也被称为online(在线)算法;

会向着局部最小逼近,但是最终无法到达局部最小点

●小批量梯度下降(Mini-Batch GraMini-Batchdient Descent):每次使用一个以上而又不是全部的训练样本

深度学习中一般都是采用的小批量(Mini-Batch)梯度下降,通常简单的将它们称为随机(Stochastic),具体实践中,通常将mini-batch的大小设置为 2的整数次方,例如 2、4、8、16...

算法如下:

使用SGD算法,最主要的就是要选择合适的Batch_Size

 a. 内存利用率提高了,大矩阵乘法的并行化效率提高。

 b. 在一定范围内,一般来说 Batch_Size 越大,其确定的下降方向越准。

pytorch 上有此优化器模块,torch.optim.SGD

2.Momentum 动量

是对随机梯度下降算法的一种优化,目的是加速学习

SGD有一个缺点,其更新方向完全依赖于当前的batch计算的梯度,更新参数时可能在一些区域出现震荡。解决这一问题的一个简单的做法便是引入momentum--动量:它模拟的是物体运动时的惯性。

动量算法 积累了之前梯度 指数级衰减的移动平均,并且继续沿着该方向移动

说白一点,就是更新参数的时候在一定程度上保留之前更新的方向,同时利用当批次的计算出的梯度微调,

并得到最终的更新方向。

更新规则如下:

可以看到,先计算当前的梯度,

然后叠加上: 超参数 α 乘以 积累的动量 v 这一项;得到新的方向v;

然后再沿着此方向更新参数值θ;

这样可以在一定程度上增加稳定性,减少训练震荡过程,加速学习

momentum超参数(也就是上式中的α)一般取值为 0.5、0.9、0.99.

将动量超参数视为 1/(1-momentum) 有助于理解,例如 0.9 对应着最大速度 10倍于梯度下降算法。

和学习率一样,momentum也会随着时间不断调整,一般初始值是一个较小的值,因为一开始的梯度会很大,随着梯度值逐渐减小,momentum的值可以慢慢变大。

pytorch上直接通过在SGD方面里面添加momentum参数:

torch.optim.SGD(xxx, xxx, momentum=0.9)

3.NAG --- Nesterov Accelerated Gradient

这又是对momentum 方法的改进,其速度更快:

我们从更新公式中就能看到其与标准动量算法的区别,

那就是在计算当前批次梯度的时候,已经考虑进了之前积累的动量,也就是超前计算梯度

但是要注意的是,后面更新参数的时候,却不是基于超前点更新的。具体来说如下:

先假设我们沿着动量方向更新了参数θ' := θ α v;

在 θ' 的基础上计算本次迭代的梯度, 然后叠加之前的动量,这一步如同标准动量方法一样;

对 θ更新,而不是对θ' 更新

如图所示:

标准动量算法,先在当前O点计算当前批次的梯度 g0(黑色短线), 然后与O点之前积累的动量V0进行叠加,得到蓝色的线 V1,则O点参数就朝着蓝色方向更新;

但是Nestrov方法,先假设O点沿着V0方向更新了参数到了另一个点然后在这个点上计算梯度g0',(黄色的短线),然后此梯度与V0进行叠加,得到更新方向V1',即黄色的长线,那么O点就朝着黄色方向更新。

pytorch上面直接把SGD中的nestrov开关打开:

torch.optim.SGD(xxx, xxx, momentum=0.9, nesterov = True)

4.AdaGrad

定义为:此方法独立的适应所有模型参数的学习率,缩放每个参数反比于其所有梯度历史平方值总和的平方根

每个字都认识但是连起来很不好懂……

其实就是说:首先要求梯度平方的积累量

在进行参数更新时,学习速率要除以这个积累量的平方根,(这是个向量)

所以,就是对学习率除以 梯度平方累积和 的开根号,

这样使得梯度大的参数的学习率小,而梯度小的或者更新频率小的参数的学习率大(因此,更AdaGrad适用于稀疏数据)。

算法如图:

优点是:

不用手动调节学习率了,相当于每一次更新学习率都会缩减,因为分母在逐渐积累变大;

目标函数中每个参数都分别拥有自己的学习率,(因为r和g是同维度的向量,相当于是在对每个子分量进行操作);

缺点就是:

由于 积累量不断增加,分母越来越大,可能导致学习率过早和过量减小。

pytorch中有此模块:torch.optim.Adagrad(params, lr=0.01, lr_decay=0, weight_decay=0)

5.RMSProp(Root Mean Square )

对AdaGrad的改进,通过滑动平均去统计梯度的平方,利用该滑动平均的值替换AdaGrad中梯度平方的累加和,如此一来,便不用担心分母越来越大了

相比于AdaGrad的改进,如下图中红色框所示,一般ρ取0.9

pytorch上有此模块:

torch.optim.RMSprop(params, lr=0.01, alpha=0.99, eps=1e-08, weight_decay=0, momentum=0, centered=False)

pytorch貌似默认把ρ设置为0.99,也就是括号中的的 alpha参数

然后pytorch的版本上,可以将RMSProp加入momentum,你会发现那里有一个momentum参数

6.AdaDelta

AdaDelta算法也是对AdaGrad的改进,与RMSProp十分相近,

与RMSProp算法不同的是,AdaDelta可以看作是用 Δθ的 均方根 代替了学习率:

论文:https://arxiv.org/pdf/1212.5701.pdf

下图是论文中的算法图

然后我把上表 “翻译” 了一下

下图是pytorch中的实现方法:我把上面算法表中的步骤注释到了旁边,方便理解。

AdaDelta算法没有学习率超参数,上表中 group[‘lr’]这一参数默认值为1.0,所以我就没有乘上去了

它通过使用有关自变量更新量平方的指数加权移动平均的项来替代RMSProp算法中的学习率。

pytorch实现中,倒数两步的顺序调换了一下,不影响结果

https://pytorch.org/docs/0.4.1/_modules/torch/optim/adadelta.html#Adadelta

7.Adam(Adaptive Moment

同时引入了一阶矩估计量和二阶矩估计量,

而且为了防止零初始化导致的开始阶段积累量较小,还进行了偏差修正操作

具体算法如下图所示:

pytorch上有:

torch.optim.Adam(params, lr=0.001, betas=(0.9, 0.999), eps=1e-08, weight_decay=0)

现在Adam优化方法算是比较常用的一种优化算法了,基本上很多算法都直接用Adam优化方法了

0 人点赞