梯度下降优化算法
大多数学习算法都涉及到优化,优化是指改变 x 以最小化或者最大化某个函数 f(x) 的过程。通常我们所说的优化算法都是指最小化的过程,因此,最大化的过程可以通过最小化 -f(x) 来实现。
导数是指某个函数 f(x) 在某一点上的斜率,它可以表明如何缩放输入的小变化才能在输出上获得相应的变化:
![f(x+\epsilon )\approx f(x)+\epsilon {f}'(x)](https://i-blog.csdnimg.cn/blog_migrate/920f9dc37dbef6fd76838f31f9b149e6.gif)
因此,导数对于最优化的过程非常有用。例如,如果对于足够小的
![\epsilon](https://i-blog.csdnimg.cn/blog_migrate/32b050cda45b1df21f715657629f4d99.gif)
来说,
![f(x-\epsilon sign({f}'(x)))](https://i-blog.csdnimg.cn/blog_migrate/a5e84d4edd8d83b04925cbfb93ac07c6.gif)
比 f(x) 小,因此我们可以把 x 往导数的反方向移动一小步来减少 f(x)。这种技术被称为梯度下降。
但是,当导数等于 0的时候,不能为我们提供方向信息。这时,称为临界点或者驻点。如果这个点是局部极小点,说明f(x)小于周围所有的点,因此这时不能通过移动一个步长来减少 f(x)。同样的,对于极大值点也是这样。
在深度学习的场景下,往往是针对具有多维输入的函数。这时我们需要用到偏导数的概念,偏导数
![\frac{\partial }{\partial x_{i}}f(X)](https://i-blog.csdnimg.cn/blog_migrate/1d7110180ee3d457481d7a1218348752.gif)
衡量点 X处只有
![x_{i}](https://i-blog.csdnimg.cn/blog_migrate/d665d72d0e4b2b1a7e880fb368f4c1a8.gif)
增加时,f(x)如何变化。梯度是相对于向量求导,f 的导数是包含所有偏导数的向量,记为
![\bigtriangledown _{x}f(x)](https://i-blog.csdnimg.cn/blog_migrate/e99ac40b17ee78796ca95cf81f4307f7.gif)
在 u(单位向量)方向的方向导数是函数 f 在u 上的斜率,方向导数是函数
![f(x+\alpha u)](https://i-blog.csdnimg.cn/blog_migrate/7c9fd845e66901676ad86f70036ae431.gif)
关于
![\alpha](https://i-blog.csdnimg.cn/blog_migrate/debaf45b2a13185bcada5601844a59bc.gif)
的导数(在
![\alpha =0](https://i-blog.csdnimg.cn/blog_migrate/debaf45b2a13185bcada5601844a59bc.gif%20%3D0)
时取得)。根据链式法则,当
![\alpha =0](https://i-blog.csdnimg.cn/blog_migrate/debaf45b2a13185bcada5601844a59bc.gif%20%3D0)
时,
![\frac{\partial }{\partial \alpha }f(x+\alpha u)=u^{T}\bigtriangledown _{x}f(x)](https://i-blog.csdnimg.cn/blog_migrate/a948e1bd7327fea69f8861bc20daceb8.gif)
因此,为了最小化 f,需要找到使 f 下降最快的方向。计算方向导数:
其中,
![\theta](https://i-blog.csdnimg.cn/blog_migrate/798a135f47a1ec3dc636082b66dc9938.gif)
是 u与梯度的夹角。当
![||u||_{2}=1](https://i-blog.csdnimg.cn/blog_migrate/29ca8ffa48363b270abff337365d07b4.gif)
时,忽略与 u 无关的项,就可以得到
![min_{u}cos\theta](https://i-blog.csdnimg.cn/blog_migrate/2af77fb970b28f372881aeb8b7074641.gif)
因此,在u 与梯度方向相反时取得最小值。梯度向量指向上坡,负梯度向量指向下坡,我们在负梯度方向上移动可以减少 f(x)。这被称为梯度下降法或者最速下降法。
梯度下降法建议新的点为:
![{x}'=x-\epsilon \bigtriangledown _{x}f(x)](https://i-blog.csdnimg.cn/blog_migrate/c62415c5235c69c4032ca36120ecb7d2.gif)
![\epsilon](https://i-blog.csdnimg.cn/blog_migrate/32b050cda45b1df21f715657629f4d99.gif)
是正标量,用来确定步长大小。通常,我们选择一个小常数,有时选择使得方向导数消失的步长。还可以根据几个
![\epsilon](https://i-blog.csdnimg.cn/blog_migrate/32b050cda45b1df21f715657629f4d99.gif)
来计算
![f(x-\epsilon \bigtriangledown _{x}f(x))](https://i-blog.csdnimg.cn/blog_migrate/dcda6d3710ea20cd9978b69da5635f16.gif)
选择能产生最小目标值的
![\epsilon](https://i-blog.csdnimg.cn/blog_migrate/32b050cda45b1df21f715657629f4d99.gif)
值。这种策略被称为线搜索。梯度下降法在每个元素为0时收敛,在某些情况下,为了避免进行迭代计算,直接解方程
![\bigtriangledown _{x}f(x)=0](https://i-blog.csdnimg.cn/blog_migrate/e99ac40b17ee78796ca95cf81f4307f7.gif%3D0)
直接跳到临界点。
虽然梯度下降被限制在连续空间内,但不断向更好的方向移动一小步的概念可以扩展到离散空间中。递增带有离散参数的目标函数被称为爬山算法。
在梯度下降法中有三种主要的框架,主要区别在于更新参数时使用的样本规模不同,因此,他们最终的优化效果以及优化时间也不同。主要是以下三个框架:
- 批量梯度下降
- 随机梯度下降
- 小批量梯度下降
批量梯度下降(Batch Gradient Descent,BGD)
这是最常见的梯度下降的方式,主要是使用使用所有的训练集样本对于每一个参数求偏导,然后更新参数。其参数更新的公式如下:。
由于BGD每次更新参数使用所有的数据集,因此每次更新的方向是正确的,最终能够保证收敛于极值点(如果是凸函数,就是全局最优;如果是非凸函数,则是局部最优)。但是,同样由于每次使用所有的数据集,因此更新时间较长,而且对于内存的消耗的较高,所以并不适合用于在线学习。
随机梯度下降(Stochastic Gradient Descent,SGD)
随机梯度下降和BGD的方法类似,但是每次更新参数的时候并不是使用所有的训练集样本。SGD每次更新参数仅仅随机选择一个样本,更新公式:。
SGD每次仅仅从训练集中随机选择一个样本进行参数更新,因此训练速度比较快,可以进行在线学习。但是,也是由于每次随机选择一个样本,因此会造成每次更新参数可能并不是朝着最优方向学习,学习的波动比较大。但是,对于非凸函数,这种特点可能会在训练过程中,使得学习算法跳出局部最优点,有可能在学习结束的时候达到更好的局部最优点或者全局最优点。
小批量梯度下降(Mini-Batch Gradient Descent,MBGD)
从上面两种方法的介绍中,可以发现它们各有自己的缺点。为了克服这些缺点,提出采用小批量的样本进行参数更新,每次从训练集中选择m个样本进行学习。这样可以避免使用所有的数据集,从而导致的学习速度过慢的问题;也可以避免每次只使用一个样本学习而导致的学习波动过大的问题。其更新公式:。具体过程如下:
MBGD每次只选择一小部分样本进行学习,因此不用担心内存问题,可以利用矩阵运算进行高效计算。一般来说,m通常选择[50,256]之间进行学习,并且这种方法通常应用在深度学习中。
在梯度下降优化算法中,一个关键的参数就是学习率。如果设置的过大,会导致算法难以收敛,如果过小,会导致算法学习速度过慢。在实践中,对于SGD、MBGD一般随着时间的推移逐渐衰减学习率。这是因为在梯度估计中引入的噪声源(m个样本的随机采样)并不会在极小点处消失。相比之下,BGD达到极小点时,真实的梯度也会变得很小,因此,BGD可以使用固定的学习率。
保证MBGD收敛的充分条件是:,并且
。实践中,一般使用线性衰减学习率直到第
次迭代:
,其中
。在
步迭代之后,一般使得学习率保持一个常数。
学习率可以通过实验和误差来选取,通常最常用的方法是检测目标函数随时间变化的学习曲线。
SGD及相关的小批量亦或更广义的基于梯度下降的在线学习优化算法,他们的优势就是每一步更新的计算时间并不依赖于训练样本数量的多寡。即使训练样本数量比较大,他们也能够收敛。对于足够大的数据集,SGD可能会在处理整个训练集之前就收敛到最终测试误差的某个固定容量之内。
问题和挑战
在梯度下降算法中,存在很多的挑战:
- 学习率的选择问题,如果选择较小的学习率会导致学习过程比较缓慢;如果选择较大的学习率,会导致难以收敛,会在极小点处震荡。
- 学习率的调整,试图在学习的过程中,对学习率进行动态调整。一般使用事先制定好的策略或者在每次迭代中衰减一个较小的阈值。上面三种算法并不能自适应学习率的变化。
- 模型中所有参数的更新都是用相同的学习率。当特征比较稀疏或者每个特征有不同的统计特征时,就不能再每次更新时使用相同的学习率,对于出现较少的特征,应该采用更大的学习率。
- 对于非凸目标函数,容易陷入非最优的局部极值点中。
为了解决上述的几个问题,并且介绍一些在深度学习中比较常用的梯度下降的优化算法。
Momentum
动量法旨在加速学习,特别是处理高曲率、小但一致的梯度,或是带噪声的梯度。动量法积累了之前的梯度指数级衰减的移动平均,并且继续沿该方向移动。动量的效果如下:
动量算法引入变量v充当速度,它代表参数在参数空间移动的方向和速率。速度被设为负梯度的指数衰减平均。动量在物理含义上是质量乘以速度,假设是单位质量,那么速度也可以看成动量。超参数决定了之前梯度的贡献衰减得有多快。更新规则如下:
相对于,
越大,之前的梯度对现在方向的影响也就越大。带动量的SGD算法如下所示:
之前的步长只是梯度范数乘以学习率,现在步长取决于梯度序列的大小和排列。当许多连续的梯度指向相同的方向时,步长最大。如果动量算法总是观测到梯度g,那么它会在方向 -g上不停的加速,直到达到最终速度,其中步长为:
因此,将动量的超参数视为 有助于理解。例如,
对应着最大速度10倍梯度下降算法。在实践中,
一般的取值为0.5,0.9和0.99。和学习率一样,
也会随着时间不断调整,一般初始值是一个较小的值,随后慢慢变大,随着时间推移调整
没有收缩
重要。
Nesterov加速梯度算法(Nesterov Accelerated Gradient,NAG)
NAG算法是一种给予我们的动量项预知能力的方法。首先使用动量项来更新
,因此可以通过计算
可以得到参数的下一个位置的估计。我们就可以通过计算参数下一个位置的梯度来实现向前看。更新规则如下:
动量法是计算当前位置的梯度,然后在更新累计梯度方向上大幅度跳跃(下图中蓝色的线)。而NAG首先在先前累计梯度上进行大幅度跳跃(棕色向量),然后在评估这个的梯度,进行一定程度的修正。这种预期更新防止我们进行的太快,也带来更高的速度。具体过程如下:
NAG的具体更新规则如下:
其中参数和
发挥了和标准动量法中类似的效果,两者之间的主要区别在于梯度计算上,Nesterov动量中,梯度计算在施加当前速度之后,因此,Nesterov可以解释为往标准的动量方法中添加一个校正因子。完整的Nesterov算法如下所示:
在凸批量梯度的情况下,Nesterov动量将额外误差收敛率从O(1/K)(k步之后)改进到。但是在随机梯度情况下,收敛率并没有提升。