写在前面:翻译自经典的梯度下降法的总结文章 An overview of gradient descent optimization algorithms
梯度下降是解决优化问题中最常用的算法,也是目前优化神经网络的通用方法。
深度学习库中封装了很多时下最先进的优化梯度下降法的算法,如果我们不了解这些算法的优点和缺点,那我们就很难知道哪种场景下用哪种算法,为什么这种场景下用这种算法优化模型更好。
这篇文章的目的就是让你对各种优化梯度下降法的算法有个直观的理解,让你在使用他们的时候有个直觉的选择。
首先我们会先讲下三种梯度下降,然后简单概括下它们在训练时遇到的challenges。
为了解决这些challenges,研究学者们提出了很多的优化梯度下降的算法,我们会讲下这些算法提出的动机即去解决的challenge是什么、基于这种优化又是如何推导出其导数更新规则的。
最后我们简短的回顾下并行计算这些梯度下降优化算法的算法和框架。
一、三种梯度下降法
梯度下降法是优化目标函数J的一种方法。
梯度下降法有三种变形,主要区别在于一次迭代计算使用多少训练数据来计算目标函数的梯度。
根据使用的数据的多少,我们会在参数更新的准确率上和更新速度上做一个权衡选择。
1、Batch 批量梯度下降法
Batch梯度下降法是每一次计算梯度都要喂入全部的训练数据。
这使得Batch梯度下降法的计算比较慢,而且训练数据很大的情况容易超出可用内存。Batch梯度下降法也不允许我们在线更新模型,即使用实时的数据(data on-the-fly),因为它要一次喂入全部的训练数据。而且因为训练数据中可能存在相似或相同的样本,每次都要对全部的训练数据进行梯度计算,也可能会造成计算的冗余。
Batch梯度下降法的伪代码是:
for i in range(nb_epochs):
params_grad = evaluate_gradient(loss_function, data, params)
params = params - learning_rate * params_grad
对于预先定义好的epochs,我们先计算目标函数在整个数据集上的梯度,然后沿着梯度的反方向更新梯度,更新的步幅由学习率决定。
如果目标函数曲面是凸的,那么Batch梯度下降法能保证收敛到全局最小;如果目标函数曲面是非凸的,那么Batch梯度下降法可以保证收敛到一个局部最小;2、Stochastic 随机梯度下降法
随机梯度下降法SGD是每次更新参数只使用一个训练数据。
所以,随机梯度下降法SGD计算更快,适合在线学习。
但是SGD对参数的高频率更新通常是高方差的,这使得目标函数的不是稳步收敛,而是动荡的收敛。
在非凸的目标函数曲面情况下,Batch梯度下降法会收敛到一个局部最小值点,SGD却可能因为它的高震荡而跳跃至另一个更好的局部最小值点,当然也有可能跳过收敛到一个较糟糕局部最小值点。
也有证明,随着迭代次数增加,如果我们逐步减小学习率,对于非凸优化,SGD算法确实可以收敛到一个局部最小值点;对于凸优化,可以收敛到一个全部最小点。
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
区别在于加了一个遍历数据的循环,另外就是每次遍历数据前shuffle数据。
3、Mini-Batch 小批量梯度下降法
Mini-batch梯度下降法中和了上面两种下降法,每次更新参数使用小批量的训练数据。
一方面它减少了参数更新的方差,能保证更稳定的收敛;另一方面它可以使用目前在深度学习领域比较先进的矩阵优化算法来计算梯度,使得计算更高效。
一般Mini-batch的大小取自 50-256,更推荐选择2^N的一个数值。
小批量梯度下降通常是训练神经网络时选择的算法,并且在使用小批量时通常也会使用术语 SGD。
Mini-batch梯度下降法的伪代码:
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
二、Mini-Batch小批量梯度下降法面临的挑战Challenges
1、很难选择一个正确的学习率
学习率太小,收敛速度太慢;学习率太大,可能会阻碍收敛,使得目标函数在最小值出动荡或者发散不收敛。
2、调整学习率的计划和阈值必须提前确定,很难使用数据集的特征
对于学习率可以尝试在训练期间进行调整,比如退火法调整学习率,即根据预定义的时间表或当 epoch 间的目标变化低于阈值时,就降低学习率。 然而,这些时间表和阈值必须提前定义,因此无法适应数据集的特征
3、所有的参数使用相同的学习率,很难适应参数对应的特征的稀疏性
如果训练数据是稀疏的,不同的特征出现的频率具有非常大的差异性,那么我们就不希望所有的特征对应的参数以相同的步幅进行更新,而是希望出现频率更少的特征对应的参数每次更新步幅更大些,出现频率更高的特征对应的参数每次更新步幅更小一些。
4、难逃脱次优局部最小值点和鞍点
对于高度非凸的目标函数,训练神经网络模型寻找最小值点的一大挑战就是容易陷入众多次优的局部最小值点中。
更大的一个挑战来自鞍点。在鞍点处,所有维度上的梯度为0,导致参数不更新,模型陷入鞍点处无法逃脱。
三、梯度下降的优化算法
接下来我们来讲下在深度学习领域中使用的一些算法,以及它们又是如何解决上文中的挑战问题的。这里我们不讨论在实践中无法对高维数据集进行计算的算法,比如牛顿法。
1、Momentum 动量法
2、Nesterov accelerated gradient 牛顿加速梯度法
3、Adagra
4、Adadelta
5、RMSprop
6、Adam
7、AdaMax
8、Nadam
9、AMSGrad
10、其他优化算法
11、优化算法可视化
12、应该选择哪种优化算法?
四、随机梯度下降法的并行和分布式计算
1、Hogwild!
2、Downpour SGD
3、Delay-tolerant Algorithms for SGD
4、TensorFlow
5、Elastic Averaging SGD
五、优化SGD算法的其他策略
1、Shuffling and Curriculum Learning
2、Batch normalization 批规范化
3、Early stopping 早停
4、Gradient noise