一文搞懂深度学习中的梯度下降
本文算是对常用梯度图下降的算法综述,从方向导数开始得到梯度下降的原始算法,接着描述了动量梯度下降算法。 而由于超参数学习率对梯度下降的重要性,所以梯度算法就有多个自适应梯度下降算法。 主要有以下内容:
- 方向导数和梯度下降
- 梯度下降的形式,批量梯度下降,SGD以及mini-batch 梯度下降
- 梯度下降的进化,主要是几种自适应梯度下降算法:AdaGrad,RMSprop,AdaDelta,Adam
方向导数和梯度
方向导数
方向导数指的是函数\(z=f(x,y)\)在某一点\(P\)沿某一方向的变化率,其表示形式为$$\frac{\partial f}{\partial l}$$其中\(l\)表示变换的方向。
设函数\(z=f(x,y)\)在点\(P(x,y)\)的某一邻域\(U(p)\)内有定义。自点\(P\)处引射线\(l\),设射线\(l\)和\(X\)轴正向的夹角为\(\theta\),并且假定射线\(l\)与函数\(z = f(x,y)\)的交点为\(P\'(x+\Delta x,y + \Delta y)\)。则函数在\(P,P\’\)的增量为\(f(x+\Delta x , y + \Delta y) – f(x,y)\),两点之间的距离为\(\rho = \sqrt{(\Delta x)^2 + (\Delta y)^2}\),当\(P\’\)沿着\(l\)趋近于\(P\)时,如果函数增量和两点距离的比值的极限存在,则称这个极限为函数\(f(x,y)\)在点\(P\)沿方向\(l\)的方向导数,记为\(\frac{\partial f}{\partial l}\),即
\]
假设,函数\(z=f(x,y)\)在点\(P(x,y)\)可微,则有:
\]
将上式的左右两边同时除以\(\rho\)
\]
取极限有
\]
梯度
梯度是和方向导数相关的一个概念。
假设函数\(z=f(x,y)\)在平面区域内\(D\)内具有一阶连续偏导数,则对每一点\((x,y) \in D\),都可得到一个向量,
\]
该向量就称为函数\(z=f(x,y)\)在点\((x,y)\)处的梯度,记为\(grad f(x,y)\),即
\]
那么梯度和方向导数,有什么样的关系呢。
设,向量\(e = \cos \theta i + \sin \theta j\)是与\(l\)同向的单位向量,则有方向导数的计算公式可知,
\]
$\cos <\nabla f,e> $表示梯度 \(\nabla f\) 与 \(e\)的夹角,当方向向量的方向\(l\)的方向与梯度一致时,方向导数\(\frac{\partial f}{\partial l}\)达到最大值,也就是说函数沿着梯度的方向增长最快。
函数在某点的梯度是一个向量,在该点沿着梯度方向的方向导数取得最大值,方向导数的最大值为梯度的模。
\]
梯度的方向由梯度向量相对于\(x\)轴的角度给出,
\]
也就是说,一个函数在某点沿着梯度的方向增长最快,而逆着梯度的方向则减小最快。
梯度下降优化算法
在复杂函数求最小值的优化问题中,通常利用上面描述的梯度的性质,逆着梯度的方向不断下降,来找到函数的极小值。
以进行一个线性回归的批量梯度下降为例,描述下梯度下降方法的过程
\]
其目标函数为:
\]
其中,\(i = 1,2,\cdots,m\)为第\(i\)个样本。这里的目标函数是所有样本误差和的均值。
则使用梯度下降进行优化时,有以下步骤
- 求目标函数的导数
\]
\(i = 1,2,\cdots,m\)为样本数。
- 利用上述样本更新参数
\]
其中,\(\alpha\)是每次下降的步长。
梯度下降中的几个基本概念:
- 假设模型,上面线性回归中使用函数\(h_{\theta}(x^i) = \theta_1 x^i + \theta_0\)作为训练集的拟合函数。在深度学习中,可以将整个神经网络看着一个复杂的非线性函数,作为训练样本的拟合模型。
- 目标函数,也称为损失函数(loss function)。使用该函数的值来评估假设的模型的好坏,目标函数的值越小,假设模型拟合训练数据的程度就越好。使用梯度下降,实际就是求目标函数极小值的过程。上述线性回归中,使用模型预测值和真实数据的差值的平方作为目标函数\(J(\theta_0,\theta_1) = \frac{1}{2m}\sum_{i=1}^m(h_{\theta}(x^i) – y^i)^2\),前面乘以\(\frac{1}{2}\)是为了求梯度方便。
- 步长\(\alpha\),超参数步长值的设定在梯度下降算法中是很重要的。目标函数的梯度只是指明了下降的方向,而步长则是每次迭代下降的距离多少。过小的步长,则会导致训练时间过长,收敛慢;而过大的步长则会导致训练震荡,而且有可能跳过极小值点,导致发散。
梯度下降的形式
梯度下降是机器学习的常用优化方法,根据每次使用的样本的数据可以将梯度下降分为三种形式:批量梯度下降(Batch Gradient Descent),随机梯度下降(Stochastic Gradient Descent)以及小批量梯度下降(Mini-batch Gradient Descent)。
以进行一个线性回归为例:
\]
其目标函数为:
\]
其中,\(i = 1,2,\cdots,m\)为第\(i\)个样本。这里的目标函数是所有样本误差和的均值。
则目标函数与参数\((\theta_0,\theta_1)\)之间关系为
在上图中,使用梯度下降的方法,求得最低位置的\((\theta_0,\theta_1)\)即为所求。
批量梯度下降
批量梯度下降是最原始的形式,它指的是每一次迭代时使用说有样本的数据进行梯度更新.
- 求目标函数的导数
\]
\(i = 1,2,\cdots,m\)为样本数。
- 利用上述样本更新参数
\]
批量梯度下降算法的优缺点都很明显:
- 优点 每次更是时使用了全部的样本数据,能更准确地朝向极值所在的方向。
- 缺点 当样本很多时,每次都是用所有的样本,训练时每轮的计算量会很大。
从迭代次数来说,批量梯度下降迭代次数较少。对于凸误差函数,批量梯度下降法能够保证收敛到全局最小值,对于非凸函数,则收敛到一个局部最小值。
随机梯度下降 SGD
不同于批量梯度下降,随机梯度下降,每次只用要给样本进行梯度更新,这样训练的速度快上不少。
其目标函数为
\]
- 目标函数求导
\]
- 梯度更新
\]
随机梯度下降每次只是用一个样本,其训练速度快。 但是在更新参数的时候,由于每次只有一个样本,并不能代表全部的训练样本,在训练的过程中SGD会一直的波动,这就使得要收敛某个最小值较为困难。不过,已经有证明缓慢减小学习率,SGD与批梯度下降法具有相同的收敛行为,对于非凸优化和凸优化,可以分别收敛到局部最小值和全局最小值。
小批量梯度下降,也称为随机批量梯度下降
在深度学习中,最常用的优化方法就是小批量梯度下降。 小批量下降是对批量梯度下降和随机梯度下降两种方法的中和,每次随机的使用batch_size个样本进行参数更新,也可以称为随机批量梯度下降。(batch_size是一个超参数)。
- 优点 算是对上面两种方法均衡,即有SGD训练快的优点,每次更新参数时使用多个样本,在训练的过程中较为稳定。
- 确定 batch_size是一个超参数,需要手动的指定。过大和过小的batch_size会带来一定的问题。
通常,小批量数据的大小在50到256之间,也可以根据不同的应用有所变化。在一定范围内,一般来说batch_Size越大,其确定的下降方向越准,引起训练震荡越小。但是,batch_size增大到一定程度后,其确定的下降方向并不会改变了,所以,过大的batch_size对训练精度已经帮助不大,只会增加训练的计算量。
梯度下降的难点
梯度下降的难点:
- 学习率的设置
- 极小值点,鞍点
梯度下降优化中的第一个难点就是上面提到的,学习率的设置问题。学习速率过小时收敛速度慢,而过大时导致训练震荡,而且可能会发散。
而非凸误差函数普遍出现在神经网络中,在优化这类函数时,另一个难点是梯度下降的过程中有可能陷入到局部极小值中。也有研究指出这种困难实际上并不是来自局部最小值,而更多的来自鞍点,即那些在一个维度上是递增的,而在另一个维度上是递减的。这些鞍点通常被具有相同误差的点包围,因为在任意维度上的梯度都近似为0,所以SGD很难从这些鞍点中逃开。
鞍点(Saddle point)在微分方程中,沿着某一方向是稳定的,另一条方向是不稳定的奇点,叫做鞍点。对于拥有两个以上变量的曲线,它的曲面在鞍点好像一个马鞍,在某些方向往上曲,在其他方向往下曲。由于鞍点周围的梯度都近似为0,梯度下降如果到达了鞍点就很难逃出来。下图是\(z = x^2 – y^2\)图形,在x轴方向向上曲,在y轴方向向下曲,像马鞍,鞍点为\((0,0)\)
另外,在梯度平坦的维度下降的非常慢,而在梯度较大的维度则有容易发生抖动。
梯度下降的算法的进化
理想的梯度下降算法要满足两点:收敛速度要快;而且能全局收敛。所以就有各种梯度算法的变种。
动量梯度下降
基于动量的梯度下降是根据指数加权平均来的,首先要了解下指数加权平均。
指数加权平均
指数加权平均(exponentially weighted averges),也称为指数加权移动平均,是常用的一种序列数据的处理方法。设在\(t\)时刻数据的观测值是\(\theta_t\),在\(t\)时刻的移动平均值为\(v_t\),则有
\]
其中,\(\beta v_{t-1}\)是上一时刻的移动平均值,也看着一个历史的积累量。通常设\(v_0 = 0\),\(\beta\)是一个参数,其值在\((0,1)\)之间。动平均值实际是按比例合并历史量与当前观测量,将上述递推公司展开
v_0 & = 0\\
v_1 & = \beta v_0 + (1-\beta)\theta_1 \\
v_2 &= \beta v_1 + (1-\beta)\theta_2 = \beta (\beta v_0 + \theta_1) + (1-\beta)\theta_2 \\
\vdots \\
v_t &= \beta v_{t-1} + (1-\beta)\theta_t = \sum_{i=1}^t \beta^{t-i}(1-\beta)\theta_t
\end{align*}
\]
展开后可以发现,在计算某时刻的\(v_t\)时,其各个时刻观测值\(\theta_t\)的权值是呈指数衰减的,离当前时刻\(t\)越近的\(\theta_t\),其权值越大,也就是说距离当前时刻越近的观测值对求得移动平均值的影响越大,这样得到的平均值的会比较平稳。由于权重指数衰减,所以移动平均数只是计算比较相近时刻数据的加权平均数,一般认为这个时刻的范围为\(\frac{1}{1-\beta}\),例如\(\beta=0.9\),可以认为是使用距离当前时刻之前10时刻内的\(\theta_t\)的观测值,再往前由于权重值国小,影响较小。
指数加权平均例子
下面是伦敦一年中每天的温度,使用指数加权平均的方法,来表示其温度的变化趋势
计算其各个时刻的移动品均值,设\(\beta = 0.9\)
v_0 &=0 \\
v_1 &= 0.9v_0 + 0.1\theta_1 \\
v_2 &= 0.9v_1 + 0.1 \theta_2 \\
\vdots \\
v_t & = 0.9 v_{t-1} + 0.1 \theta_t
\end{align*}
\]
将移动平均值即每日温度的指数加权平均值的曲线图
上图的 \(\beta=0.9\),也就是近10天的加权平均值。设\(\beta =0.98\),也就是近50天的加权均值,可以得到如下曲线(绿色)
相比于红色曲线,绿色曲线更为平坦,因为使用50天的温度,所以这个曲线,波动更小,更加平坦,缺点是曲线进一步右移,因为现在平均的温度值更多,要平均更多的值,指数加权平均公式在温度变化时,适应地更缓慢一些,所以会出现一定延迟。而且\(\beta = 0.98\)给历史积累量的权值过多,而给当前量权值仅为0.02过少。
那如果平均过少的天数呢,比如\(\beta = 0.5\)只使用2天内的温度
可以看到黄色曲线波动较大,有可能出现异常值,但是这个曲线能够更快适应温度变化。
参数\(\beta\)的选择较为重要,不能过大或者国小。在本例中,\(\beta = 0.9\)取得的红色曲线,显然更能表示温度变化的趋势。
动量梯度下降
动量梯度下降算法是Boris Polyak在1964年提出的,其基于这样一个物理事实:将一个小球从山顶滚下,其初始速率很慢,但在加速度作用下速率很快增加,并最终由于阻力的存在达到一个稳定速率。
m &\leftarrow \gamma \cdot m+\eta \cdot \nabla J(\theta) \\
\theta &\leftarrow \theta-m
\end{align*}
\]
可以看到,在更新权值时,不仅仅使用当前位置的梯度,还加入了一个累计项:动量,多了也给超参数\(\gamma\)。
动量梯度下降,实际上是引入了指数加权平均,在更新参数时不仅仅的只考虑当前梯度的值,还要考虑前几次梯度的值。
v_t &= \beta v_{t – 1} + (1 – \beta) \nabla J(\theta)_t \\
\theta &= \theta – \alpha v_t
\end{align*}
\]
将学习速率\(\alpha\)整合到第一个式子中,更简洁一些
v_t &= \gamma v_{t – 1} + \eta \nabla J(\theta)_t \\
\theta &= \theta – v_t
\end{align*}
\]
在进行参数更新时,使用当前的\(v_t\)移动平均值来代替当前的梯度,进行参数更新。所谓的动量,也就是近几次的梯度加权移动平均。例如,通常有\(\beta = 0.9\),也就是当前时刻最近的10次梯度做加权平均,然后用次平均值更新参数。
如下图,红点代表最小值的位置
原始的梯度下降算法,会在纵轴上不断的摆动,这种波动就就减慢了梯度下降的速度。理想情况是,在纵轴上希望学习的慢一点,而在横轴上则要学习的快一点,尽快的达到最小值。 要解决这个问题有两种思路:
- 纵轴方向和横轴方向设置不同的学习率,这是自适应学习速率算法的方法。后面会说到,这里先不提。
- 带动量的梯度下降。
如上图,在纵轴方向其每次的梯度摇摆不定,引入动量后,每次使用一段时间的梯度的平均值,这样不同方向的梯度就会相互抵消,从而减缓纵轴方向的波动。而在,横轴方向,由于每次梯度的方向都指向同一个位置,引入动量后,其平均后的均值仍然指向同一个方向,并不会影响其下降的速度。
动量梯度下降,每一次梯度下降都会累积之前的速度的作用,如果这次的梯度方向与之前相同,则会因为之前的速度继续加速;如果这次的方向与之前相反,则会由于之前存在速度的作用不会产生一个急转弯,而是尽量把路线向一条直线拉过去,这样就减缓的波动。
Nesterov Accelerated Gradient,NAG
球从山上滚下的时候,盲目地沿着斜率方向,往往并不能令人满意。我们希望有一个智能的球,这个球能够知道它将要去哪,以至于在重新遇到斜率上升时能够知道减速。
NAG算法是Yurii Nesterov在1983年提出的对冲量梯度下降算法的改进版本,其速度更快。其变化之处在于计算“超前梯度”更新冲量项。
在动量梯度下降中,使用动量项\(\gamma v_{t-1}\)来更新参数\(\theta\),通过计算\(\theta – \gamma v_{t-1}\)能够大体预测更新后参数所在的位置,也就是参数大致将更新为多少。通过计算关于参数未来的近似位置的梯度,而不是关于当前的参数的梯度位置
v_t &= \gamma v_{t -1 } + \eta \nabla J(\theta – \gamma v_{t-1}) \\
\theta &= \theta – v_t
\end{align*}
\]
如下图
动量梯度下降,首先计算当前的梯度项,上图的蓝色小向量;然后加上累积的动量项,得到大蓝色向量,在改方向上前进一步。
NAG则首先在之前累积的动量项(棕色向量)前进一步,计算梯度值,然后做一个修正(绿色的向量)。这个具有预见性的更新防止我们前进得太快,同时增强了算法的响应能力。
直观想象下这个过程,就像骑一辆自行车向下冲。一般的动量下降,就像骑到某一个地方,然后根据当前的坡度,决定往那个方向拐。而NAG则是首先判断下前方的坡度,然后根据前方的坡度决定往那个方向拐。也就是预判下一个位置的坡度,对当前下降的方向进行修正,避免走冤枉路。
AdaGrad
在基本的梯度优化算法中,有个常见问题是,要优化的变量对于目标函数的依赖是不相同的。有些变量,已经优化到极小值附近,但是有些变量仍然离极小值很远,位于梯度较大的地方。这时候如果对所有的变量都使用同一个全局的优学习速率就有可能出现问题,学习率太小,则梯度很大的变量就会收敛的很慢;如果梯度很大,已经优化的差不多的变量可能会不稳定。
针对这个问题,Jhon Duchi提出了AdaGrad(Adaptive Gradient),自适应学习速率。AdaGrad的基本思想是对每个变量使用不同的学习率。在最初,学习速率较大,用于快速下降。随着优化过程的进行,对于已经下降很多的变量,则减小学习率;对于没有怎么下降的变量,则仍保持大的学习率。
AdaGrad对每个变量更新时,利用该变量历史积累的梯度来修正其学习速率。这样,已经下降的很多的变量则会有小的学习率,而下降较少的变量则仍然保持较大的学习率。基于这个更新规则,其针对变量\(\theta_i\)的更新
\]
其中,\(\nabla J(\theta_i)_t\)表示t时刻变量\(\theta_i\)的梯度。\(\sum_{\tau =1}^t \nabla J(\theta_i)_\tau\)就表示变量\(\theta_i\)历史累积的梯度值 ,用来修正学习率。加上很小的值\(\tau\)是为了防止0的出现。
AdaGrad虽然能够动态调整变量的学习率,但是其有两个问题:
- 仍然需要手动的设置一个初始的全局学习率
- 使用变量的历史累积梯度来调整学习率,这就导致其学习率是不断衰减的,训练后期学习速率很小,导致训练过早停止。
后面的几种自适应算法都是对AdaGrad存在的上述问题进行修改.
RMSprop
RMSprop是Hinton在他的课程上讲到的,其算是对Adagrad算法的改进,主要是解决学习速率过快衰减的问题。其思路引入了动量(指数加权移动平均数)的方法,引入了超参数\(\gamma\),在累积梯度的平方项近似衰减:
s_{(t,i)} &= \gamma s_{(t-1,i)} + (1-\gamma) \nabla J(\theta_i)_t \odot \nabla J(\theta_i)_t \\
\theta_{(t,i)} &= \theta_{(t-1,i)} – \frac{\eta}{\sqrt{s_{(t,i)} + \epsilon}} \odot \nabla J(\theta_i)_t
\end{align*}
\]
其中,\(i\)表示第\(i\)个变量,\(t\)表示\(t\)时刻更新,\(\gamma\)是超参数通常取\(\gamma=0.9\)。\(s_{(t,i)}\)表示梯度平方的指数加权移动平均数,用来代替AdaGrad中不断累加的历史梯度,有助于避免学习速率衰减过快的问题。同时Hinton也建议将全局的学习率\(\eta\)设置为0.001。
AdaDelta
AdaDelta对AdaGrad进行两方面的改进:
- 学习率衰减过快
- 全局学习率超参数问题
针对学习率衰减过快的问题,其思路和RMSprop一样,不在累积所有的历史梯度,而是引入指数加权平均数,只计算一定时间段的梯度。
s_{(t,i)} &= \gamma s_{(t-1,i)} + (1-\gamma) \nabla J(\theta_i)_t \odot \nabla J(\theta_i)_t \\
\theta_{(t,i)} &= \theta_{(t-1,i)} – \frac{\eta}{\sqrt{s_{(t,i)} + \epsilon}} \odot \nabla J(\theta_i)_t
\end{align*}
\]
为了解决学习率超参数的问题,AdaDelta维护了一个额外的状态变量\(\Delta \theta_t\),根据上面的公式有
\]
上述使用的是梯度平方的指数加权移动平均数,在AdaDelta中作者又定义了:每次参数的更新值\(\Delta \theta\)的平方的指数加权移动平均数
\]
因此每次更新时,更新值的均方根(Root Mean Squard,RMS)
\]
使用\(RMS(\Delta \theta)_{t-1}\)来近似更新\(t\)时刻的学习速率\(\eta\),这样可以得到其更新的规则为
\]
设初始的\(RMS(\Delta \theta)_0 = 0\),这样就不用设置默认的学习速率了。 也就是,AdaDelta和RMSprop唯一的区别,就是使用\(RMS(\Delta \theta)_{t-1}\)来代替超参数学习速率。 至于为什么可以代替,使用牛顿迭代的思想,这里不再说明,有兴趣可以参看原始论文ADADELTA: An Adaptive Learning Rate Method 。
Adam
Adaptive moment estimation,Adam 是Kingma等在2015年提出的一种新的优化算法,其结合了Momentum和RMSprop算法的思想。相比Momentum算法,其学习速率是自适应的,而相比RMSprop,其增加了冲量项。所以,Adam是两者的结合体。
Adam不只使用梯度平方的指数加权移动平均数\(v_t\),还使用了梯度的指数加权移动平均数\(m_t\),类似动量。
\]
可以看到前两项和Momentum和RMSprop是非常一致的, 由于和的初始值一般设置为0,在训练初期其可能较小,需要对其进行放大
\hat{m}_{t}&=\frac{m_{t}}{1-\beta_{1}^{t}}\\
\hat{v}_{t}&=\frac{v_{t}}{1-\beta_{2}^{t}}
\end{aligned}
\]
这样就得到了更新的规则
\]
作者建议\(\beta_1\)设置为0.9,\(\beta_2\)设置为0.999,取\(\epsilon = 10^{-8}\)。
Summary
下图给出各个梯度下降算法的可视化下降过程
本文综述了一些常见的梯度下降方法,主要是自适应梯度下降。 由于超参数学习速率的难以设定,自适应梯度下降有很好的实用价值。除了使用自适应梯度下降算法外,也可以手动的设定学习速率的自适应过程,例如学习速率的多项式衰减等。