梯度下降优化算法
大多数学习算法都涉及到优化,优化是指改变 x 以最小化或者最大化某个函数 f(x) 的过程。通常我们所说的优化算法都是指最小化的过程,因此,最大化的过程可以通过最小化 -f(x) 来实现。
导数是指某个函数 f(x) 在某一点上的斜率,它可以表明如何缩放输入的小变化才能在输出上获得相应的变化:。因此,导数对于最优化的过程非常有用。例如,如果对于足够小的来说,比 f(x) 小,因此我们可以把 x 往导数的反方向移动一小步来减少 f(x)。这种技术被称为梯度下降。
但是,当导数等于 0的时候,不能为我们提供方向信息。这时,称为临界点或者驻点。如果这个点是局部极小点,说明f(x)小于周围所有的点,因此这时不能通过移动一个步长来减少 f(x)。同样的,对于极大值点也是这样。
在深度学习的场景下,往往是针对具有多维输入的函数。这时我们需要用到偏导数的概念,偏导数衡量点 X处只有增加时,f(x)如何变化。梯度是相对于向量求导,f 的导数是包含所有偏导数的向量,记为。在 u(单位向量)方向的方向导数是函数 f 在u 上的斜率,方向导数是函数关于的导数(在时取得)。根据链式法则,当时,。因此,为了最小化 f,需要找到使 f 下降最快的方向。计算方向导数:
其中,是 u与梯度的夹角。当时,忽略与 u 无关的项,就可以得到,因此,在u 与梯度方向相反时取得最小值。梯度向量指向上坡,负梯度向量指向下坡,我们在负梯度方向上移动可以减少 f(x)。这被称为梯度下降法或者最速下降法。
梯度下降法建议新的点为:。是正标量,用来确定步长大小。通常,我们选择一个小常数,有时选择使得方向导数消失的步长。还可以根据几个来计算,选择能产生最小目标值的值。这种策略被称为线搜索。梯度下降法在每个元素为0时收敛,在某些情况下,为了避免进行迭代计算,直接解方程直接跳到临界点。
虽然梯度下降被限制在连续空间内,但不断向更好的方向移动一小步的概念可以扩展到离散空间中。递增带有离散参数的目标函数被称为爬山算法。
在梯度下降法中有三种主要的框架,主要区别在于更新参数时使用的样本规模不同,因此,他们最终的优化效果以及优化时间也不同。主要是以下三个框架:
- 批量梯度下降
- 随机梯度下降
- 小批量梯度下降
批量梯度下降(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步之后)改进到。但是在随机梯度情况下,收敛率并没有提升。
自适应学习率算法
神经网络研究员早就意识到学习率肯定是难以设置的超参数之一,因为它对模型的性能有显著的影响。动量算法可以在一定程度缓解这些问题,但这样做的代价是引入了另一个超参数。在这种情况下,自然会问有没有其他方法。如果我们相信方向敏感度在某种程度是轴对齐的,那么每个参数设置不同的学习率,在整个学习过程中自动适应这些学习率是有道理的。
Delta-bar-delta 算法是一个早期的在训练时适应模型参数各自学习率的启发式方法。该方法基于一个很简单的想法,如果损失对于某个给定模型参数的偏导保持相同的符号,那么学习率应该增加。如果对于该参数的偏导变化了符号,那么学习率应减小。当然,这种方法只能应用于全批量优化中。
最近,提出了一些增量(或者基于小批量)的算法来自适应模型参数的学习率。
AdaGrad
AdaGrad 算法可以独立地适应所有模型参数的学习率,缩放每个参数反比于其所有梯度历史平方值总和的平方根。具有损失最大偏导的参数相应地有一个快速下降的学习率,而具有小偏导的参数在学习率上有相对较小的下降。净效果是在参数空间中更为平缓的倾斜方向会取得更大的进步。
在凸优化背景中,AdaGrad 算法具有一些令人满意的理论性质。然而,经验上已经发现,对于训练深度神经网络模型而言,从训练开始时积累梯度平方会导致有效学习率过早和过量的减小。AdaGrad 在某些深度学习模型上效果不错,但不是全部。
AdaGrad 算法的具体过程如下所示:
AdaDelta
AdaDelta是对AdaGrad算法的改进,主要解决了两个方面的问题:
- 训练过程中学习率不断衰减
- 需要手工选择全局学习率
在AdaGrad方法中,每次迭代中分母从训练开始就累积平方梯度。由于每一项都是正的,因此在整个训练过程中,这个累加的总和将继续增长,从而有效地缩小了每个维度的学习率。 经过多次迭代,该学习率将变得无限小。
AdaDelta算法没有在所有时间内累积平方梯度的总和,而是将过去的梯度的窗口限制为一定的固定大小w(而不是大小t,其中t是AdaGrad中的当前迭代)。通过这种窗口累积,AdaDelta的分母不能累积到无穷大,而是变成使用最近的梯度的局部估计。这样可以确保即使在完成多次更新之后,学习仍继续取得进展。
由于存储w个先前的平方梯度效率低下,因此我们的方法将这种累加实现为平方梯度的指数衰减平均值。假设在第t步中,该平均值可以通过以下公式计算。
其中的衰减常数类似于动量法中使用的衰减常数。由于在参数更新中要求此值的平方根,因此变成了直到时间t的先前平方梯度的RMS。具体的计算公式如下:
添加了一个常数以更好地调节公式中的分母,最终生成的参数更新公式为:
此外,还可以考虑估算。当前时间步的未知,因此假设曲率是局部平滑的,并通过在先于的大小为w的窗口上计算指数衰减的RMS来近似。最后生成的AdaDelta算法的参数更新公式如下:
同样的常数也被添加到分子RMS上。 此常数的目的是从第一次迭代开始(),确保即使先前的更新变小也继续取得进展。
最后,在每一个时间步t中,AdaDelta算法进行参数更新的具体过程如下:
该算法具有的特点如下:
- AdaDelta不依赖于全局学习率
- 训练初中期,训练的加速效果很快
- 训练后期,反复在局部最小值附近波动
RMSProp
RMSProp 算法修改AdaGrad 以在非凸设定下效果更好,改变梯度积累为指数加权的移动平均。AdaGrad 旨在应用于凸问题时快速收敛。当应用于非凸函数训练神经网络时,学习轨迹可能穿过了很多不同的结构,最终到达一个局部是凸碗的区域。AdaGrad 根据平方梯度的整个历史收缩学习率,可能使得学习率在达到这样的凸结构前就变得太小了。RMSProp 使用指数衰减平均以丢弃遥远过去的历史,使其能够在找到凸碗状结构后快速收敛,它就像一个初始化于该碗状结构的AdaGrad 算法实例。
RMSProp 的标准形式以及结合Nesterov 动量的形式如下图 所示。相比于AdaGrad,使用移动平均引入了一个新的超参数,用来控制移动平均的长度范围。
经验上,RMSProp 已被证明是一种有效且实用的深度神经网络优化算法。目前它是深度学习从业者经常采用的优化方法之一。
Adam
Adam 是另一种学习率自适应的优化算法,算法具体过程如下图所示。“Adam’’ 这个名字派生自短语“adaptive moments’’。早期算法背景下,它也许最好被看作结合RMSProp 和具有一些重要区别的动量的变种。首先,在Adam 中,动量直接并入了梯度一阶矩(指数加权)的估计。将动量加入RMSProp 最直观的方法是将动量应用于缩放后的梯度,结合缩放的动量使用没有明确的理论动机。其次,Adam 包括偏置修正,修正从原点初始化的一阶矩(动量项)和(非中心的)二阶矩的估计。RMSProp 也采用了(非中心的)二阶矩估计,然而缺失了修正因子。因此,不像Adam,RMSProp 二阶矩估计可能在训练初期有很高的偏置。Adam 通常被认为对超参数的选择相当鲁棒,尽管学习率有时需要从建议的默认修改。
选择正确的优化算法
我们讨论了一系列算法,通过自适应每个模型参数的学习率以解决优化深度模型中的难题。此时,一个自然的问题是:该选择哪种算法呢?
遗憾的是,目前在这一点上没有达成共识。Schaul et al. 展示了许多优化算法在大量学习任务上极具价值的比较。虽然结果表明,具有自适应学习率(以RMSProp 和AdaDelta 为代表)的算法族表现得相当鲁棒,不分伯仲,但没有哪个算法能脱颖而出。
目前,最流行并且使用很高的优化算法包括SGD、具动量的SGD、RMSProp、具动量的RMSProp、AdaDelta 和Adam。此时,选择哪一个算法似乎主要取决于使用者对算法的熟悉程度(以便调节超参数)。
参考文献
- 深度学习 [美] Ian Goodfellow, [加] Yoshua Bengio, [加] Aaron Courville 著,赵申剑 黎彧君 符天凡 李凯 译,张志华 等 审校, 人民邮电出版社
说明
- 本文仅为参考书籍的日常学习总结