找回密码
 立即注册
查看: 278|回复: 0

优化算法到底如何工作?深度学习中的几个经典优化算法的道理解析

[复制链接]
发表于 2023-9-7 09:17 | 显示全部楼层 |阅读模式
神经网络学习的目的就是找到使损掉函数的值尽可能小的参数。这是寻找最优参数的问题,而优化算法就是为了解决这个问题而发生的。由此可见,优化算法是神经网络的核心。
<hr/>一、SGD

1. 何为SGD

SGD即为随机梯度下降算法。是深度学习优化算法的基石一般的存在,后续的优化算法可以说都是基于SGD进行的改良。
如何理解SGD呢?《深度学习入门-基于Python的理论与实现》一书中给了一个经典的例子。
有一个性情古怪的探险家。他在广袤的干旱地带旅行,对峙寻找幽深的山谷,他的方针是要达到最深的谷底。
他给本身制定了两个规定:一是不许看地图;二是把眼睛蒙上。
因此,他并不知道最深的谷底在这个广袤的大地的何处。在如此严苛的条件下,冒险家如何才能找到“至深之地”呢?
寻找最优参数的过程,与这位探险家寻找至深之地的过程十分类似。若是盲目的摸索,无异于大海捞针。
在如此困难的情况下,感知地面的坡度对于探险家来说就尤为重要。探险家虽然无法通过眼睛不雅察看,但是可以感知地面坡度,他只需要朝着当前地址位置的坡度最大的标的目的前进,对比于盲目摸索,更加容易达到至深之地。这就是随机梯度下降算法SGD。
SGD的数学公式暗示为: W\leftarrow W - \eta (\partial L/\partial W) 。为了便利阅读,后续将 (\partial L/\partial W) 改写为 g_{t} 。即SGD的数学暗示也可以写为: W\leftarrow W - \eta \cdot g_{t} 。我们可以使用Python很容易的实现SGD:
class SGD:
    def __init__(self, lr=0.01):
        self.lr = lr

    def update(self, param, grads):
        for key in params.keys():
            params[key] -= self.lr * grads[key]2. 如何理解这个更新的公式呢?

其一:梯度的负标的目的是函数局部下降最快的标的目的。
假设有损掉函数 f(x) ,向某个标的目的移动t,变为 f(x+t) ,那么什么情况下损掉函数下降最大呢,其实就是求解什么情况下 f(x)-f(x+t) 的值达到最大。由泰勒公式可知 f(x+t)≈f(x)+f(x)^{&#39;}t ,颠末平移可以得到: f(x)-f(x+t)≈-f(x)^{&#39;}t=df(x)t 。
我们要注意的是d f(x)和t均为向量,d f(x)t也就是两个向量进行点积,而向量进行点积的最大值,也就是两者共线的时候,也就是说t的标的目的和d f(x)标的目的不异的时候,点积值最大。而又存在一个负号,故要求df(x)和t是相反的,这样得到的差值才是最大。故梯度的负标的目的是局部下降最快的标的目的。
其二:
假设有 f(x_{1}, x_{2}, x_{3})=w_{1}x_{1}+w_{2}x_{2}+w_{3}x_{3} ,则 f 关于 x 的梯度,即标的目的导数为: (\partial f/\partial x_{1},\partial f/\partial x_{2},\partial f/\partial x_{3}) 。每一个偏导数暗示当其对应的x发生变化时,函数f的值会有多大的变化。
而在一个有着形状为2×3的权重W的神经网络,用L暗示损掉函数,则损掉函数L关于权重W的梯度可以暗示为:



图1

此中每一个偏导数都暗示当该偏导数对应位置的权重发生变化时,损掉函数L会发生多大的变化。所以我们按照 W=W-\eta \cdot (\partial L/\partial W) 来不竭更新权重,使得损掉函数值越来越小。
3. SGD存在的问题

但是通过对SGD的使用,人们很快发现了SGD的一个错误谬误:在某些情况下收敛非常慢。具体是什么情况呢?就是如图2所示的处在一个类似于倾斜向右的山谷的形状的情况。我们已知最深处在山谷的右侧。



图2

图2(左)为山谷,图2(右)为山谷的俯视图。假设当前从(-5, 8)处开始进行搜索(即处在靠左的某一面山坡上),那么此时有一个向山谷的速度以及一个向右(因为山谷是略向右倾斜的)的速度。而由于朝向山谷的速度非常大,故向右的速度可以忽略不计,则寻找至深之处的路线就会变成如图3所示:



图3

需要颠末反反复复的上上下下才可以最终找到谷底。在上述的情况下,SGD的性能非常差,这就导致了模型的训练非常慢,以至于看起来已经收敛。为了解决这个问题,研究人员提出了动量的概念。
二、Momentum

动量的呈现就是为了解决或者说减缓上述SGD的错误谬误的。
动量算法的感化是在参数更新时增加了一个动量向量的累积项,它能够保持之前的更新标的目的,并按照历史梯度的大小来调整更新的步长。这样做的好处是使得参数在梯度标的目的上获得持续的加速,减少了震荡现象。此外,动量算法还可以辅佐模型跳出局部最小值,并更快地收敛到全局最优解。使其搜索路线可以达到如下图所示的效果:



图4

那么这个效果是如何实现的呢?我们先来看动量的数学表达式: W \leftarrow W - \eta \cdot g_{t} + \alpha \cdot v 。W \leftarrow W - \eta \cdot g_{t} 是SGD的部门,尔后面多了一个  \alpha \cdot v ,暗示前面累积的速度。具体表达的是什么思想呢?如下图所示:



图5

如图5所示,添加动量这个因素相当于给参数优化添加了一点物理的味道。
本来的SGD是不管下一次权重更新之后梯度是如何变化的,只是纯挚的按照学习率对权重参数进行更新。
但是添加了动量之后,就会考虑到“力”的因素,如上图,当小球向上走时,就会有一个重力作为阻力,当小球向下走时,重力又作为推力。即在参数更新的过程中,如果更新前的速度与梯度标的目的一致,则更新的数值更大,如果纷歧致,则更新的数值会比SGD时更小。
总之一句话:动量的感化就是加速收敛,减少震荡。动量通过考虑过去梯度的平均值来调整参数的更新步长和标的目的。
三、AdaGrad

1. 道理

学习率是个很重要的东西,决定了一次更新的步长。
而学习率衰减是一个优化技巧,使模型一开始多学,慢慢的少学,可以有效避免模型在学到最优值附件反复横跳。而这个学习率衰减的方式是使全体参数的学习率值一起降低,并不是很人性化。
AdaGrad进一步成长了这个思想,针对一个一个的参数进行学习率更新。



图6

这里呈现了一个新的变量h,如上图所示,h累积了以前所有梯度值的平方和。这个h是个什么概念呢,我们知道,梯度代表了损掉函数下降最快的标的目的和大小,即梯度值越大,那么权重参数更新的幅度也就越大,而累积了前面所有的梯度平方和,说明模型的参数在前面更新的越快,则梯度越大,从而h的值也越大。而在第二个公式中,使用学习率除以这个h。说明更新的越快的参数,其学习率就减小的越快。



图7

如上图所示,由于y轴的梯度较大,因此一开始的变换斗劲大,但是后面会按照这个较大的变换进行调整,减小在y轴上更新的法式,因此y轴上的更新程度布景减弱,更新曲线趋于平缓。
2 . RMSProp

但是这样会呈现一个问题,随着学习的深入,h的值会越来越大,直至使得学习率的值趋于0。这必定不是我们想要的成果。针对这个问题,可以使用RMSProp方式。
RMSProp方式并不会将前面所有的梯度都一视同仁的相加起来,而是使用逐渐遗忘过去的操作,将做加法时将新的梯度信息看的更重要。这种操作叫做“指数移动平均”。
四、Adam

首先给结论: Adam ≈ Momentum + AdaGrad
Adam结合了两种方式的长处。设置了三个超参数:学习率 \alpha ,一次动量 \beta_{1} ,二次动量 \beta_{2} ,一般情况下 \beta_{1}=0.9 , \beta_{2}=0.999 。这个是论文作者本身炼出来的,可以使用于大部门情况。可以达到如下效果:



图8

具体理论还在学习中,未完待续。。。。。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-5-2 22:30 , Processed in 0.250232 second(s), 27 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表