终于可以开始讲优化算法了(写博客真是太花时间了,不过对于自我总结还是很有帮助的),本篇博客主要参照《Deep Learing》第8章,《深度学习实战》第5章以及清华博士大佬的一篇知乎文章《一个框架看懂优化算法》。
  首先,我们先回顾一下优化算法的发展历程:SDG→→\rightarrowSGDM→→\rightarrowNAG→→\rightarrowAdaGrad→→\rightarrowRMSProp→→\rightarrowAdam→→\rightarrowNadam。我们平时Google,百度会有很多关于这些算法的原理,各算法是怎么一步步演变的文章,而清华大佬换了一个思路,只用一个框架就对所有优化算法进行了梳理,当时看得我茅塞顿开,这里给大家分享一下。

一个框架

  我们首先定义:待优化参数:www,目标函数:L(f(x(i);w),y(i))" role="presentation" style="position: relative;">L(f(x(i);w),y(i))L(f(x(i);w),y(i))L(f(x^{(i)};w),y^{(i)}),学习率:ϵϵ\epsilon
  然后开始迭代优化过程,在每个epochepochepoch ttt:
Step1:计算目标函数关于当前参数的梯度

gt=∇L(f(x(i);wt),y(i))" role="presentation">gt=∇L(f(x(i);wt),y(i))gt=∇L(f(x(i);wt),y(i))

g_t=\nabla L(f(x^{(i)};w_t),y^{(i)})Step2:根据历史梯度计算一阶动量和二阶动量

mt=ϕ(g1,g2,…,gt)mt=ϕ(g1,g2,…,gt)

m_t=\phi(g_1,g_2,\dots,g_t)

Vt=ψ(g1,g2,…,gt)Vt=ψ(g1,g2,…,gt)

V_t=\psi(g_1,g_2,\dots,g_t) Step3:计算当前时刻的下降梯度

ηt=ϵ⋅mtVt−−√ηt=ϵ⋅mtVt

\eta_t=\epsilon \cdot \frac{m_t}{\sqrt{V_t}} Step4:根据当前的下降梯度对参数进行更新

wt+1=wt−ηtwt+1=wt−ηt

w_{t+1}=w_t-\eta_t  不同优化算法的Step3和Step4都是一样的,主要差别体现在Step1和Step2上。接下来我们就按照这个框架来解析一下各个优化算法。

随机梯度下降(Stochastic Gradient Descent,SGD)

  原始的梯度下降是沿着整个训练集的梯度方向下降,因为每次都需要计算所有样本的梯度,计算量可想而知非常大。而SGD是每次按照数据生成分布(独立同分布)抽取mmm个样本作为一个小批量,通过计算它们的梯度均值,可以得到梯度的无偏估计。通过这种方式,可以得到很大程度上的加速:

gt=1m∑i=1m∂L(f(x(i);w),y(i))∂w" role="presentation">gt=1m∑i=1m∂L(f(x(i);w),y(i))∂wgt=1m∑i=1m∂L(f(x(i);w),y(i))∂w

g_t=\frac{1}{m}\sum_{i=1}^m\frac{\partial L(f(x^{(i)};w),y^{(i)})}{\partial w}  SGD中没有动量的概念,即mt=gt;Vt=I2mt=gt;Vt=I2m_t=g_t;V_t=I^2,代入Step3,下降梯度就是最简单的ηt=ϵ⋅gtηt=ϵ⋅gt\eta_t=\epsilon \cdot g_t。至于小批量样本的抽取,仍然是那个老问题——我们无从得知数据真实的生成分布,因此我们在实践中只能尽量保证抽取的随机性(训练集一定要打乱)。这种随机获取mini-batch的方式给算法引入了噪声源,即使算法到达了最优解附近,噪声也不会消失,这也就形成了在最优解附近震荡的现象。为了缓解这种现象,在实践中,有必要随着时间的推移逐渐降低学习率。
  因为梯度下降算法下降的方向为局部最速方向,即它的下降方向在每一个下降点一定与对应的等高线的切线垂直,这导致算法优化通过的路径是锯齿状的,因此只基于梯度的优化算法(包括梯度下降和SGD)最大缺点就是下降速度慢,而且可能在沟壑两边持续震荡,停留在局部最优点。

动量(SGD with Momentum,SGDM)

  为了抑制SGD的震荡,SGDM认为梯度下降过程可以加入惯性。下坡的时候,如果发现是陡坡,就利用惯性跑的快一些,反之则慢一些。SGDM在SGD基础上引入了一阶动量。
  在SGD的梯度下降过程中,每一步走多远是简单的梯度乘以学习率;而在动量学习算法中,一步走多远不仅和当前梯度有关,还和过去的梯度积累有关,步长取决于梯度序列的大小和排序,当许多连续的梯度指向相同的方向时,步长最大。

mt=β1⋅mt−1+(1−β1)⋅gtmt=β1⋅mt−1+(1−β1)⋅gt

m_t=\beta_1 \cdot m_{t-1}+(1-\beta_1)\cdot g_t一阶动量其实就是各个时刻梯度方向的指数移动平均值,约等于最近 11−β111−β1\frac{1}{1-\beta_1}个时刻的梯度向量和的平均值。 β1β1\beta_1在实践中一般取0.5、0.9和0.99,和学习率一样, β1β1\beta_1也会随着时间不断调整,一般初始值是一个较小的值,因为一开始没有积累什么学习经验,所以以当前找到的梯度方向为准;随后慢慢增大 β1β1\beta_1的值,下降方向主要是此前积累的下降方向,避免最后因为优化超平面的波动陷入持续震荡。动量法是令梯度直接指向最优解的策略之一。
  SGDM是一阶动量算法,二阶动量依然为 Vt=I2Vt=I2V_t=I^2。

牛顿动量法(Nesterov Acceleration Gradient,NAG)

  SGD的一个问题是当其困在局部最优的沟壑里面震荡。举个栗子,想象一下你进入到一个盆地,四周都是略高的小山,你觉得没有下坡的方向,那就只能呆在这里了。可是如果你爬上高低,就会发现外面的世界还很广阔。因此我们不能停留在当前位置去观察未来的方向,而要想前一步,多看一步,看远一些。
  在SGDM中,当前时刻的主要下降方向是由积累动量决定的,当前时刻自己的梯度方向说了也不算,那不如先看看沿着积累动量多走一步,那个时候怎么走。NAG在Step1中,不是计算当前位置的梯度方向,而是计算继续沿着动量积累方向多走一步的位置处的梯度方向:

gt=∇L(f(x(i);wt+1)gt=∇L(f(x(i);wt+1)

g_t=\nabla L(f(x^{(i)};w_{t+1})然后用这个表示下一步梯度方向的梯度域历史积累动量结合,计算Step2中当前时刻的积累动量。
  NAG收敛速度更好,防止算法过快且增加了反应性(多走一步的方式具有前瞻性,能及时“刹车”)。NAG也没有用到二阶动量。

AdaGrad(自适应梯度)

  之前的方法所有参数都使用同一个学习率,但损失函数的下降通常高度敏感于参数空间中的某些方向。一阶动量算法可以在一定程度上缓解这些问题,但这样又引入了另一个超参数。如果我们相信方向敏感度在某种程度上是轴对齐的,那么每个参数设置不同的学习率,在整个学习过程中自动适应这些学习率是有道理的。从更直观的角度看,模型中往往包含大量的参数,这些参数并不是总会用的到,对于经常更新的参数,我们已经积累了大量关于它的知识,不希望被单个样本影像太大,希望学习速率慢一些;对于偶尔更新的参数,我们了解的信息太少,希望能从每个偶然出现的样本身上多学一些,即学习速率大一些。二阶动量的出现,意味着“自适应学习率”优化算法时代的到来。
  那么如何去度量一个参数的历史更新频率呢?那就是二阶动量,是至今为止所有梯度值的平方和:

Vt=∑i=1tg2iVt=∑i=1tgi2

V_t=\sum_{i=1}^tg_i^2回顾Step3中的下降梯度公式,可以看出,此时学习率实质上变成了 ϵVt√ϵVt\frac{\epsilon}{\sqrt{V_t}},一般为了避免分母为0,会在分母上加上一个小的平滑项,此时梯度下降更新公式如下:

ηt=ϵ⋅mtVt−−√+δηt=ϵ⋅mtVt+δ

\eta_t=\epsilon \cdot \frac{m_t}{\sqrt{V_t}+\delta}此时,当参数更新越频繁,则 Vt−−√Vt\sqrt{V_t}越大,学习率就越低,是不是很简单?
  AdaGrad在稀疏数据场景下表现的非常好,但因为 Vt−−√Vt\sqrt{V_t}是单调递增的,会使学习率单调递减至0,可能会使训练过程提前结束,即使后续有数据也无法学到必要的知识。所以AdaGrad也对初始值敏感(如果一开始梯度就很大,那么极有可能很快就停止学习)。

RMSProp(均方差传播)

  AdaGrad对历史梯度一视同仁,简单的把所有梯度的平方加起来来衡量参数的更新频率,这中导致学习率单调递减的方式过于激进,RMSProp对其进行了改进。
  RMSProp在AdaGrad基础上引入衰减因子,距离当前时刻越远的梯度影响越小,即主要关注一段时间窗口内的下降梯度:

Vt=β2⋅Vt−1+(1−β2)⋅g2tVt=β2⋅Vt−1+(1−β2)⋅gt2

V_t=\beta_2 \cdot V_{t-1}+(1-\beta_2) \cdot g_t^2如果最近一段时间某个参数更新的很频繁,那么久选择较小的更新幅度;如果最近一段时间几乎没有更新,则选择大幅度更新一下。这样就避免了二阶动量持续积累,导致训练过程提早结束的问题。

Adam

  讲到这里,Adam的出现就很自然而然了——它是前述方法的集大成者。SGDM在SGD基础上增加了一阶动量来抑制震荡现象,AdaGrad和RMSProp在SGD基础上增加了二阶动量实现各个参数学习率的自适应调整。将一阶动量和二阶动量都用起来就是Adam了。

mt=β1⋅mt−1+(1−β1)⋅gtVt=β2⋅Vt−1+(1−β2)⋅g2tmt=β1⋅mt−1+(1−β1)⋅gtVt=β2⋅Vt−1+(1−β2)⋅gt2

m_t=\beta_1 \cdot m_{t-1}+(1-\beta_1)\cdot g_t\\ V_t=\beta_2 \cdot V_{t-1}+(1-\beta_2) \cdot g_t^2在实际应用中,参数的经验值是 β1=0.9,β2=0.999β1=0.9,β2=0.999\beta_1=0.9,\beta_2=0.999, m0m0m_0和 V0V0V_0一般初始化为0,这就会导致在初期 mtmtm_t和 VtVtV_t都会接近0,这是有问题的。因此我们常常会用下面的式子进行误差修正:

m~t=mt1−βt1V~t=Vt1−βt2m~t=mt1−β1tV~t=Vt1−β2t

\tilde m_t=\frac{m_t}{1-\beta_1^t} \\ \tilde V_t=\frac{V_t}{1-\beta_2^t}于是在初期( ttt较小)的时候mt" role="presentation" style="position: relative;">mtmtm_t和 VtVtV_t会除以一个小于1的数,得到了放大,避免了初期接近0的情况;随着迭代的进行, βt≈0βt≈0\beta^t \approx 0,有 m~t≈mtm~t≈mt\tilde m_t \approx m_t, V~t≈VtV~t≈Vt\tilde V_t \approx V_t,在后期就不需要对一阶二阶动量进行放大了。

Nadam

  有了前面的基础,Nadam就不需要怎么展开了。Nadam就是在Adam的基础上引入了Nestrov,即在计算梯度时多看一步。


Adam的缺陷

  到这里,大概明白了为什么说Adam/Nadam是目前最主流最好用的方法。但是人无完人,Adam依然存在两个很重要的缺陷。
1. 可能不收敛
  回忆一下之前的各个优化算法,SGD没有用到二阶动量,因此学习率是恒定的(实际使用中会采用学习率递减)。AdaGrad是二阶动量不断积累,最终学习率衰减到0,模型得以收敛。
  而RMSProp和Adam则不一样,二阶动量是固定时间窗口内的积累,随着时间窗口的变化,遇到的数据可能发生巨变,使得VtVtV_t可能会时大时小,不是单调变化。这就可能导致在训练后期引起学习率的震荡,导致模型无法收敛。
2. 可能错过全局最优解
  深度神经网络往往包含大量的参数,在这样一个维度极高的空间内,非凸的目标函数往往起起伏伏,拥有无数个高地和洼地。高峰通过引入动量可能很容易越过,但是对于高原地区,可能探索很多次都出不来,于是停止了训练。
  有一篇文章《The Marginal Value of Adaptive Gradient Methods in Machine Learning》提到,同一个优化问题,不同优化算法可能会找到不同的答案,但是自适应学习率算法的结果往往比较差,因为自适应学习率算法可能会对前期出现的特征过拟合,后期才出现的特征很难纠正前期的拟合效果。另一篇文章《Improving Generalization Performance by Switching from Adam to SGD》提到,Adam收敛速度比SGD快很多,但是最终收敛的结果不如SGD好,主要是因为后期Adam学习率太低,影响了有效的收敛,如果对Adam的学习率下界进行控制,效果会好很多。
  基于这两点,出现了一种方法——先用Adam快速下降,然后在用SGD调优。问题就在于什么时候切换优化算法(切换得太晚的话Adam已经掉到沟里去了)和切换算法后使用什么样的学习率。有兴趣的朋友可以去读上面第二篇论文,这里就不展开了。


二阶优化方法

  本篇博客的第三部分,来在简单介绍一下二阶优化方法(我自己弄懂后再补一篇博客),前面提到的都是只是用了梯度这个一阶信息,属于一阶优化方法。

牛顿法

  最广泛使用的二阶方法是牛顿法。牛顿法就是每次用H−1H−1H^{-1}重新调整梯度,就会直接跳到极小值,对于目标函数是凸的情况,牛顿法会下降的非常快。但是深度学习中目标函数通常都是非凸的,牛顿法往往会被吸引到临界点处,这是有问题的,可以通过正则化Hessian矩阵来避免。不过因为涉及到计算Hessian矩阵,当模型参数非常多的时候,计算量即非常可怕了。

共轭梯度(CG)

  共轭梯度是一种通过迭代下降的共轭方向来避免Hessian矩阵求逆计算的方法。该方法灵感来源于对梯度下降的改善。因为梯度下降每次的下降方向都是和当前等高线切线的垂直方向,是锯齿形的下降过程。这个过程是一个相当低效的来回往复,因为每次下降方向的改变都有可能在某种程度上撤销了之前取得的进展。而共轭方向则不会有这个问题,所以相比梯度下降会快很多,在kkk维空间中,至多经过k" role="presentation" style="position: relative;">kkk次搜索就能达到极小值。

BFGS

  BFGS和共轭梯度很想,只不过是使用了一个更直接的方法近似牛顿更新。牛顿法的主要计算难点在于计算Hessian的逆H−1H−1H^{-1},而拟牛顿法采用的是使用矩阵MtMtM_t迭代地低秩更新精度以更好的近似H−1H−1H^{-1}。和CG不同的是,BFGS花费较少的时间改进每个方向的线搜索。但是BFGS任然需要O(n2)O(n2)O(n^2)de 空间存储Hessian逆矩阵MMM,不适用于百万数量级参数的大型深度学习模型。

L-BFGS

  L-BFGS是轻量级的BFGS方法,通过避免存储完整的Hessian逆近似M" role="presentation" style="position: relative;">MMM,存储代价显著降低。

深度学习中优化算法小结相关推荐

  1. 深度学习的优化算法——梯度下降和随机梯度下降

    深度学习的优化算法--梯度下降和随机梯度下降 优化算法在深度学习中存在的问题 优化在深度学习中有很多挑战,下面描述其中两个,局部最小值和鞍点. 1.局部最小值 深度学习模型的目标函数可能存在若干极点- ...

  2. 深度学习中的算法学习与记忆,利用故事联想帮助大家记忆,每个人都会

    大家好,我是微学AI,大家看过我的文章,想必是对深度学习有了一定的了解了,但是对于初学者来说,深度学习中有很多名词和数学知识.原理还是不太清楚,记忆的不牢固,用起来不熟练,今天就给大家讲一个故事,让大 ...

  3. 浅析深度学习中优化方法

    目前而言,深度学习是机器学习的发展前沿,一般针对大数据量的学习目标.其优化方法来源于基本的机器学习的优化方法,但也有所不同. 下面,小结一下,其基础是随机梯度下降的方法,但是为了学习的自适应性,做了如 ...

  4. 深度学习(五)优化算法--提高神经网络的训练速度和精度

    转自:https://blog.csdn.net/red_stone1/article/details/78348753 上节课我们主要介绍了如何建立一个实用的深度学习神经网络.包括Train/Dev ...

  5. 深度学习常见优化算法,图解AdaGrad、RMSProp,Adam

    1. AdaGrad AdaGrad算法是梯度下降法的改进算法,其优点是可以自适应学习率.该优化算法在较为平缓处学习速率大,有比较高的学习效率,在陡峭处学习率小,在一定程度上可以避免越过极小值点.在S ...

  6. 收藏 | 从SGD到NadaMax,深度学习十种优化算法原理及实现

    点上方蓝字计算机视觉联盟获取更多干货 在右上方 ··· 设为星标 ★,与你不见不散 仅作学术分享,不代表本公众号立场,侵权联系删除 转载于:作者丨永远在你身后@知乎 来源丨https://zhuanl ...

  7. 深度学习经典优化算法-公式汇总

    -----整理自DeepLearning chapter8,主要是方便做算法的对比. 1.基础算法 1.1 随机梯度下降(SGD,Stochastic Gradient Descent) 随机梯度下降 ...

  8. 「深度学习之优化算法」(六)人工蜂群算法

    1. 人工蜂群算法简介 (以下描述,均不是学术用语,仅供大家快乐的阅读) 工蜂群算法(Artificial Bee Colony Algorithm,ABC)是一种模仿蜜蜂采蜜机理而产生的群智能优化算 ...

  9. 动手学深度学习——基础优化算法梯度下降,小批量随机梯度下降

    一.梯度下降算法 挑选一个初始值w0: 重复迭代参数t=1,2,3: 在接下来不断的更新w0,使它接近最优解: 具体来说,法则如下: wt等于wt的上一时刻减去η乘以损失函数关于wt的上一时刻的梯度. ...

  10. 【深度学习】优化算法-Ftrl

    脑图 代码实现 '''DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSEVersion 2, December 2004Copyright (C) 2004 Sam ...

最新文章

  1. 数据通信技术(十一:无中继的DHCP配置(ZTE))
  2. 提升10倍生产力:IDEA远程一键部署SpringBoot到Docker
  3. 奥特linux系统监控,奥特曼知识大挑战答案
  4. 黄金时代:这个地区17所新大学建设,提速!
  5. NetBeans优化技巧 提升启动速度
  6. python 预测算法_通过机器学习的线性回归算法预测股票走势(用Python实现)
  7. C++中检查vector是否包含给定元素的几种方式
  8. 多任务学习漫谈:分主次之序
  9. java中Runnable和Callable的区别
  10. 200多个js技巧代码(五)
  11. java面试题总结(二)----java中级面试题 含答案
  12. selenium遇到的问题记录
  13. 如何打开浏览器的TLS 1.1 TLS 1.2支持
  14. Marxan模型保护区优化与保护空缺甄选技术、InVEST生态系统中的应用
  15. GO 语言的GOROOT 和GOPATH
  16. 键盘代替鼠标工具 Vimac for Mac
  17. Codesys基础应用----ST语言实现经典冒泡排序
  18. HTML5+CSS3基础响应式页面布局
  19. 寓言故事:羊、狼、狮子(转帖,时寒冰博客网友留言)
  20. openwrt屏蔽广告不生效

热门文章

  1. 时差怎么理解_英国与中国的时差为什么隔8小时(英国与中国的时差解读)
  2. 护眼软件Linux,四个 Linux 下的“护眼”软件解析
  3. HTML5小游戏源码收藏
  4. 亲密关系科学(03)夫妻相处的智慧
  5. 什么是结构体【详解】
  6. Android:H5 通过 URL Scheme 拉起app应用
  7. html5中span作用,span标签的作用与用法总结
  8. matlab中ix是什么意思,详解pandas中iloc, loc和ix的区别和联系
  9. jQuery弹窗组件 colorbox
  10. matlab恶狼追兔问题,饿狼追兔问题-数学建模.doc