最近有用到Adam优化器寻思了解下,找了些博客看看,大多是对比及几个的优劣,看不太懂,于是看了Sebastian Ruder的An overview of gradient descent optimization algorithms ,大佬就是大佬分析的非常透彻。特分享自译的版本。
梯度下降优化算法,虽然越来越流行,但经常被用作黑盒优化器,因为它们的优点和缺点的实际解释是很难得到的。这篇文章的目的是为读者提供直观的关于不同算法的行为,介绍怎么使用它们。在这篇概述中,我们研究了梯度下降的不同变体,总结了挑战,介绍了最常见的优化算法,回顾了并行和分布式环境下的架构,并研究了其他优化梯度下降的策略
梯度下降法有三种变体,它们在我们使用多少数据来计算目标函数的梯度上有所不同。根据数据量,我们在参数更新的准确性和执行更新所需的时间之间进行权衡。
批处理梯度下降法,计算成本函数的梯度 参数θ的整个训练数据集:
由于我们需要计算整个数据集的梯度来执行一次更新,批处理梯度下降可能非常缓慢,而且对于不适合内存的数据集来说非常棘手。批量梯度下降也不允许我们在线更新我们的模型,即使用新的例子在飞行。
在代码中,批量梯度下降看起来像这样:
for i in range(nb_epochs):
params_grad = evaluate_gradient(loss_function , data, params)
params = params - learning_rate * params_grad
对于预先定义的几个epoch,我们首先计算整个数据集的损失函数的梯度向量params_grad。请注意,最先进的深度学习库提供自动分化,有效地计算梯度一些参数。如果您自己推导梯度,那么梯度检查是一个好主意。
然后我们沿着梯度的方向更新参数,学习率决定我们执行的更新的大小。保证批量梯度下降收敛于凸误差曲面的全局最小值和非凸曲面的局部最小值。
相反,随机梯度下降(SGD)对每个训练示例x(i)和y(i)执行参数更新:
批处理梯度下降对大型数据集执行冗余计算,因为它在每个参数更新之前重新计算类似示例的梯度。SGD通过每次执行一个更新来消除这种冗余。因此,它通常更快,也可以用于在线学习。SGD执行频繁的更新,其方差很大,导致目标函数出现很大的波动,如图1所示。
当批量梯度下降收敛到参数所在盆地的最小值时,SGD s的波动,一方面,使它跳跃到新的和可能更好的局部最小值。另一方面,这最终会使收敛变得非常复杂,因为SGD会继续超调。然而,已有研究表明,当我们缓慢降低学习速率时,SGD表现出与批梯度下降相同的收敛行为,几乎可以肯定地分别收敛于非凸优化和凸优化的局部或全局最小值。它的代码片段只是在训练示例上添加一个循环,并计算每个示例的梯度.。请注意,我们在每个epoch中重新排列训练数据,如第6.1节所述。
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_gra
小批量梯度下降最终取得了最好的两个结果,并执行更新的每一个小批量的n个训练的例子:
这样一来,a)减小了参数更新的方差,从而使收敛更稳定;b)可以利用高度优化的矩阵优化,这是最先进的深度学习库所共有的,这使得计算梯度w.r.t.非常高效。常见的迷你批处理大小在50到256之间,但是可以根据不同的应用程序而变化。小批量梯度下降通常是训练神经网络时选择的算法,小批量梯度下降通常也用SGD这个词。
在代码中,我们不再对示例进行迭代,而是对大小为50的小批进行迭代:
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
SGD在沟壑的导航方面有困难,也就是说,在一个维度的表面曲线比在另一个维度的更陡峭的区域,这在局部最优值附近是很常见的。在这些情况下,SGD在峡谷的斜坡上振荡,而只在底部向局部最优方向缓慢前进,如图2a所示。
动量是一种在相关方向上加速SGD并抑制振荡的方法,如图2b所示。它通过添加更新矢量的γ过去一小部分时间步更新当前矢量
动量项γ通常设置为0.9或类似的值。
本质上,当使用动量时,我们把球推下山。球在滚下坡时积累的动力,变得越来越快的路上(直到它达到终端速度,如果有空气阻力,即γ< 1)。同样的事情也发生在我们的参数更新上:对于梯度指向相同方向的维度动量项增加,对于梯度改变方向的维度动量项减少。因此,我们得到更快的收敛和减少振荡。
然而,一个球从山上滚下来,盲目地跟随斜坡,是非常不令人满意的。
我们希望有一个更聪明的球,一个知道自己要去哪里的球,这样它就知道在山坡再次倾斜之前减速。
Nesterov accelerated gradient (NAG)是一种给我们的动量项赋予这种预见性的方法。我们知道,我们将使用我们的动量项γv_(t-1)移动参数θ。计算θ-γv_(t-1)因此给了我们一个近似的下一个位置参数(梯度是完整更新失踪):
再一次,我们设置了动量项γ值约为0.9。而动量首先计算当前梯度(图3中的蓝色小矢量),然后在更新的累积梯度方向上进行一次大的跳跃(蓝色大矢量),NAG首先在之前积累的梯度方向(棕色向量)上做一个大的跳跃,测量梯度,然后做一个修正(绿色向量)。这种预先更新可以防止我们进行得太快,并提高响应能力,从而显著提高了RNNs在许多任务上的性能。
现在,我们能够根据错误函数的斜率调整更新并相应地加快SGD的速度,我们还希望根据每个单独的参数调整更新,根据其重要性执行更大或更小的更新。
Adagrad是一种基于梯度的优化算法,它使学习率与参数相适应,对不频繁的参数执行较大的更新,对频繁的参数执行较小的更新。由于这个原因,它非常适合处理稀疏数据。
为简便起见,我们将g_(t,i)设为目标函数在时间步长t参数θ_i的梯度:
SGD更新每一个参数θ_i在每个时间步t就变成了:
在它的更新规则,Adagrad修改一般学习率η在每个时间步t为每个参数θ_i基于过去为θ_i的梯度计算:
G_t∈R^(d×d)是一个对角矩阵, 每个对角线位置i,i为对应参数θ_i从第1轮到第t轮梯度的平方和,ϵ是一个平滑的术语,避免分母为零(通常的1 e-8)。如果不进行平方根运算,算法的性能会差很多。
现在可以vectorize实现通过执行以元素矩阵向量乘法向量化 G_t和g_t:
Adagrad的主要优点之一是它消除了手动调整学习率的需要。大多数实现使用默认值0.01,并保持不变。
Adagrad的主要缺点是它在分母上积累了梯度的平方: 因为每增加一项都是正的,所以在训练过程中积累的总和会不断增加。这反过来又导致学习率萎缩,并最终变得无穷小,此时算法不再能够获得额外的知识。下面的算法旨在解决这一缺陷。
Adadelta是Adagrad的扩展,它试图降低其侵略性的、单调递减的学习率。Adadelta并没有积累所有过去的平方梯度,而是将积累过去梯度的窗口限制为某个固定大小的w。
没有有效地存储以前的梯度的平方,梯度的和被递归地定义为所有过去的梯度的平方的衰减平均值。运行平均值E〖 [g^2]〗_t 在时间步然后决定(如γ一小部分类似于动量词)只有前面的平均和当前的梯度:
我们γ类似的值设置为动量词,约0.9。为了清晰起见,我们现在重写SGD更新的参数更新向量θ_t:
我们之前推导的Adagrad的参数更新向量就是这样的形式:
现在我们简单地将对角矩阵G t替换为过去平方梯度的衰减平均值E〖 [g^2]〗_t
由于分母只是梯度的均方根误差准则,我们可以用简写的准则来代替:
作者注意到这次更新中的单位(以及SGD、Momentum或Adagrad中的单位)不匹配,即更新的假设单位应该与参数相同。为了实现这一点,他们首先定义了另一个指数衰减的平均值,这次不是梯度的平方,而是参数更新的平方:
参数更新的均方根误差为:
RMS[〖∆θ]〗t是未知的,我们把它近似的RMS参数更新,直到前一个时间步。在前面的更新规则RMS[〖∆θ]〗(t-1)取代了学习率η,最后收益率Adadelta更新规则:
使用Adadelta,我们甚至不需要设置默认的学习率,因为它已经从更新规则中删除了。
RMSprop是Geoff Hinton在Coursera课程第6e讲中提出的一种尚未发表的自适应学习速率方法.
RMSprop和Adadelta都是大约在同一时间独立开发的,它们都是为了解决学习速度急剧下降的Adagrad而开发的。RMSprop实际上与我们在上面推导出的Adadelta的第一个更新向量是相同的:
RMSprop也将学习率除以梯度的指数衰减平均值。Hinton建议γ被设置为0.9,而良好的学习率η的默认值是0.001。
自适应矩估计(Adam)是另一种计算每个参数的自适应学习率的方法。除了像Adadelta和RMSprop那样存储过去梯度的指数衰减平均值v_t, Adam还保存了过去梯度的指数衰减平均值m_t,类似于动量:
m_t和v_t分别是梯度的第一个矩(均值)和第二个矩(无中心方差)的估计,因此得名。m_t和v_t初始化向量(0), Adam的作者观察到它们偏向零,尤其是在初始时间步骤,特别是当衰变速率很小(即β_1和β_2接近1)。
通过计算经第一和第二矩修正的偏差来抵消这些偏差:
然后他们使用这些来更新参数,就像我们在Adadelta和RMSprop中看到的那样,这就产生了Adam更新规则
作者提出对β_1默认值为0.9, β_2 0.999和ϵ为10^(-8). 他们的经验表明,Adam在实践中工作良好,并优于其他自适应学习方法的算法。
最后两张图从直观上展现了算法的优化过程。第一张图为不同算法在损失平面等高线上随时间的变化情况,第二张图为不同算法在鞍点处的行为比较。
3.参考资料
An overview of gradient descent optimization algorithms