小编邀请您,先思考:
1 随机梯度下降算法怎么理解?
2 随机梯度下降算法有哪些变体?
随机梯度下降算法是深度学习中最常用的算法。算法就是不停地寻找某个节点中下降幅度最大的那个趋势进行迭代计算,直到将数据收缩到符合要求的范围之内。其实也很好理解,以简单的二元函数为例,如果我们想找到二元函数的极值,一般第一步我们是对该二元函数求导,然后令其为0,找出此时自变量的值,将该自变量代入函数式,即可求出该函数的极值。
那么在深度学习中,针对实际问题,我们首先需要建立一个模型,然后确定一个目标函数。目标函数通常是网络输出值和目标之间的误差,误差的形式有很多种,例如常见的有平方差、交叉熵等等。
训练模型的目的是使得目标函数达到极小值。对于一个深度神经网络,它的参数数目比较庞大,因此目标函数通常是一个包含很多参量的非线性函数。对于这个非线性函数,我们采用的是随机梯度下降算法来对参数进行更新。具体步骤如下:
(1)对网络参数进行初始化,一般情况下,权重初始化为均值是0,方差为0.01的高斯分布随机值,而偏置统一初始化为0;
(2)将参数代入网络计算前馈输出值,从而可以根据已有的目标标签得出目标函数值;
(3)根据目标函数值以及各参数与目标函数所构成的树结构,运用后向传播算法计算出每个参数的梯度;
(4)设置学习率大小(随着迭代的步骤增多,学习率通常要逐渐减小,这样可以有效避免训练中出现误差震荡情况),进行参数更新,最一般的更新方式是 新参数=旧参数-学习率×梯度;
(5)重复进行第2~4步,直到网络收敛为止。
那么为什么叫随机梯度下降算法呢?这里的随机是指每次迭代过程中,样本都要被随机打乱,这个也很容易理解,打乱是有效减小样本之间造成的参数更新抵消问题。
随机梯度下降算法通常还有三种不同的应用方式,它们分别是SGD、Batch-SGD、Mini-Batch SGD,下面分别解释一下这三种方式的不同。
SGD是最基本的随机梯度下降,它是指每次参数更新只使用一个样本,这样可能导致更新较慢;
Batch-SGD是批随机梯度下降,它是指每次参数更新使用所有样本,即把所有样本都代入计算一遍,然后取它们的参数更新均值,来对参数进行一次性更新,这种更新方式较为粗糙;
Mini-Batch-SGD是小批量随机梯度下降,它是指每次参数更新使用一小批样本,这批样本的数量通常可以采取trial-and-error的方法来确定,这种方法被证明可以有效加快训练速度。
下面我来介绍七种常见的随机梯度下降算法。
算法一:最基本的随机梯度下降算法
在最基本的随机梯度下降算法中,参数每一步通过减去它的梯度来更新的,通常需要首先打乱训练样本,然后将它们划分为一定数量的mini-batch,如果mini-batch的数量为1,那么更新方程一般为:
param = param-lr*g(param)
对于该算法,需要注意的是我们必须小心调节学习率。因为如果学习率设置太大的话,算法会导致目标函数发散;反之如果学习率设置太小的话,算法会导致目标函数收敛过慢。将训练样本随机打乱会避免参数更新的抵消,对于大规模的机器学习任务,随机梯度下降算法表现的性能可观。
算法二:动量法
如果参数的初始值和学习率没有设置恰当,算法一在实践中不能表现出较好的性能。引入动量的算法可以帮助网络跳出局部最优的限制。动量法已经被证明其在训练深度神经网络中的性能可以媲美之前的Hessian优化算法。并且,动量法通过在多次迭代中,在目标值持续递减的方向上累积一个速度矢量来加速梯度下降。其更新公式为:
v=mu*v-lr*g(param)
param=param+v
其中mu是动量系数,其最优值在实践中可以通过trial-and-error的方法来确定。通过与算法一比较可见,动量法仅仅是在权重更新上加了一部分之前的权重更新。当梯度下降保持原来的方向时,这就会增加下降的布幅,从而使得更快地达到最优值;当梯度下降改变方向时,动量法就会使得改变量平滑一点,这个对于网络的初始值设置地不好具有重要的弥补作用。动量法可以使得网络较快地达到最优值而没有太多震荡。
算法三:Nesterov Accelerated Gradient
NAG算法是基于算法二的一个变种,既然我们已经有了基于之前的更新mu*v,我们现在不计算在param处的梯度,取而代之的是计算在param+mu*v处的梯度,于是NAG算法的更新公式为:
v=mu*v-lr*g(param+mu*v)
param=param+v
由于NAG算法在计算梯度时做了小小的改变,在实践中,这使得NAG在很多情况下表现地要比算法二更加稳定。
现在既然已经有了根据目标函数的陡峭程度来更新参数,除此之外,我们还希望可以根据每个参数的特点来制定或大或小的更新步幅,换句话说,更新算法需要更精准。
算法四:AdaGrad
如果我们希望根据每个参数去调节学习率,那么AdaGrad恰好解决了这个问题。AdaGrad算法根据每个参数过去的更新历史来决定现在的更新学习率。AdaGrad会记录之前每一步更新值的平方,通过将这些累加起来来调节每一步学习率的大小。这样一来,对于那些频繁更新的参数,学习率会比较小;而对于那些不频繁更新的参数,学习率会比较大。从这个角度看,AdaGrad很适合比较稀疏的数据。更新公式如下:
G=G+[g(param)]^2
param=param-lr*g(param)/sqrt(G+epsilon)
其中epsilon是一个极小值,为了数值稳定。AdaGrad的一个优点是它可以避免手动去调节学习率,并且在很多时候,只要初始化学习率为0.01即可,然后可以放任不管。但是,一个明显的缺点是随着更新步骤的增多,学习率将会一直减小直至接近于0,这样就会导致网络更新停滞。
算法五:RMSProp
RMSProp是为了解决算法四的学习率消失问题,通过在历史更新与梯度平方之间设置一定的比例。其更新公式如下:
G=0.9*G+0.1*[g(param)]^2
param=param-lr*g(param)/sqrt(G+epsilon)
RMSProp与接下来要讨论的算法六几乎是同时提出的。
算法六:AdaDelta
AdaDelta也是为了解决AdaGrad的学习率消失问题,与AdaGrad累积历史更新所不同的是,AdaDelta将过去的更新限制在固定的长度w里面。并且,由于存储过去w个更新在计算上效率很低,取而代之的是通过采取指数衰减的形式来保留最近的更新项(平方梯度)。
这里需要定义一个叫做均方根的概念,均方根的公式如下:
RMS[g]=sqrt(E(g^2)+epsilon)
简而言之,均方根就是平方均值的平方根。
AdaDelta的更新公式如下:
首先初始化两个均值,E[g^2]=0,E[d_param^2]=0
E[g^2]=rou*E[g^2]+(1-rou)*g^2
d_param=RMS[d_param]/RMS[g]*g
E[d_param^2]=rou*E[d_param^2]+(1-rou)*d_param^2
param=param-lr*d_param
其中rou为衰减率。
算法七:Adam
最近,Adam算法被提出来,该算法非常有效,并且只需要一阶梯度,而且对内存要求也很低。Adam同时考虑了梯度以及梯度的平方,因此,Adam同时具有AdaGrad和AdaDelta的优点,能够很好地适应于稀疏数据或不当的初始化网络。
Adam算法的更新公式如下:
初始化一阶向量m和二阶向量v为0;
设置最优的beta1、beta2的值(论文中有介绍实践最优默认值);
m=beta1*m+(1-beta1)*g
v=beta2*v+(1-beta2)*g^2
m=m/(1-beta1)
v=v/(1-beta2)
param=param-lr*m/(sqrt(v)+epsilon)
总结
根据我之前所使用的情况来看,Adam算法是最快的也是最稳定的。不过,我想具体问题应该有所不同吧,最常用的是算法二、算法四、算法七了。