梯度下降法(Gradient descent )是一个一阶最优化算法,通常也称为最陡下降法 ,要使用梯度下降法找到一个函数的局部极小值 ,必须向函数上当前点对应梯度(或者是近似梯度)的反方向的规定步长距离点进行迭代搜索。 如果相反地向梯度正方向迭代进行搜索,则会接近函数的局部极大值点;这个过程则被称为梯度上升法 ,相反则称之为梯度下降法。
说起梯度下降算法,其实并不是很难,它的重要作用就是求函数的极值。梯度下降就是求一个函数的最小值,对应的梯度上升就是求函数最大值。虽然梯度下降与梯度上升都是求函数极值的算法,为什么我们常常提到“梯度下降”而不是梯度上升“呢?主要原因是在大多数模型中,我们往往需要求函数的最小值,即使求最大值也可以转化为求最小值(取反即可)。比如BP神经网络算法,我们得出损失函数,当然是希望损失函数越小越好,这个时候肯定是需要梯度下降算法的。梯度下降算法作为很多算法的一个关键环节,其重要意义是不言而喻的
对于神经网络模型,借助于BP算法可以高效地计算梯度,从而实施梯度下降算法。但梯度下降算法一个老大难的问题是:不能保证全局收敛。如果这个问题解决了,深度学习的世界会和谐很多。梯度下降算法针对凸优化问题原则上是可以收敛到全局最优的,因为此时只有唯一的局部最优点。而实际上深度学习模型是一个复杂的非线性结构,一般属于非凸问题,这意味着存在很多局部最优点(鞍点),采用梯度下降算法可能会陷入局部最优,这应该是最头疼的问题。这点和进化算法如遗传算法很类似,都无法保证收敛到全局最优。因此,我们注定在这个问题上成为“高级调参师”。可以看到,梯度下降算法中一个重要的参数是学习速率,适当的学习速率很重要:学习速率过小时收敛速度慢,而过大时导致训练震荡,而且可能会发散。理想的梯度下降算法要满足两点:收敛速度要快;能全局收敛。为了这个理想,出现了很多经典梯度下降算法的变种,下面将分别介绍它们。
冲量梯度下降算法是Boris Polyak在1964年提出的,其基于这样一个物理事实:将一个小球从山顶滚下,其初始速率很慢,但在加速度作用下速率很快增加,并最终由于阻力的存在达到一个稳定速率。“冲量”这个概念源自于物理中的力学,表示力对时间的积累效应。
在普通的梯度下降法x -= v中,每次x的更新量v为v = dx * lr,其中dx为目标函数func(x)对x的一阶导数。当使用冲量时,则把每次x的更新量v考虑为本次的梯度下降量 dx * lr与上次x的更新量v乘上一个介于[0, 1]的因子momentum(一般取接近1的值如0.9)的和,即v = dx * lr + v * momemtum。
v = dx * lr + v * momemtum
x=x-v
从公式上可看出:
(1)当本次梯度下降 dx * lr的方向与上次更新量v的方向相同时,上次的更新量能够对本次的搜索起到一个正向加速的作用。
(2)当本次梯度下降- dx * lr的方向与上次更新量v的方向相反时,上次的更新量能够对本次的搜索起到一个减速的作用。
有时候,冲量梯度下降算法也可以按下面方式实现:
v = dx * (1-momemtum) + v * momemtum
x=x-v
此时我们就可以清楚地看到,所谓的冲量项其实只是梯度的指数加权移动平均值。这个实现和之前的实现没有本质区别,只是学习速率进行了放缩一下而已。
TensorFlow中提供了冲量梯度下降算法的实现:
tf.train.MomentumOptimizer(learning_rate=learning_rate,
momentum=0.9)
NAG算法全称Nesterov Accelerated Gradient,是YuriiNesterov在1983年提出的对冲量梯度下降算法的改进版本,其速度更快。然而,让一个小球盲目地沿着斜坡滚下山是不理想的,我们需要一个更聪明的球,它知道下一步要往哪里去,因此在斜坡有上升的时候,它能够自主调整方向。Nesterov Accelerated Gradient 是基于冲量梯度下降算法进行改进的一种算法,也是梯度下降算法的变种,我们利用动量项算来更新参数,通过计算能够告诉我们参数未来位置的一个近似值(梯度并不是完全更新),这也就是告诉我们参数大致将变为多少。通过计算关于参数未来的近似位置的梯度,而不是关于当前的参数的梯度,我们可以高效的求解。
NAG算法是Yurii Nesterov在1983年提出的对冲量梯度下降算法的改进版本,其速度更快。其变化之处在于计算“超前梯度”更新冲量项,具体公式如下:
既然参数要沿着 γ⋅m 更新,不妨计算未来位置 θ−γ⋅m 的梯度,然后合并两项作为最终的更新项,其具体效果如图1所示,可以看到一定的加速效果。在TensorFlow中,NAG优化器为:
tf.train.MomentumOptimizer(learning_rate=learning_rate, momentum=0.9, use_nesterov=True)
AdaGrad是Duchi在2011年提出的一种学习速率自适应的梯度下降算法。在训练迭代过程,其学习速率是逐渐衰减的,经常更新的参数其学习速率衰减更快,这是一种自适应算法。 其更新过程如下:
式中是梯度平方的积累量 s ,在进行参数更新时,学习速率要除以这个积累量的平方根,其中加上一个很小值 ε 是为了防止除0的出现。由于 s 是逐渐增加的,那么学习速率是衰减的。考虑如图所示的情况,目标函数在两个方向的坡度不一样,如果是原始的梯度下降算法,在接近坡底时收敛速度比较慢。而当采用AdaGrad,这种情况可以被改观。由于比较陡的方向 s 比较大,其学习速率将衰减得更快,这有利于参数沿着更接近坡底的方向移动,从而加速收敛。
AdaGrad算法优缺点如下:
(1)把每一维度的梯度平方和记录下来,每次学习率都除以这个和
(2)每一维度的学习率不一样,且都在不断减小
(3)在梯度大的维度,减小下降速度;在梯度小的维度,加快下降速度
(4)让学习率适应参数,对于出现次数较少的特征,我们对其采用更大的学习率,对于出现次数较多的特- 征,我们对其采用较小的学习率。因此,Adagrad非常适合处理稀疏数据。
(5)Adagrad算法的一个主要优点是无需手动调整学习率
(6)Adagrad的一个主要缺点是它在分母中累加梯度的平方:由于每增加一个正项,在整个训练过程中,累加的和会持续增长。这会导致学习率变小以至于最终变得无限小,在学习率无限小时,Adagrad算法将无法取得额外的信息。
(7)TensorFlow也提供了这一优化器:tf.train.AdagradOptimizer。
4、RMSprop
RMSprop是Hinton在他的课程上讲到的,其算是对Adagrad算法的改进,主要是解决学习速率过快衰减的问题。其实思路很简单,类似Momentum思想,引入一个超参数,在积累梯度平方项进行衰减:
此时可以看到 s 是梯度平方的指数加权移动平均值,其中 γ 一般取值0.9,此时 s 更平稳,减少了出现的爆炸情况,因此有助于避免学习速率很快下降的问题。同时Hinton也建议学习速率设置为0.001。RMSprop是属于一种比较好的优化算法了,在TensorFlow中当然有其身影:
tf.train.RMSPropOptimizer(learning_rate=learning_rate, momentum=0.9, decay=0.9, epsilon=1e-10)
5、Adaptive moment estimation (Adam)
Adam是Kingma等在2015年提出的一种新的优化算法,其结合了Momentum和RMSprop算法的思想。相比Momentum算法,其学习速率是自适应的,而相比RMSprop,其增加了冲量项。所以,Adam是两者的结合体:
可以看到前两项和Momentum和RMSprop是非常一致的, 由于和的初始值一般设置为0,在训练初期其可能较小,第三和第四项主要是为了放大它们。最后一项是参数更新。其中超参数的建议值是: β1=0.9,β2=0.999,ε=1e−8 。Adm是性能非常好的算法,在TensorFlow其实现如下:
tf.train.AdamOptimizer(learning_rate=0.001, beta1=0.9, beta2=0.999, epsilon=1e-08)
对于梯度下降you算法,这应该是一个最重要的超参数。如果学习速率设置得非常大,那么训练可能不会收敛,就直接发散了;如果设置的比较小,虽然可以收敛,但是训练时间可能无法接受;如果设置的稍微高一些,训练速度会很快,但是当接近最优点会发生震荡,甚至无法稳定。不同学习速率的选择影响可能非常大。
理想的学习速率是:刚开始设置较大,有很快的收敛速度,然后慢慢衰减,保证稳定到达最优点。所以,前面的很多算法都是学习速率自适应的。除此之外,还可以手动实现这样一个自适应过程,如实现学习速率指数式衰减。
我们希望优化算法能够收敛速度快,并且想找到全局最优。对于凸函数来说,其仅有一个极值点,就是全局最优点,此时采用梯度下降算法是可以收敛到最优点的,因为沿着下坡的道路走就可以了。但是其实现在的深度学习模型是一个庞大的非线性结构,这样其一般是非凸函数,存在很多局部最优点(local optimum),一旦梯度下降算法跳进局部陷阱,可以想象其很难走出来,这就很尴尬了,此时梯度下降算法变得不再那么可靠,因为我们想要的是全局最优。很难找到全局最优,这可能是目前优化算法共同面对的问题。不过到底深度学习的损失函数是不是存在很多局部最优点呢?前面所有的分析都是基于低维空间,我们很容易观察到局部最优点。但是深度学习的参数一般庞大,其函数已经成为了超高维空间。但是Bengio等最新的研究表明,对于高维空间,非凸函数最大的存在不是局部最优点,而是鞍点(saddle point),鞍点也是梯度为0的点,但是它不像局部最优点或者全局最优点。对于局部最优或者全局最优点,其周围的所有方向要朝向上(最小)或者朝向上(最大),但是考虑到参数庞大,很有可能是一部分方向朝下,一部分方向朝上,这就成为了鞍点。意思就是说在高维度空间,不大可能像低维度空间那样出现很多局部最优。而且鞍点也不大可能会成为梯度下降算法的葬身之地。那么真正影响梯度下降算法会是什么呢?可能是平稳区(plateaus),如果出现大面积梯度很小或者近似为0的区域,那么梯度下降算法就找不到方向,想象你自己站在一望无际的平原,估计你也方向感全无了。
优先选择学习速率自适应的算法如RMSprop和Adam算法,目前比较常用的应该仍是 Adam ,大部分情况下其效果是较好的。还有一定要特别注意学习速率的问题。其实还有很多方面会影响梯度下降算法,如梯度的消失与爆炸,这也是要额外注意的。最后不得不说,梯度下降算法目前无法保证全局收敛。