找回密码
 立即注册
查看: 604|回复: 1

优化方法

[复制链接]
发表于 2021-11-25 16:02 | 显示全部楼层 |阅读模式
以下内容来自CS231n笔记:有关优化方法的一节和自己的一些补充
引言

考虑以下问题,找出一条直线,如途中黄线所示,将两类正反例分开



每个点都可以用一对坐标和一个标签表示

每个点可用   ,则这条直线可以表示为 ,记 ,这条直线则可记为
,则将任意的点的一对坐标代入, 可以衡量该点到直线的距离, 可以表示该点在直线的哪一边。如果 越大,那么我们就越可以确信这一点分类是正确的(因为它远离了边界,就不太可能分类出错)。以此我们将 外套上一层 ,就能衡量该点属于某一类的概率。对于某个点  , , 为损失函数,衡量了这一条直线,在将这一点进行分类的时候的误差是多少。对于给定的数据集,这条直线在这一数据集上的损失为 ,则现在寻找到这条直线的任务就变为 。在给定数据集的情况下,由以上可知,损失 是直线的三个参数的函数,最小化损失的过程,就是优化过程,对于以上损失函数可操作的机器学习算法,优化的过程就是训练的过程。

基于梯度的优化方法

1.梯度下降法(Vanilla gradient descent)
延续之前的问题,由梯度的定义我们可以知道,梯度对应的方向是多元函数增长最快的方向,取负之后,梯度方向就是函数下降最快的方向。我们可以利用这一特点,通过多次迭代,找到最小的参数值。如下:


其中 为学习率,是特别重要的一个超参数(需要我们自己手动调节,无法通过学习得到)。  过大,就会导致在迭代到极小值附近,会发生抖动,导致模型无法收敛。  过小就会导致模型收敛过慢。
其代码实现如下:
while True:
        grad = evaluate_gradient(loss_function, data)
        weight -= learning_rate*grad梯度下降的缺点:
1.每一次训练都需要使用全部的数据集,对于深度学习这样,比如ImageNet这样1T的图片集,每一轮迭代的代价太大,不可承受
2.如果当训练到鞍点,极小值,或者各个坐标轴的梯度都极小的时候,此时会出现梯度消失的现象,训练无法进行。在深度学习这种维数相当爆炸的数据集上,可以发现大部分数据点都处于鞍点之上。训练无法继续进行。
3.由于学习率恒定,在训练到不同阶段,恒定的学习率不一定适合。

针对以上缺点,前人提出了许多改进的算法。

2.随机梯度下降(Stochastic Gradient Descent)

针对梯度下降法的第一点,我们提出了随机梯度下降。因为损失函数的梯度是损失函数对各个参数值偏导的累加。在实际的优化中,我们并不在一次迭代中计算所有维度的梯度,而是随机取几个维度计算梯度后迭代。同时,在实际中,在一次迭代中我们也不使用全部的数据集,而是使用一个小的子集来训练,这样就能加速单轮迭代的计算速度。SGD和GD还有一个缺点,就是梯度方向和最小值不一定在一条直线上。如果只是沿着梯度方向前进时。对于不需要走很大步,就能走到合适位置的维度,由于学习率在这一维度上过大,就有可能导致ZigZag现象,使得收敛过程变慢。如下图:



ZagZig

3.带动量的随机梯度下降(SGD with Momentum)

针对SGD和GD都存在的鞍点问题和ZigZag问题,我们可以引入动量加以解决。引用动量之后,就不是直接用梯度对权值进行直接的更新,而是速度,更新的公式如下:




从更新的角度看,每次的更新是由上一次更新和当前的梯度共同决定的。当损失函数位于鞍点时,不会因为梯度消失,而停止学习。当位于极小值点的时候,也有一定的可能越过极值点,但是仍存在被极值点限制住的可能。当下降到最小值时,会出现来回的抖动,类似于球滚到谷底后,来回滚动一样。   



更新方向和梯度以及速度的关系

vx = 0
while True:
        grad = evaluate_gradient_random(loss_function, data)
        vx = rho * vx + grad
        weight -= learning_rate*vx4.牛顿动量(Nesterov Momentum)

牛顿动量法和刚才讲的动量有着略微的不同,其不同之处在于所计算的梯度不是当前所在位置的梯度,而是当前节点加上当前速度后的梯度。因为牛顿动量额外利用了另一个节点的信息,在单纯的凸优化问题上的表现时是优于一般动量的。但是在深度学习的非凸优化中,其表现和一般动量差不多。



牛顿动量更新方向和梯度以及速度的关系,可以结合上图对比

其更新的规则如下:





实际上计算这样的梯度是比较不直观的,我们通常用换元法换元后进行计算。如下:
,则
while True:
        grad = evaluate_gradient_random(loss_function, data)
        old_v = v
        v = rho * v - leaning_rate*dx
        x +=  v + rho * (v - old)_v
下图比较了SGD, SGD with Momentum, Nesterov Momentum三种方法:


可以看得出来带了动量的优化的轨迹都试图绕开局部最小值,并且动量方法收敛更快,这方面的行为两个算法都表现得差不多。但是一般动量和牛顿动量的方向更新各有差别,因此具体的轨迹也有所差别。
下图则表现了,动量方法如何消除ZigZag现象,当在某一维度上,当前的坐标距离最小值的坐标很接近了,在这一维度上就会发生来回的滚动,在来回的滚动过程中,ZigZag现象就会被抵消,收敛速度也会变快,从上图我们也可以看出。


以上的方法都是在没有修改学习率的情况下,对GD算法提出的优化,下面介绍通过修改学习率对GD算法的优化。

5.AdaGrad

AdaGrad和GD算法的差别在于,每一次迭代的实际学习率是人为设定的学习率除以累计梯度的平方和。最开始的时候,累计梯度的平方和为0,我们的分母将会是一个很小的数,此时的学习率就会很大,随着迭代次数的增加,累计梯度平方和将会越来越大,分母不断增加,导致真实的学习率越来越小。其更新公式如下:




其代码如下:
gradsquare = 0
while True:
        grad = evaluate_gradient_random(loss_function, data)
        gradsquare = grad * grad ##注意这行和下面RMSProp的差别
        weight -= learning_rate * grad /(gradsquare + 1e-8) AdaGrad有一个较为致命的问题就是,学习率始终是在衰减的,就有可能导致在还未达到最小值之前,学习率就以及很低,导致了算法不能收敛。针对这一问题,提出了RMSProp算法

6.RMSProp算法

RMSProp算法和AdaGrad算法的差别并不大,区别在于分母的位置不再是累计梯度平方和,而是累计梯度平方和的指数加权平均。这样,如果梯度长时间处于一个很小的值,分母就会随之变小,就避免了学习率过早变为很小的值导致学习率GG。代码如下:
gradsquare = 0
while True:
        grad = evaluate_gradient_random(loss_function, data)
        gradsquare = decay_rate * gradsquare + (1 - dacay_rate) * grad * grad
        weight -= learning_rate * grad /(gradsquare + 1e-8)下图是动量方法,SGD和RMSProp的差别,可以看到RMSProp的优化只是针对学习率进行了优化,其行为和SGD差不多,但是在训练早期,RMSProp学习率较大,因此收敛速度稍快于SGD。



7.Adam

Adam算法是目前最优秀的深度学习优化算法,它结合了动量方法和RMSProp方法,其收敛行为接近于带动量了RMSprop方法,在实际使用中,这是默认的深度学习训练算法



结合前面的讲解,Adam应该很容易理解了



图片展示了不同算法正常的收敛行为和速度



图片展示了不同算法在鞍点处行为

本帖子中包含更多资源

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

×
发表于 2021-11-25 16:09 | 显示全部楼层
这个图也太漂亮了吧,楼主厉害的
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

GMT+8, 2024-9-23 03:20 , Processed in 0.090820 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

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