神经网络中的优化算法(BGD、SGD、MBGD、动量(Momentum)、NAG、Adagrad、AdaDelta、Adam、AMSGrad、牛顿法)、如何选择神经网络的优化算法

版权声明:站在巨人的肩膀上学习。 https://blog.csdn.net/zgcr654321/article/details/83032561

优化算法:

给定一个具有参数θ的目标函数,我们想要找到一个θ使得目标函数取得最大值或最小值。优化算法就是帮助我们找到这个θ的算法。 

反向传播技术:

先在前向传播中计算输入信号的乘积及其对应的权重,然后将激活函数作用于这些乘积的总和。这种将输入信号转换为输出信号的方式,是一种对复杂非线性函数进行建模的重要手段,并引入了非线性激活函数,使得模型能够学习到几乎任意形式的函数映射。然后,在网络的反向传播过程中回传相关误差(即loss函数的值),使用梯度下降更新权重值,通过计算loss函数E相对于权重参数W的梯度,在损失函数梯度的相反方向上更新权重参数。

如:

如上图,权重更新方向与梯度矢量误差的方向相反,其中U形曲线为梯度。

鞍点:

鞍点(saddle point)这个词来自的图形,在x轴方向向上曲,在y轴方向向下曲,像马鞍,鞍点为(0,0)。 

如:

上图是拥有两个以上参数的函数。它的曲面在鞍点好像一个马鞍,在某些方向往上曲,在其他方向往下曲。在一幅等高线图里,一般来说,当两个等高线圈圈相交叉的地点,就是鞍点。 

神经网络优化问题中的鞍点即一个维度向上倾斜且另一维度向下倾斜的点。鞍点和局部极小值相同的是,在该点处的梯度都等于零,不同在于在鞍点附近Hessian矩阵是不定的(行列式小于0),而在局部极值附近的Hessian矩阵是正定的。

检验二元实函数F(x,y)上某一驻点(在该点处函数梯度等于零)是不是鞍点的一个简单的方法:

计算函数在这个点的Hessian矩阵: 如果该矩阵的特征值有正有负,这个矩阵就是不定的,对应的点就是鞍点; 如果矩阵为正定的,这个点就是局部极小值。

在鞍点附近,基于梯度的优化算法会遇到较为严重的问题: 

鞍点处的梯度为零,鞍点通常被相同误差值的平面所包围(这个平面又叫Plateaus,Plateaus是梯度接近于零的平缓区域,会降低神经网络学习速度),在高维的情形,这个鞍点附近的平坦区域范围可能非常大,这使得SGD算法很难脱离区域,即可能会长时间卡在该点附近(因为梯度在所有维度上接近于零)。 在鞍点数目极大的时候,这个问题会变得非常严重。

高维非凸优化问题之所以困难,是因为高维参数空间存在大量的鞍点。

Error来源分析:

Error = bias + variance + noise

bias描述的是训练样本在模型上拟合的好不好: 拟合的好就是low bias,模型就较为复杂,参数较多,容易过拟合,使得测试样本在模型上的预测具有high variance; 拟合的不好就是high bias,模型较为简单,参数较少,容易欠拟合,但是这样的模型由于对数据变化不那么敏感(不管是训练数据还是测试数据),因此在测试样本上的输出具有low variance。 

因此,想让模型的训练误差小(low bias)就要设置更多参数,但容易造成过拟合,在测试样本上出现high variance;想让模型的测试误差小(low variance),则参数要少一点,这样泛化(generalization)能力才强,但容易出现high variance。

一阶优化算法

通过计算目标函数f关于参数θ的梯度(一阶偏导数)来最小化代价函数。常用的SGD、Adam、RMSProp等基于梯度的优化算法都属于一阶优化算法。

批量梯度下降(BGD):

神经网络中最常用的梯度下降方法。批量梯度下降(Batch gradient descent,BGD)计算整个数据集梯度,但只会进行一次更新,在样本量较大时容易一下子占满内存,而且不支持online update。权重更新的快慢是由学习率η决定的,并且可以在凸面误差曲面中收敛到全局最优值,在非凸曲面中可能趋于局部最优值。使用批量梯度下降还有一个问题,就是在训练大型数据集时存在冗余的权重更新。

使用BGD方法更新梯度时,我们总是计算完所有数据中的误差梯度后,累加再除以梯度的个数得到一个平均的梯度值,再用这个平均的梯度值来更新参数。

参数更新形式如下:

θ=θ−η⋅∇J(θ) 

其中η 为 learning rate ,∇J(θ) 为 代价函数J(θ)对参数θ的梯度 。

注意,有些资料中是加梯度,这是因为在梯度中隐藏着负号,我们可以理解为参数的更新方向是负梯度方向。

学习率η:

学习率的选择时一个有技巧性的活。如果学习率选的太大,那么loss函数就会很快达到最低值附近并产生较大的震荡;如果学习率太小,那么最低值附近的震荡范围也会较小,但是达到最低值附近的时间也变长了。

随机梯度下降(SGD):

随机梯度下降(Stochastic gradient descent,SGD)对每个训练样本进行参数更新,计算量大大减少,支持online update(在线学习)。频繁的更新使得参数间具有高方差,损失函数会以不同的强度波动,这有助于我们发现新的和可能更优的局部最小值,而标准梯度下降将只会收敛到某个局部最优值。因为每学习一条数据就更新一次参数,而数据本身可能是有噪声的,所以随机梯度下降使用的梯度时带有噪声的梯度,下降的方向是曲折的,因此训练出来的模型可能有更强的抗噪声能力。

使用SGD方法更新梯度时,我们总是计算一条输入数据中的误差梯度后,就用这个梯度值来更新参数。

缺点:

是由于频繁的更新和波动,最终将收敛到最小限度,并会因波动频繁存在超调量。当缓慢降低学习率η时,标准梯度下降的收敛模式与SGD的模式相同。另外,每个训练样本中高方差的参数更新会导致损失函数大幅波动,因此我们可能无法获得给出损失函数的最小值。

参数更新形式如下:

θ=θ−η⋅∇(θ) × J(θ;x(i);y(i))

其中x(i)和y(i)为训练样本。

小批量梯度下降(MBGD):

为了避免SGD和标准梯度下降中存在的问题,一个折中的改进方法是小批量梯度下降(Mini Batch Gradient Descent),即一次将一个mini batch(通常为50~256个样本)作为输入来执行一次参数更新。这种方法可以减少参数更新的波动,最终得到效果更好和更稳定的收敛。可以使用最新的深层学习库中通用的矩阵优化方法,使计算小批量数据的梯度更加高效。这是目前神经网络中最为常用的优化方法。

使用MBGD方法更新梯度时,我们总是计算一个小批量的数据的平均误差梯度后,用这个梯度值来更新参数。

上面三种方法的共同缺点:

对learning rate的设置较为敏感,太小则训练的太慢,太大则容易使目标函数发散掉;

针对不同的参数,learning rate都是一样的。这对于稀疏数据来说尤为不方便,因为我们更想对那些经常出现的数据采用较小的step size,而对于叫较为罕见的数据采用更大的step size;

梯度下降法的本质是寻找不动点(目标函数对参数的导数为0的点),而这种不动点通常包括三类:极大值、极小值、鞍点。高维非凸函数空间中存在大量的鞍点,使得梯度下降法极易陷入鞍点(saddle points)且长时间都出不来。

动量(Momentum):

SGD方法中的高方差振荡使得网络很难稳定收敛,所以有研究者提出了一种称为动量(Momentum)的技术,通过优化相关方向的训练和弱化无关方向的振荡,来加速SGD训练。换句话说,这种新方法将上个步骤中更新向量的分量’γ’添加到当前更新向量。

当其梯度指向实际移动方向时,动量项γ增大;当梯度与实际移动方向相反时,γ减小。这种方式意味着动量项只对相关样本进行参数更新,减少了不必要的参数更新,从而得到更快且稳定的收敛,也减少了振荡过程。

momentum相当于给参数更新加了惯性,更新的方向与距离是通过当前的梯度与上一次更新的方向距离联合得到的。

参数更新形式如下:

动量项γ通常设定为0.9,或相近的某个值。

这里的动量与经典物理学中的动量是一致的,就像从山上投出一个球,在下落过程中收集动量,小球的速度不断增加。

motentum方法的优点在于可以使网络能更优和更稳定的收敛,并减少振荡过程。缺点是下坡的过程中动量越来越大,在最低点的速度太大了,可能又冲上坡导致错过极小点。

Nesterov accelerated gradient(NAG):

Nesterov accelerated gradient(NAG)是对motentum算法进行的改进。上面说了动量(Momentum)方法存在一个缺点,即下坡的过程中动量越来越大,在最低点的速度太大了,可能又冲上坡导致错过极小点。

NAG给算法增加了预见能力,先根据之前的动量进行大步跳跃,然后计算梯度进行校正,从而实现参数更新。这种预更新方法能防止大幅振荡,不会错过最小值,并对参数更新更加敏感。

通俗的说法:按照原来的移动先移动了一下,并且计算移动后位置的梯度,相当于对周围的状况有了更多的了解,因此能够更准确的确定新的更新方向。

参数更新形式如下:

在上式中,更新参数θ的时候会用到动量项γV(t−1)。计算θ−γV(t−1)能提供参数下一位置的近似值。这样我们就可以通过计算参数未来位置的近似值上的梯度“预见未来”。

下面是一个示意图。首先沿上一次方向(γvt−1)跨出一大步(brown vector),然后站在那儿计算一下梯度(∇θJ(θ−γvt−1))(red vector),于是,修正过的梯度方向就是γvt−1+η∇θJ(θ−γvt−1)(green vector) 。

Adagrad:

Adagrad方法是通过参数来调整合适的学习率η,对稀疏参数进行大幅更新和对频繁参数进行小幅更新。因此,Adagrad方法非常适合处理稀疏数据。Adagrad方法基于每个参数计算的过往梯度,为不同参数θ设置不同的学习率。在每个时间步t中,Adagrad方法为每个参数θ选取不同的学习率,更新对应参数,然后进行向量化。

为了简单起见,我们把在t时刻参数θ(i)的损失函数梯度设为g(t,i)。

参数更新形式如下: 

上式中,ϵ为平滑因子,避免除数为零。

从上式中,我们可以看到:

某方向上的Gi,t较小,则相应的学习率较大,也就是说,为不频繁出现的参数做较大的更新。随着时间的推移,Gi,t越来越大,从而使学习率越来越小。因此,我们无需手动调整学习率。大多数Adagrad的实现中,η均使用默认值0.01。

由于Gi,t为平方和,每一项都是正值。因此,随着训练过程的进行,Gi,t会持续不断地增长。这意味着,学习率会持续不断地下降,模型收敛越来越慢,训练需要漫长的时间,甚至最终学习率小到模型完全停止学习。

AdaDelta:

Adagrad方法的改进,解决Adagrad方法学习率衰减的问题。Adadelta对累加的范围作了限制,只累计固定大小w的窗口内的过往梯度。为了提升效率,Adadelta也没有存储w个平方梯度,而是过往平方梯度的均值。这样,时步t的动态均值就只取决于先前的均值和当前梯度。

参数更新形式如下:

γ的取值和动量方法类似,在0.9左右。

由于分母是梯度平方和的均值的平方根(root mean squared——RMS),因此还可以写成:

RMSProp:

RMSProp是由Hinton发明的,跟AdaDelta基本一样。 

参数更新形式如下:

η通常设为0.001。

Adam:

Adam算法即自适应时刻估计方法(Adaptive Moment Estimation),能计算每个参数的自适应学习率。这个方法不仅存储了AdaDelta先前平方梯度的指数衰减平均值,而且保持了先前梯度M(t)的指数衰减平均值,这一点与动量类似。

第一个公式通过衰减系数β1计算了梯度的平均值;第二个公式利用衰减系数β2 计算梯度平方的均值。 

通常将mt和vt都初始化为零向量。由于β1和β2都是接近于1的衰减系数,mt和vt刚开始总是会接近于0。为了解决这个问题,利用下面的方式对mt和vt进行改进: 

其中,β1设为0.9,β2设为0.9999,ϵ设为10-8。

由于衰减系数接近1,分母1−βt1是一个接近0的小数,新的m^t就会在mt的基础上放大好多倍,也就不再容易趋于0了。 

AMSGrad:

在ICLR 2018上,Google的Reddi等提交了一篇关于Adam收敛性的论文,指出了Adam算法收敛性证明中的一个错误。并构造了一个简单的凸优化问题作为反例,证明Adam在其上无法收敛。Reddi等提出了Adam算法的一个变体,AMSGRad,其主要改动为:

基于算法的简单性考量,去除了Adam的偏置纠正步骤。

仅当当前vt大于vt-1时,才应用vt。这有助于避免收敛至次优解时,某些提供较大、有用梯度的罕见mini-batch的作用可能被过往平方梯度均值大为削弱,导致难以收敛的问题。

Reddi等在小型网络(MNIST上的单层MLP、CIFAR-10上的小型卷积网络)上展示了AMSGrad在训练损失和测试损失方面相对Adam的优势。然而,有人在较大模型上进行了试验,发现两者并无显著差异(顺便,Adam和AMSGrad的偏置纠正是否开启,影响也不大)。

各种算法的收敛过程动图:

从上图中可以看出,SGD、Momentum、NAG容易陷入鞍点,RMSprop, Adadelta, and Adam不容易陷入鞍点。

二阶优化算法

通过计算目标函数f对参数θ的二阶偏导数来最小化代价函数。二阶偏导数可以用Hessian矩阵表示,每个元素都代表函数对每个参数的二阶偏导数。二阶导数的计算成本很高,但是不容易陷入鞍点。

牛顿法:

牛顿法可以用来求f(x)的零点。

如果要求f(x)的极值,那么就是求f′(x)的零点,求解方法是:

当x的维度变高后,引入海森矩阵H,有:

拟牛顿法:

牛顿法有个缺点,海森矩阵是非稀疏矩阵,参数太多,其计算量太大。因此拟牛顿法采用一些优化方法去近似计算海森矩阵的逆,大大减少了计算量。

常用的拟牛顿法有:

BFGS;

L-BFGS(使用随着时间的梯度信息去近似海森矩阵的逆);

拟牛顿法在神经网络的训练中用的较少,原因主要是拟牛顿法的训练需要使用全部的数据集。batch的拟牛顿法目前还不成熟。

如何选择神经网络的优化算法:

如果你的数据输入量很小,那就选一种自适应学习速率的方法(如Adam)。这样你就不用对学习速率进行调优,因为你的数据本来就小,NN学习耗时也小。这种情况你更应该关心网络分类的准确率;

对于稀疏数据集,应该使用某种自适应学习率的方法(如Adam),且另一好处为不需要人为调整学习率,使用默认参数就可能获得最优值;

如果想使训练深层网络模型快速收敛或所构建的神经网络较为复杂,则应该使用自适应学习速率的方法(如Adam),通常它们收敛起来比较快,实际效果更优;

Adam在不同超参数下的鲁棒性较好,不过有时你可能需要调整下η值。Adam算法中的超参数β1和β2以及learning-rate也会显著影响模型,有时需要调试;

RMSprop, Adadelta, 和 Adam 非常相似,在相同的情况下表现都很好,但偏置校验让Adam的效果稍微比RMSprop好一点;

如果你不知道为你的神经网络选择哪种优化算法,就直接选Adam吧!

另一篇专门讨论自适应优化算法AdaGrad, RMSProp, and Adam和SGD性能之间的比较和选择的文章:

The Marginal Value of Adaptive Gradient Methods in Machine Learning,链接:https://arxiv.org/pdf/1705.08292.pdf

自适应优化算法通常都会得到比SGD算法性能更差(经常是差很多)的结果,尽管自适应优化算法在训练时会表现的比较好,因此使用者在使用自适应优化算法时需要慎重考虑;

用相同数量的超参数来调参,SGD和SGD +momentum 方法性能在测试集上的额误差好于所有的自适应优化算法,尽管有时自适应优化算法在训练集上的loss更小,但是他们在测试集上的loss却依然比SGD方法高;

自适应优化算法在训练前期阶段在训练集上收敛的更快,但是在测试集上这种有点遇到了瓶颈;

所有方法需要的迭代次数相同,这就和约定俗成的默认自适应优化算法需要更少的迭代次数的结论相悖。

总之,上面的结论都未必正确,需要自己去实践。

猜你喜欢

转载自blog.csdn.net/zgcr654321/article/details/83032561
今日推荐