我正在研究 TensorFlow 以及如何使用它,即使我不是神经网络和深度学习方面的专家(只是基础知识)。
按照教程,我不了解三个优化器之间的真实和实际差异。我查看了 API 并理解了这些原则,但我的问题是:
1. 什么时候最好用一种代替另一种?
2. 是否有重要的区别需要了解?
以下是根据我的理解做一个简单的解释:
动量有助于 SGD 沿着相关方向导航,并软化不相关的波动。它只是将前一步的方向的一部分添加到当前步骤。这实现了在正确方向上的速度放大并软化了错误方向上的振荡。这个分数通常在 (0, 1) 范围内。使用自适应动量也很有意义。在学习开始时,大动量只会阻碍您的进步,因此使用 0.01 之类的值是有意义的,一旦所有高梯度消失,您就可以使用更大的动量。动量有一个问题:当我们非常接近目标时,大多数情况下我们的动量非常高,它不知道应该放慢速度。这可能会导致它错过或围绕最小值振荡
Nesterov 加速梯度通过提早开始减速克服了这个问题。在动量中,我们首先计算梯度,然后在这个方向上跳跃,这个方向被我们之前拥有的任何动量放大。 NAG 做同样的事情,但顺序不同:首先我们根据我们存储的信息做了一个大跳跃,然后我们计算梯度并做一个小的修正。这种看似无关紧要的变化带来了显着的实际加速。
AdaGrad 或自适应梯度允许学习率根据参数进行调整。它对不频繁的参数执行较大的更新,对频繁的参数执行较小的更新。因此,它非常适合稀疏数据(NLP 或图像识别)。另一个优点是它基本上消除了调整学习率的需要。每个参数都有自己的学习率,由于算法的特殊性,学习率是单调递减的。这导致了最大的问题:在某个时间点,学习率太小以至于系统停止学习。
AdaDelta 解决了 AdaGrad 中学习率单调递减的问题。在 AdaGrad 中,学习率的计算近似为一除以平方根之和。在每个阶段,您在总和中添加另一个平方根,这导致分母不断增加。在 AdaDelta 中,它不是对所有过去的平方根求和,而是使用允许总和减少的滑动窗口。 RMSprop 与 AdaDelta 非常相似
Adam 或自适应动量是一种类似于 AdaDelta 的算法。但除了存储每个参数的学习率之外,它还分别存储每个参数的动量变化。一些可视化:
我会说 SGD、Momentum 和 Nesterov 不如最后 3 个。
Salvador Dali's answer 已经解释了一些流行方法(即优化器)之间的区别,但我会尝试详细说明它们。
(请注意,我们的答案在某些方面存在分歧,尤其是关于 ADAGRAD。)
经典动量 (CM) 与 Nesterov 加速梯度 (NAG)
(主要基于论文 On the importance of initialization and momentum in deep learning 中的第 2 部分。)
CM 和 NAG 中的每个步骤实际上都由两个子步骤组成:
动量子步 - 这只是最后一步的一小部分(通常在 [0.9,1) 范围内)。
与梯度相关的子步骤——这与 SGD 中的通常步骤类似——它是学习率和与梯度相反的向量的乘积,而梯度是从该子步骤开始的位置计算的。
CM 先采用梯度子步,而 NAG 先采用动量子步。
这是来自 an answer about intuition for CM and NAG 的演示:
https://i.stack.imgur.com/pAwIf.png
所以 NAG 似乎更好(至少在图像中),但为什么呢?
需要注意的重要一点是,动量子步骤何时到来并不重要——无论哪种方式都是一样的。因此,如果已经采取了动量子步骤,我们还不如采取行动。
因此,问题实际上是:假设梯度子步是在动量子步之后进行的,我们应该将梯度子步计算为从动量子步之前还是之后的位置开始计算?
“在它之后”似乎是正确的答案,一般来说,某个点 θ
的梯度大致将您指向从 θ
到最小值的方向(具有相对正确的幅度),而其他点的梯度是不太可能将您指向从 θ
到最小值的方向(具有相对正确的幅度)。
这是一个演示(来自下面的 gif):
https://i.stack.imgur.com/T7Ori.png
最小值是星星所在的位置,曲线是等高线。 (关于等高线的解释以及为什么它们垂直于渐变,请参见传奇 3Blue1Brown 的视频 1 和 2。)
(长)紫色箭头是动量子步。
如果它在动量子步骤之前开始,则透明的红色箭头是梯度子步骤。
如果黑色箭头在动量子步骤之后开始,则它是梯度子步骤。
CM 最终会成为暗红色箭头的目标。
NAG 最终会成为黑色箭头的目标。
请注意,为什么 NAG 更好的这个论点与算法是否接近最小值无关。总的来说,NAG 和 CM 都经常存在积蓄多于对它们有利的动量的问题,因此每当它们应该改变方向时,它们都有一个尴尬的“响应时间”。我们解释过的 NAG 优于 CM 的优势并不能避免问题,只是让 NAG 的“响应时间”不那么令人尴尬(但仍然令人尴尬)。
https://i.stack.imgur.com/ihlS2.gif
阿达格拉德
(主要基于 ADADELTA: An Adaptive Learning Rate Method(原始 ADADELTA 论文)中的第 2.2.2 节,因为我发现它比 Adaptive Subgradient Methods for Online Learning and Stochastic Optimization(原始 ADAGRAD 论文)更易于理解。)
在 SGD 中,步长由 - learning_rate * gradient
给出,而 learning_rate
是一个超参数。
ADAGRAD 也有一个 learning_rate
超参数,但梯度每个分量的实际学习率是单独计算的。< br> 第 t
步的第 i
分量由下式给出:
learning_rate
- --------------------------------------- * gradient_i_t
norm((gradient_i_1, ..., gradient_i_t))
尽管:
gradient_i_k 是第 k 步中梯度的第 i 个分量
(gradient_i_1, ..., gradient_i_t) 是具有 t 个分量的向量。这并不直观(至少对我而言)构造这样一个向量是有意义的,但这就是算法所做的(从概念上)。
norm(vector) 是向量的欧氏范数(又名 l2 范数),这是我们对向量长度的直观概念。
令人困惑的是,在 ADAGRAD(以及其他一些方法)中,乘以 gradient_i_t(在本例中为 learning_rate / norm(...))的表达式通常称为“学习率”(实际上,我称之为“实际学习率”在上一段)。我猜这是因为在 SGD 中 learning_rate 超参数和这个表达式是一回事。
在实际实现中,会在分母上添加一些常数,以防止被零除。
例如,如果:
第一步中梯度的第 i 个分量是 1.15
第二步梯度的第i个分量是1.35
第三步梯度的第i个分量为0.9
那么(1.15, 1.35, 0.9)
的范数就是黄线的长度,即:
sqrt(1.15^2 + 1.35^2 + 0.9^2) = 1.989
。
所以第三步的第i
分量是:- learning_rate / 1.989 * 0.9
https://i.stack.imgur.com/pjyp7.png
请注意关于该步骤的第 i
个组件的两件事:
它与 learning_rate 成正比。在它的计算中,范数在增加,因此学习率在降低。
这意味着 ADAGRAD 对超参数 learning_rate
的选择很敏感。
此外,可能是一段时间后步长变得如此之小,ADAGRAD 实际上会卡住。
ADADELTA 和 RMSProp
本文提出的想法源自 ADAGRAD,以改进该方法的两个主要缺点:1)在整个训练过程中学习率不断下降,2)需要手动选择全局学习率。
然后,该论文解释了旨在解决第一个缺点的改进:
我们不是一直累积梯度平方和,而是将累积的过去梯度的窗口限制为某个固定大小 w [...]。这确保了即使在进行了多次更新迭代之后,学习也能继续取得进展。由于存储 w 个先前的平方梯度是低效的,我们的方法将这种累积实现为平方梯度的指数衰减平均值。
通过“平方梯度的指数衰减平均值”,该论文意味着对于每个 i
,我们计算所有已计算梯度的所有平方 i
分量的加权平均值。
每个平方 i
分量大于上一步中平方 i
分量的权重。
这是大小为 w
的窗口的近似值,因为前面步骤中的权重非常小。
(当我想到一个指数衰减的平均值时,我喜欢想象一条 comet's 轨迹,随着它离彗星越来越远,它变得越来越暗:
https://i.stack.imgur.com/UIzkI.png
如果您仅对 ADAGRAD 进行此更改,那么您将获得 RMSProp,这是 Geoff Hinton 在 Lecture 6e of his Coursera Class 中提出的一种方法。
所以在 RMSProp 中,第 t
步的第 i
分量由下式给出:
learning_rate
- ------------------------------------------------ * gradient_i_t
sqrt(exp_decay_avg_of_squared_grads_i + epsilon)
尽管:
epsilon 是一个防止被零除的超参数。
exp_decay_avg_of_squared_grads_i 是计算的所有梯度(包括 gradient_i_t)的第 i 个平方分量的指数衰减平均值。
但如前所述,ADADELTA 还旨在摆脱 learning_rate
超参数,因此其中肯定有更多内容。
在 ADADELTA 中,第 t
步的第 i
分量由下式给出:
sqrt(exp_decay_avg_of_squared_steps_i + epsilon)
- ------------------------------------------------ * gradient_i_t
sqrt(exp_decay_avg_of_squared_grads_i + epsilon)
而 exp_decay_avg_of_squared_steps_i
是计算的所有步骤的平方 i
分量的指数衰减平均值(直到第 t-1
步)。
sqrt(exp_decay_avg_of_squared_steps_i + epsilon)
有点类似于动量,并且根据the paper,它“充当加速项”。 (论文还给出了添加它的另一个原因,但我的答案已经太长了,所以如果你好奇,请查看第 3.2 节。)
亚当
(主要基于原始 Adam 论文 Adam: A Method for Stochastic Optimization。)
Adam 是 Adaptive Moment Estimation 的缩写(有关名称的解释,请参见 this answer)。
第 t
步的第 i
组件由以下公式给出:
learning_rate
- ------------------------------------------------ * exp_decay_avg_of_grads_i
sqrt(exp_decay_avg_of_squared_grads_i) + epsilon
尽管:
exp_decay_avg_of_grads_i 是计算的所有梯度的第 i 个分量的指数衰减平均值(包括 gradient_i_t)。
实际上,exp_decay_avg_of_grads_i 和 exp_decay_avg_of_squared_grads_i 也都被纠正以解释对 0 的偏差(有关更多信息,请参见论文中的第 3 节,以及 stats.stackexchange 中的答案)。
请注意,Adam 使用梯度的第 i
个分量的指数衰减平均值,而大多数 SGD 方法使用当前梯度的第 i
个分量。正如论文 GANs Trained by a Two Time-Scale Update Rule Converge to a Local Nash Equilibrium 中所解释的,这导致 Adam 表现得像“一个带有摩擦的重球”。
有关 Adam 的类动量行为与通常的类动量行为有何不同的更多信息,请参见 this answer。
让我们把它归结为几个简单的问题:
哪个优化器会给我最好的结果/准确性?
没有银弹。一些针对您的任务的优化器可能会比其他优化器工作得更好。没有办法事先说明,你必须尝试一些才能找到最好的。好消息是不同优化器的结果可能会彼此接近。但是,您必须为您选择的任何单个优化器找到最佳超参数。
我现在应该使用哪个优化器?
也许,使用 AdamOptimizer 并针对 learning_rate 0.001 和 0.0001 运行它。如果您想要更好的结果,请尝试以其他学习率运行。或者尝试其他优化器并调整它们的超参数。
很长的故事
选择优化器时需要考虑几个方面:
易于使用(即您可以多快找到适合您的参数);
收敛速度(基本为 SGD 或更快);
内存占用(通常在模型的 0 到 x2 大小之间);
与培训过程的其他部分的关系。
普通 SGD 是可以做到的最低限度:它只是将梯度乘以学习率并将结果添加到权重中。 SGD 有许多美好的品质:它只有 1 个超参数;它不需要任何额外的内存;它对训练的其他部分影响很小。它也有两个缺点:它可能对学习率的选择过于敏感,并且训练可能比其他方法花费更长的时间。
从普通 SGD 的这些缺点中,我们可以看到更复杂的更新规则(优化器)的用途是:我们牺牲了一部分内存来实现更快的训练,并可能简化超参数的选择。
内存开销通常不显着,可以忽略。除非模型非常大,或者你在 GTX760 上训练,或者为 ImageNet 的领导地位而战。动量或 Nesterov 加速梯度等更简单的方法需要 1.0 或更少的模型大小(模型超参数的大小)。二阶方法(Adam,可能需要两倍的内存和计算量。
在收敛速度方面,几乎任何东西都比 SGD 好,其他任何东西都很难比较。一个注意事项可能是 AdamOptimizer 擅长几乎立即开始训练,无需热身。
我认为易于使用是选择优化器时最重要的。不同的优化器有不同数量的超参数,并且对它们有不同的敏感性。我认为亚当是所有现成的最简单的。您通常需要检查 0.001
和 0.0001
之间的 2-4 个 learning_rates 以确定模型是否很好地收敛。为了比较 SGD(和动量),我通常尝试 [0.1, 0.01, ... 10e-5]
。 Adam 还有 2 个很少需要更改的超参数。
优化器与训练的其他部分之间的关系。超参数调整通常涉及同时选择 {learning_rate, weight_decay, batch_size, droupout_rate}
。它们都是相互关联的,每一个都可以看作是模型正则化的一种形式。例如,如果使用 weight_decay 或 L2-norm 并可能选择 AdamWOptimizer
而不是 AdamOptimizer
,则必须密切注意。
不定期副业成功案例分享