TensorFlow 中的梯度下降 vs Adagrad vs Momentum

Posted

技术标签:

【中文标题】TensorFlow 中的梯度下降 vs Adagrad vs Momentum【英文标题】:Gradient Descent vs Adagrad vs Momentum in TensorFlow 【发布时间】:2016-07-09 19:12:06 【问题描述】:

我正在研究 TensorFlow 以及如何使用它,即使我不是神经网络和深度学习方面的专家(只是基础知识)。

按照教程,我不了解三个优化器之间的真实和实际差异。我查看API 并了解其中的原理,但我的问题是:

1.什么时候最好使用一个而不是其他的?

2。是否有重要的区别需要了解?

【问题讨论】:

对于哪个优化器应该在 MNIST 上更好地工作没有理论,因此人们尝试了几种优化器并选择最适合他们的问题的一种。梯度下降通常是最差的,Momentum/AdaGrad 可能比另一个更好/更差,具体取决于数据集 好的,我需要创建一个具有 4 - 5 类识别的图像识别模型。如果我使用 Imagenet 数据集,你有什么建议? AdamOptimizer 似乎在 Imagenet 上运行良好 只是补充已经说过的内容,在选择优化器时还应牢记优化器所需的超参数数量。梯度下降很慢,但你只需要设置学习率。 【参考方案1】:

以下是根据我的理解做一个简单的解释:

动量 helpsSGD 沿着相关方向导航并软化不相关的波动。它只是将前一步的方向的一部分添加到当前步骤。这实现了在正确方向上的速度放大并软化了错误方向上的振荡。这个分数通常在 (0, 1) 范围内。使用自适应动量也很有意义。在学习开始时,大动量只会阻碍您的进步,因此使用 0.01 之类的值是有意义的,一旦所有高梯度消失,您就可以使用更大的动量。动量有一个问题:当我们非常接近目标时,大多数情况下我们的动量非常高,它不知道应该放慢速度。这可能会导致它错过或围绕最小值振荡 nesterov 加速梯度 通过提前开始减速来克服这个问题。在动量中,我们首先计算梯度,然后在这个方向上跳跃,这个方向被我们之前拥有的任何动量放大。 NAG 做同样的事情,但顺序不同:首先我们根据我们存储的信息做了一个大跳跃,然后我们计算梯度并做一个小的修正。这种看似无关紧要的变化带来了显着的实际加速。 AdaGrad 或自适应梯度允许学习率根据参数进行调整。它对不频繁的参数执行较大的更新,对频繁的参数执行较小的更新。因此,它非常适合稀疏数据(NLP 或图像识别)。另一个优点是它基本上消除了调整学习率的需要。每个参数都有自己的学习率,由于算法的特殊性,学习率是单调递减的。这导致了最大的问题:在某个时间点,学习率太小以至于系统停止学习。 AdaDelta resolves AdaGrad 中学习率单调递减的问题。在 AdaGrad 中,学习率的计算近似为一除以平方根之和。在每个阶段,您在总和中添加另一个平方根,这导致分母不断增加。在 AdaDelta 中,它不是对所有过去的平方根求和,而是使用允许总和减少的滑动窗口。 RMSprop 与 AdaDelta 非常相似

Adam 或自适应动量是一种类似于 AdaDelta 的算法。但除了存储每个参数的学习率之外,它还分别存储每个参数的动量变化。

few visualizations:

我会说 SGD、Momentum 和 Nesterov 不如最后 3 个。

【讨论】:

“SGD、Momentum 和 Nesterov 比最后 3 个差”——它们不是,而是。人们使用 SGD+Momentum 进行论文训练是有原因的。 SGD+Momentum 有更高的机会达到平坦的最小值。 @minerals 如果我们要学究气,那么我们也不能使用较慢这个词。因为它在理论上总是有可能找到一个表面和一个起点,任何算法都将在该处表现最好。但实际上这并没有那么有用。 从您提供的关于 AdaDelta 的链接中的 cmets 中:“对于选择哪种算法以及何时选择没有一个明确的结论。根据问题和参数化,它们的表现都不同。[... ] 这里可以得出的一个“可靠”结论是“选择最适合您的问题的方法”——恐怕” 这篇论文 (arxiv.org/abs/1705.08292) 讨论了 SGD 如何经常获得比自适应方法更好的解决方案。在更好的验证损失/准确性(即模型更好地概括)而不是快速的训练时间方面更好 您所说的“亚当或自适应动量”是什么意思?正如this answer 解释的那样,根据最初的 Adam 论文,Adam 是“自适应矩估计”的缩写。【参考方案2】:

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的演示:

所以 NAG 似乎更好(至少在图像中),但为什么呢?

需要注意的重要一点是,动量子步骤何时到来并不重要 - 无论哪种方式都是一样的。因此,如果已经采取了动量子步骤,我们还不如采取行动。

因此,问题实际上是:假设梯度子步在动量子步之后进行,我们是否应该将梯度子步计算为从动量子步之前或之后的位置开始计算?

“在它之后”似乎是正确的答案,通常情况下,某个点的梯度 θ 大致将您指向从 θ 到最小值的方向(具有相对正确的幅度),而在某些点的梯度其他点不太可能将您指向从 θ 到最小值(具有相对正确的幅度)的方向。

这是一个演示(来自下面的 gif):

最小值是星星所在的位置,曲线是contour lines。 (有关等高线及其与渐变垂直的原因的说明,请参见传奇3Blue1Brown 的视频1 和2。) (长)紫色箭头是动量子步。 如果在动量子步骤之前开始,则透明的红色箭头是梯度子步骤。 如果黑色箭头在动量子步骤之后开始,则它是梯度子步骤。 CM 最终会出现在暗红色箭头的目标中。 NAG 最终会出现在黑色箭头的目标中。

请注意,为什么 NAG 更好的这个论点与算法是否接近最小值无关。 总的来说,NAG 和 CM 都经常存在积蓄多于对它们有利的动量的问题,因此每当它们应该改变方向时,它们都有一个尴尬的“响应时间”。我们解释过的 NAG 相对于 CM 的优势并不能避免问题,只是让 NAG 的“响应时间”不那么令人尴尬(但仍然令人尴尬)。

Alec Radford(出现在Salvador Dali's answer)在 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 超参数,但梯度每个分量的实际学习率是单独计算的。t-th 步骤的 i-th 组件由以下公式给出:

              learning_rate 
- --------------------------------------- * gradient_i_t
  norm((gradient_i_1, ..., gradient_i_t))

同时:

gradient_i_kk-th 步骤中梯度的i-th 分量 (gradient_i_1, ..., gradient_i_t) 是一个带有 t 分量的向量。构造这样一个向量并不直观(至少对我而言),但这就是算法所做的(从概念上)。 norm(vector)vector 的 Eucldiean norm(又名 l2 norm),这是我们对 vector 长度的直观概念。 令人困惑的是,在 ADAGRAD(以及其他一些方法)中,乘以 gradient_i_t(在本例中为 learning_rate / norm(...))的表达式通常称为“学习率”(实际上,我称之为“实际学习率”在上一段)。我猜这是因为SGD 中的learning_rate 超参数和这个表达式是一回事。 在实际实现中,会向分母添加一些常数,以防止被零除。

例如如果:

第一步渐变的i-th分量是1.15 第二步中梯度的i-th分量为1.35 第三步渐变的i-th分量为0.9

那么(1.15, 1.35, 0.9)的范数就是黄线的长度,即:sqrt(1.15^2 + 1.35^2 + 0.9^2) = 1.989. 所以第三步的i-th 组件是:- learning_rate / 1.989 * 0.9

请注意有关步骤的i-th 组件的两点:

    learning_rate成正比。 在它的计算中,范数在增加,因此学习率在降低。

这意味着 ADAGRAD 对超参数 learning_rate 的选择很敏感。 此外,可能是一段时间后步数变得如此之小,以至于 ADAGRAD 几乎被卡住了。

ADADELTA 和 RMSProp

来自ADADELTA paper:

本文提出的想法源自 ADAGRAD,以改进两个主要缺点 该方法的:1)学习率的不断衰减 在整个培训过程中,以及 2) 需要手动选择 全局学习率。

该论文随后解释了一项旨在解决第一个缺点的改进:

而不是累积所有梯度的平方和 时间,我们限制了过去累积的梯度窗口 是一些固定大小w [...]。这确保了学习的继续 即使经过多次更新迭代也取得进展 已经完成了。 由于存储w之前的平方梯度效率低下, 我们的方法将这种累积实现为指数 平方梯度的衰减平均值。

通过“平方梯度的指数衰减平均值”,该论文意味着对于每个i,我们计算所有已计算梯度的平方i-th 分量的加权平均值。 每个i-th 平方分量的权重大于上一步中i-th 平方分量的权重。

这是大小为w 的窗口的近似值,因为前面步骤中的权重非常小。

(当我想到一个指数衰减的平均值时,我喜欢将comet's 轨迹可视化,随着它离彗星越来越远,它变得越来越暗:

)

如果您只对 ADAGRAD 进行此更改,那么您将获得 RMSProp,这是 Geoff Hinton 在Lecture 6e of his Coursera Class 中提出的一种方法。

所以在 RMSProp 中,t-th 步骤的 i-th 组件由以下公式给出:

                   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-th 分量的指数衰减平均值。

但如前所述,ADADELTA 还旨在摆脱 learning_rate 超参数,因此其中肯定有更多内容。

在 ADADELTA 中,t-th 步骤的 i-th 组件由以下公式给出:

  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-th 分量的指数衰减平均值(直到t-1-th 步骤)。sqrt(exp_decay_avg_of_squared_steps_i + epsilon) 有点类似于动量,根据the paper,它“充当加速项”。 (论文还给出了添加它的另一个原因,但我的答案已经太长了,所以如果你好奇,请查看第 3.2 节。)

亚当

(主要基于 Adam: A Method for Stochastic Optimization,亚当的原始论文。)

Adam 是 Adaptive Moment Estimation 的缩写(有关名称的说明,请参阅 this answer)。t-th 步骤的 i-th 组件由以下公式给出:

                   learning_rate
- ------------------------------------------------ * exp_decay_avg_of_grads_i
  sqrt(exp_decay_avg_of_squared_grads_i) + epsilon

同时:

exp_decay_avg_of_grads_i 是计算的所有梯度(包括 gradient_i_t)的 i-th 分量的指数衰减平均值。 实际上,exp_decay_avg_of_grads_iexp_decay_avg_of_squared_grads_i 也都已更正以说明对0 的偏见(有关更多信息,请参阅the paper 中的第 3 部分,以及 an answer in stats.stackexchange)。

请注意,Adam 使用梯度的 i-th 分量的指数衰减平均值,而大多数 SGD 方法使用当前梯度的 i-th 分量。这导致 Adam 表现得像“一个有摩擦力的重球”,正如论文 GANs Trained by a Two Time-Scale Update Rule Converge to a Local Nash Equilibrium 中所解释的那样。 有关 Adam 的类动量行为与通常的类动量行为有何不同的更多信息,请参阅 this answer。

【讨论】:

很好的答案!! 被严重低估的答案;值得更多的支持。还要感谢您将人们引向 3Blue1Brown。他是一位美丽的老师、动画师和数学思想家【参考方案3】:

让我们把它归结为几个简单的问题:

哪个优化器会给我最好的结果/准确性?

没有灵丹妙药。一些针对您的任务的优化器可能会比其他优化器工作得更好。没有办法事先说明,你必须尝试一些才能找到最好的。好消息是不同优化器的结果可能会彼此接近。不过,您必须为您选择的任何单个优化器找到最佳超参数。

我现在应该使用哪个优化器?

也许,使用 AdamOptimizer 并针对 learning_rate 0.001 和 0.0001 运行它。如果您想要更好的结果,请尝试以其他学习率运行。或者尝试其他优化器并调整它们的超参数。

说来话长

在选择优化器时需要考虑几个方面:

易于使用(即您可以多快找到适合您的参数); 收敛速度(基本与 SGD 一样或更快); 内存占用(通常在模型的 0 到 x2 大小之间); 与培训过程的其他部分的关系。

Plain SGD 是可以做到的最低限度:它只是将梯度乘以学习率并将结果添加到权重中。 SGD 有许多美好的品质:它只有 1 个超参数;它不需要任何额外的内存;它对训练的其他部分影响很小。它也有两个缺点:它可能对学习率的选择过于敏感,而且训练可能比其他方法花费更长的时间。

从普通 SGD 的这些缺点中,我们可以看到更复杂的更新规则(优化器)的用途:我们牺牲一部分内存来实现更快的训练,并可能简化超参数的选择。

内存开销通常不显着,可以忽略。除非模型非常大,或者你在 GTX760 上训练,或者为 ImageNet 的领导地位而战。动量或 Nesterov 加速梯度等更简单的方法需要 1.0 或更少的模型大小(模型超参数的大小)。二阶方法(Adam,可能需要两倍的内存和计算量。

收敛速度 - 几乎任何东西都比 SGD 好,其他任何东西都难以比较。需要注意的是,AdamOptimizer 擅长几乎立即开始训练,无需热身。

我认为易于使用是选择优化器时最重要的因素。不同的优化器有不同数量的超参数,并且对它们有不同的敏感性。我认为亚当是所有现成的最简单的。您通常需要检查 0.0010.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

【讨论】:

以上是关于TensorFlow 中的梯度下降 vs Adagrad vs Momentum的主要内容,如果未能解决你的问题,请参考以下文章

用TensorFlow来实现梯度下降

用TensorFlow来实现梯度下降

Tensorflow细节-P84-梯度下降与批量梯度下降

如何在tensorflow中实现多元线性随机梯度下降算法?

Tensorflow--梯度下降解决线性回归

梯度下降:SGD vs Momentum vs NAG vs Adagrad vs Adadelta vs RMSprop vs Adam