从 SGD 到 Adam —— 常见优化算法总结
1 概览
虽然梯度下降优化算法越来越受欢迎,但通常作为黑盒优化器使用,因此很难对其优点和缺点的进行实际的解释。本文旨在让读者对不同的算法有直观的认识,以帮助读者使用这些算法。在本综述中,我们介绍梯度下降的不同变形形式,总结这些算法面临的挑战,介绍最常用的优化算法,回顾并行和分布式架构,以及调研用于优化梯度下降的其他的策略。
2 Gradient descent 变体
有3种基于梯度下降的方法,主要区别是我们在计算目标函数( objective function)梯度时所使用的的数据量。2.1 Batch gradient descent 批梯度下降法
计算公式如下: 其中η表示学习率。 该方法在一次参数更新时,需要计算整个数据集的参数。 优点:可以保证在convex error surfaces 条件下取得全局最小值,在non-convex surfaces条件下取得局部极小值。 缺点:由于要计算整个数据集的梯度,因此计算比较慢,当数据量很大时,可能会造成内存不足。另外,该方法也无法在线(online)更新模型。 计算的伪代码如下:for i in range ( nb_epochs ): params_grad = evaluate_gradient ( loss_function , data , params ) params = params - learning_rate * params_grad
其中,params和params_grad均是向量(vector)。
2.2 Stochastic gradient descent(SGD) 随机梯度下降
计算公式如下:for i in range(nb_epochs): np.random.shuffle(data) for example in data: params_grad = evaluate_gradient(loss_function, example, params) params = params - learning_rate * params_grad
注:每次循环中,我们需要先将样本打乱。
2.3 Mini-batch gradient descent
小批量梯度下降法结合了上述两种方法的优点,在每次跟新参数时使用小批量(n个样本)的训练样本。for i in range(nb_epochs): np.random.shuffle(data) for batch in get_batches(data, batch_size=50): params_grad = evaluate_gradient(loss_function, batch, params) params = params - learning_rate * params_grad
3 Challenges
mini-batch梯度下降法虽然有上述的优点,但是仍然还是有一些问题: 1)选择一个合适的学习率比较困难。学习率太小会导致收敛缓慢,学习率太大会损失函数在最小值附近波动甚至无法收敛。 2)学习率调整( Learning rate schedules)在训练时,根据预定义的策略(如目标函数的相邻迭代之间的下降值小于阈值时)减少学习率。这种方法需要提前设置好策略和阈值,而且可能无法适应数据集的特点。 3)所有参数的更新使用同一个学习率。如果我们的数据是稀疏的,同时特征的频率差异很大,我们可能不想使用同样的学习率更新所有的的参数,对于那些出现次数较少的特性,我们对其使用更大的学习率。 4)非凸误差函数普遍出现在神经网络中,在优化这类函数时,其中一个挑战就是使函数避免陷入次优的局部最小值。 Dauphin等人指出出现这种困难实际上并不是来自局部最小值,而是来自鞍点,即那些在一个维度上是递增的,而在另一个维度上是递减的。这些鞍点通常被具有相同误差的点包围,因为在任意维度上的梯度都近似为0,所以SGD很难从这些鞍点中逃开。4 Gradient descent optimization algorithms
下面我们将介绍一些在深度学习中广泛使用的优化算法,来解决上述提到的问题。我们不会讨论实际中不适合高维数据集中计算的算法,如牛顿法的二阶方法。4.1 Momentum 动量法
动量法改进自SGD算法,让每一次的参数更新方向不仅仅取决于当前位置的梯度,还受到上一次参数更新方向的影响。 SGD很难通过陡谷(指在一个维度上的表面弯曲程度远大于其他维度的区域),这种情况通常出现在局部最优点附近。 在这种情况下,SGD摇摆地通过陡谷的斜坡,同时,沿着底部到局部最优点的路径上只是缓慢地前进,这个过程如图2a所示。 如图2b所示,动量法[16]是一种帮助SGD在相关方向上加速并抑制摇摆的一种方法。动量法将历史步长的更新向量的一个分量增加到当前的更新向量中(部分实现中交换了公式中的符号) 公式如下:4.2 Nesterov accelerated gradient (NAG)
NAG是在Momentum的基础上改进的。 NAG就对Momentum说:“既然我都知道我这一次一定会走4.3 Adagrad
Adagrad是这样一种基于梯度的优化算法:它让学习率适应参数,对于出现次数较少的特征,我们对其采用更大的学习率,对于出现次数较多的特征,我们对其采用较小的学习率。因此,Adagrad非常适合处理稀疏数据。 AdaGrad算法就是将每一个参数的每一次迭代的梯度取平方累加后在开方,用全局学习率除以这个数,作为学习率的动态更新。 具体的计算方法如下: 1)计算梯度4.4 Adadelta
Adadelta是Adagrad的一种扩展算法,以处理Adagrad学习速率单调递减的问题。不是计算所有的梯度平方,Adadelta将计算计算历史梯度的窗口大小限制为一个固定值。 在Adadelta中,无需存储先前的w个平方梯度,而是将梯度的平方递归地表示成所有历史梯度平方的均值。在t时刻的均值只取决于先前的均值和当前的梯度(分量类似于动量项):4.5 RMSprop
RMSprop是一个未被发表的自适应学习率的算法,该算法由Geoff Hinton在其Coursera课堂的课程6e中提出。 RMSprop和Adadelta在相同的时间里被独立的提出,都起源于对Adagrad的极速递减的学习率问题的求解。实际上,RMSprop是先前我们得到的Adadelta的第一个更新向量的特例: 同样,RMSprop将学习率分解成一个平方梯度的指数衰减的平均。Hinton建议将γ设置为0.9,对于学习率,一个好的固定值为0.001。4.6 Adam 自适应矩估计(Adaptive Moment Estimation,Adam)[9]是另一种自适应学习率的算法,Adam对每一个参数都计算自适应的学习率。除了像Adadelta和RMSprop一样存储一个指数衰减的历史平方梯度的平均,Adam同时还保存一个历史梯度的指数衰减均值,类似于动量:
4.7 AdaMax
见原文4.8 Nadam
见原文4.9 Visualization of algorithms
下面两张图给出了上述优化算法的优化行为的直观理解。(还可以看看这里关于Karpathy对相同的图片的描述以及另一个简明关于算法讨论的概述)。 在图4a中,我们看到不同算法在损失曲面的等高线上走的不同路线。所有的算法都是从同一个点出发并选择不同路径到达最优点。注意:Adagrad,Adadelta和RMSprop能够立即转移到正确的移动方向上并以类似的速度收敛,而动量法和NAG会导致偏离,想像一下球从山上滚下的画面。然而,NAG能够在偏离之后快速修正其路线,因为NAG通过对最优点的预见增强其响应能力。 图4b中展示了不同算法在鞍点出的行为,鞍点即为一个点在一个维度上的斜率为正,而在其他维度上的斜率为负,正如我们前面提及的,鞍点对SGD的训练造成很大困难。这里注意,SGD,动量法和NAG在鞍点处很难打破对称性,尽管后面两个算法最终设法逃离了鞍点。而Adagrad,RMSprop和Adadelta能够快速想着梯度为负的方向移动,其中Adadelta走在最前面。正如我们所看到的,自适应学习速率的方法,即 Adagrad、 Adadelta、 RMSprop 和Adam,最适合这些场景下最合适,并在这些场景下得到最好的收敛性。