勇于学习机器学习:梯度下降和流行优化器的详细探索

原文:towardsdatascience.com/courage-to-learn-ml-a-detailed-exploration-of-gradient-descent-and-popular-optimizers-022ecf97be7d

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/a1d21e838d49efe487676586daf143b8.png

今天我们将使用一个角色扮演游戏作为类比。由 ChatGPT 创建

欢迎回到“勇于学习机器学习”的新篇章。对于那些刚开始这个系列的人来说,这个系列旨在使这些复杂主题易于理解和吸引人,就像导师和学习者之间的轻松对话一样,灵感来源于"《勇于被讨厌》"的写作风格,特别关注机器学习。

在我们之前的讨论中,我们的导师和学习者讨论了一些常见的损失函数以及设计损失函数的三个基本原则。今天,他们将探讨另一个关键概念:梯度下降。

和往常一样,以下是今天我们将探讨的主题列表:

  • 梯度究竟是什么,为什么这个技术被称为“梯度下降”?

  • 为什么传统的梯度下降在深度神经网络(DNNs)中表现不佳,以及有哪些改进?

  • 对各种优化器及其关系的回顾(牛顿法、Adagrad、动量、RMSprop 和 Adam)

  • 根据我的个人经验,选择合适的优化器的实用见解


因此,我们已经设置了损失函数来衡量我们的预测与实际结果之间的差异。为了缩小这个差距,我们调整模型的参数。为什么大多数算法使用梯度下降进行学习和更新过程?

为了回答这个问题,让我们想象一下开发一种独特的更新理论,假设我们对梯度下降不熟悉。我们首先使用损失函数来量化差异,这包括信号(当前模型与潜在模式的偏差)和噪声(如数据不规则性)。接下来的步骤是传达这些数据并利用它来调整各种参数。挑战变成了确定每个参数需要修改的程度。一种基本的方法可能涉及计算每个参数的贡献并按比例更新它。例如,在一个线性模型如 W*x + b = y 中,如果预测值是 50 而实际值是 100,差距是 50。然后我们可以计算 w 和 b 的贡献,调整它们以使预测值与实际值 100 对齐。

然而,出现了两个重大问题:

  1. 计算贡献:当 x = 1 时,有多个 w 和 b 的组合可能产生 100,我们如何决定哪个组合更好?

  2. 复杂模型中的计算需求:更新具有数百万参数的深度神经网络(DNN)可能需要大量计算。我们如何才能高效地管理这一点?

这些困难凸显了问题的复杂性。几乎不可能准确确定每个参数对最终预测的贡献,尤其是在非线性且复杂的模型中。因此,为了根据损失有效地更新模型参数,我们需要一种可以精确指定每个参数调整的方法,而不会造成计算上的负担。

因此,我们与其关注如何将损失分配给每个参数,不如将其视为一种遍历损失表面的策略。目标是找到一组参数,引导我们达到全局最小值——模型能够实现的最近似值。这个过程类似于玩 RPG 游戏,玩家在地图上寻找最低点。这就是梯度下降的基础思想。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/24233281ccc75d54890f3ae4eb6d14f6.png

我们有一套基本动作来引导我们的英雄找到宝藏,宝藏位于地图的最低点。由 ChatGPT 创建

那么,梯度下降究竟是什么?为什么叫梯度下降?

让我们分解一下。损失表面,优化中的核心,由损失函数和模型参数塑造,随着不同参数组合的变化而变化。想象一下 3D 损失表面图:垂直轴代表损失函数的值,其他两个轴是参数。在全局最小值处,我们找到具有最低损失的参数集,这是我们最终的目标,即最小化实际结果与预测之间的差距。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/54fe42462b10bd6740e84683e1446cf9.png

来源:miro.medium.com/v2/resize:fit:1400/format:webp/1*DDjCOEPSHLsU7tff7LmYUQ.png

但我们如何导航到这个全局最小值?这正是梯度发挥作用的地方。它引导我们移动的方向。你可能想知道,为什么计算梯度?理想情况下,我们会看到整个损失表面,然后直接走向最小值。但在现实中,尤其是在复杂模型和众多参数的情况下,我们无法可视化整个景观——它比一个简单的山谷要复杂得多。我们只能看到我们周围的情况,就像在 RPG 游戏中身处雾蒙蒙的景观中。因此,我们使用梯度,它指向最陡的上升方向,然后朝相反方向前进,即最陡的下降方向。通过跟随梯度,我们在损失表面上逐渐下降到全局最小值。这次旅程就是我们所说的梯度下降。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/71ac2b44ceda9355722eac6fd7753ed6.png

雾蒙蒙的景观。由 ChatGPT 创作

梯度下降究竟是如何决定每个参数所需的调整,以及为什么它比我们最初提出的方法更有效?

我们的目标是使用一组特定的参数最小化损失函数,这只能通过调整这些参数来实现。我们通过这些变化间接影响损失函数。

让我们重新审视我们的 RPG 类比。英雄只有基本动作(左右,前后)和有限的可见性,目标是找到一张未绘制的地图上的最低点,以挖掘传说中的武器。我们知道梯度指示移动的方向,但它不仅仅是指南针。它还分解成基本动作。

梯度,是每个参数的偏导数向量,表示在哪个基本方向(左,右,前,后)移动多少。它就像一个神奇的指南,不仅指向山的一侧将引导我们找到传说中的武器,还指导我们具体要转弯和迈出的步伐。

然而,理解梯度实际上是什么至关重要。通常教程建议想象你站在山上四处张望,选择最陡峭的方向下降。但这可能会误导人。梯度不是损失表面的方向,而是该方向在参数维度(在图中,x,y 坐标)上的投影,引导我们在损失函数的最小方向上。这种区别至关重要——梯度不在损失表面上,而是在参数空间内的方向指南。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/da772448c3042db8fa3d14c557177e00.png

向量 v 代表梯度,可以用由我们的参数 x 和 y 确定的坐标形式表示。来源:eli.thegreenplace.net/images/2016/plot-3d-parabola.png

正因如此,大多数可视化使用参数等高线,而不是损失函数来展示梯度下降过程。运动是关于调整参数的,损失函数上的变化只是结果。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/663cc3d3ff33c288e3d1715a1b3c17f8.png

来源:machinelearningmastery.com/wp-content/uploads/2021/07/gradientDescent1.png

梯度是由偏导数构成的。另一方面,偏导数帮助我们理解函数相对于特定参数的变化情况,同时保持其他参数不变。这就是梯度如何量化每个参数对损失函数方向变化的影响力的。

梯度下降法自然且高效地解决了我们最初面临的参数调整难题。它在寻找凸问题的全局最小值和非凸场景的局部最小值方面特别擅长。现代实现得益于并行化和通过 GPU 或 TPU 的加速。像小批量梯度下降和 Adam 这样的变体在不同的环境中优化了其效率。总的来说,梯度下降法稳定,能够处理大量数据集和众多参数,使其成为我们学习目的的优选方案。

在梯度下降公式 𝜃 = 𝜃 – 𝜂⋅∇𝜃𝐽(𝜃) 中,我们使用学习率(𝜂)乘以梯度(∇𝜃𝐽(𝜃))来更新每个参数。为什么学习率是必要的?直接用梯度调整参数不是更快吗?

初看起来,仅使用梯度达到全局最小值似乎很简单。然而,这忽略了梯度的本质。梯度,是损失函数相对于参数的偏导数向量,指示最陡上升方向及其陡峭程度。本质上,它在我们有限视角下引导我们走向最有希望的方向,但仅仅是方向。我们必须决定如何利用这个信息。

学习率,或步长,在这里至关重要。它控制着我们的学习过程的速度。想象一下在我们视频游戏示例中山顶上的角色。游戏指示向左下山是到达宝藏(代表全局最小值)最快的路线。它还告诉你山丘的陡峭程度:向左 5 度,向前 10 度。现在,你决定你的英雄移动多远。如果你小心谨慎,你可能会选择小步,比如说学习率为 0.001。这意味着你的英雄向左移动 0.001_5 = 0.005 个单位,向前移动 0.001_10 = 0.01 个单位。结果,你的英雄朝着目标移动,与梯度的方向一致,但以受控的速度移动,不会超过。

总结来说,不要混淆梯度的幅度与学习速度。幅度表示上升方向的陡峭程度,这取决于损失表面。另一方面,学习率是你做出的选择,独立于数据集。它是一个超参数,表示我们在学习旅程中希望多么谨慎或激进地前进。

如果学习率不依赖于数据集,我们如何确定它?学习率的典型范围是多少,设置得太高或太低会有什么问题?

由于学习率是一个超参数,我们通常通过实验,如交叉验证,或基于以往的经验来选择它。学习率的常见范围在 0.001 到 0.1 之间。这个范围是基于数据科学社区的实证观察,他们发现这个范围内的学习率往往收敛得更快、更有效。从理论上讲,我们更喜欢不超过 0.1 的学习率,因为较大的学习率会在每一步剧烈改变我们的参数,导致超调等风险。在实践方面,我们避免使用低于 0.001 的学习率,因为它们可能会减慢学习过程,使计算变得昂贵且耗时。

常见的范围让我们了解了极端学习率的问题。当学习率过高时,大的步长可能导致算法移动过快,导致超调并永远无法达到目标。相反,非常低的学习率会导致微小的步长,可能需要过量的时间才能达到全局最小值,从而浪费计算资源和时间。

这里有一个视觉表示,有助于理解不同学习率对学习过程的影响:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/bb28073eb1701eb7a538e2f2b305dfbf.png

来源:www.jeremyjordan.me/content/images/2018/02/Screen-Shot-2018-02-24-at-11.47.09-AM.png

纯梯度下降法在应用于 DNN 模型时有哪些局限性?

尽管梯度下降在理论上效果很好,但在实际应用中,尤其是在 DNN 模型中,它面临着重大的挑战。关键限制包括:

  • 纯梯度下降法计算量很大。纯梯度下降公式 𝜃 = 𝜃 – 𝜂⋅∇𝜃𝐽(𝜃) 需要计算整个数据集上的平均损失 𝐽(𝜃)。这意味着将所有预测值与它们的真实标签进行比较,并平均这些差异。对于一个典型的深度神经网络(DNN)模型,它通常涉及数百万个参数和大量数据集,这个过程变得计算量很大。这种复杂性是直到 2012 年 AlexNet 等模型出现之前,深度神经网络(DNN)的实际应用不可行的原因之一,尽管梯度下降是一个更古老的概念。

  • 在深度神经网络中,损失表面通常是非凸的,包含多个局部最小值。在这种情况下,使用梯度下降来寻找 𝐽(𝜃) = 0 的点的简单标准是不够的。在我们的视频游戏类比中,这就像我们的英雄不确定下一步该往哪里移动,因为最陡下降方向变得难以辨认。尤其是高原和鞍点问题,其中 𝐽(𝜃) 为零。接近鞍点和局部最小值区域的地方甚至可能是有害的,因为在那里的 𝐽(𝜃) 非常小,接近零。𝐽(𝜃) 的小值可能会显著减慢学习过程,不必要地消耗时间和计算资源。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/4d3764da716207e5e8219010b504fdf0.png

记住,在雾蒙蒙的地形场景中,我们不知道我们是在高原上,还是在全局最小值或局部最小值上。来源:miro.medium.com/v2/resize:fit:1400/1*vx235JUNzgv0fGzONlNIYg.png

梯度下降为什么有效,为什么学习率必须小?

作者注:我知道数学公式可能会让人感到害怕,所以我曾考虑是否在我的文章中包含这一部分。然而,在探索梯度下降的过程中,我发现自己质疑为什么认为最陡下降方向会引导到全局最小值,以及为什么教程强调设置一个小的学习率以防止过冲。我试图通过 RPG 游戏类比来合理化这些概念,这有所帮助,但并不完全令人满意。最终,梯度下降背后的直接数学证明才最终消除了我的疑虑。如果你有类似的问题,我鼓励你阅读这一部分。这可能会提供你需要的清晰度,以完全掌握这些概念。

要掌握梯度下降,我们需要讨论使用泰勒级数来近似损失函数。泰勒级数是一种非常强大的工具,用于估计复杂函数在特定点的值。它就像试图用更简单、更具体的元素来描述一个复杂的情况。与其用“我发生了车祸”这样的宽泛陈述,不如将其分解成具体的事件:开车带狗去看兽医,狗突然出现在后排座位上,电话响起,然后发生碰撞。泰勒级数做的是类似的事情。它不是试图用一个单一的通用项来描述复杂函数 f(x),而是使用一系列项来描述 f(x) 在 x = a 处的特定值。泰勒级数根据函数在特定点(x = a)的导数将函数分解成多项式项的总和。级数的每一项都会为近似增加更多细节。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/7042ec1f7e601547bc6f023e90e2eb0b.png

要了解泰勒级数以及一阶和二阶导数如何对其展开做出贡献的有趣解释,请查看 3Blue1Brown 的泰勒级数视频。它有效地展示了为什么这些导数通常足以在感兴趣点周围进行良好的近似。

现在,回到我们的目标,即最小化损失函数 𝐽(𝜃),我们可以应用泰勒级数,主要依赖于一阶导数来进行有效的近似。在这种情况下,𝐽(𝜃) 是一个多变量函数,其中 𝜃 是一个向量,代表一组参数变量,而 a 是这些参数的当前值。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/6ee3f78d6dfbfa3acb59b8dcdc49a2c7.png

为了最小化 𝐽(𝜃),我们只能调整 (𝜃 – a) 使其非常小,这意味着我们的下一个 𝜃 值必须非常接近由向量 a 表示的当前位置。这种接近性的必要性是为什么小学习率至关重要的原因。如果 𝜃 与当前参数值 a 有显著偏差,最小化我们的损失函数就会变得具有挑战性。此外,由于梯度 𝐽’(a) 指示一个方向,我们选择 (𝜃 – a) 向相反方向移动。这种方法解释了为什么沿着最速下降方向(与梯度相反)能引导我们走向全局最小值,此时 𝐽(𝜃) = 0。

你特别提到标准梯度下降不适合深度神经网络。为什么?

将标准梯度下降应用于深度神经网络的核心问题在于其损失函数的性质,这些函数通常是非凸的。梯度下降在这些情况下会遇到困难。想象一下在一个复杂的地图上导航,这个地图不仅仅是一个简单的山丘或山谷,而是一个充满了不可预测的高地和洼地的地形。在这样的景观中,梯度下降可能无法引导我们到达全局最小值,甚至可能在参数更新后增加损失函数的值。这部分是因为一阶偏导数提供了有限的信息,显示了损失如何随着一个参数的变化而变化,同时保持其他参数不变。但是,这没有考虑到多个参数之间的相互作用,这在复杂模型中是至关重要的。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/543884bbdff6ae1ce3be46c46286f53d.png

来源:www.researchgate.net/publication/334986617/figure/fig1/AS:789459528335363@1565233227897/Illustration-of-the-non-convex-mean-squared-error-cost-function-of-a-two-dimensional.png

回顾我们之前讨论的泰勒级数概念,我们看到当目标函数或损失函数变得高度复杂时,仅使用一阶导数并不能提供准确的近似。因此,传统的梯度下降在导航复杂、非凸损失函数时效果较差。

重要的是要注意,梯度下降在非凸场景中仍然可以减少损失。它是一种连续优化的通用方法,可以应用于非凸函数,其中它将收敛到一个驻点。然而,这个点可能不是全局最小值,而可能是局部最小值,甚至是一个鞍点,这取决于函数的凸性。

我们如何改进传统的梯度下降法以加速达到全局最小值?

这是一个很好的问题!我们之前的讨论和视频游戏类比揭示了几个改进梯度下降的方法。让我们探索这些增强功能:

使地图更加适合玩家

就像在游戏中导航一个更宽容的地图可以使找到宝藏更容易一样,某些修改可以使梯度下降中达到全局最小值的路径更加平滑。

修改你的地图(损失表面)的最明显方法之一是选择合适的损失函数。例如,在分类问题中,交叉熵通常被使用(或对于二分类,使用对数损失)。在分类任务中选用均方误差(MSE)可能会导致具有多个局部最小值的损失表面,增加学习过程卡在其中一个最小值上的可能性。

其他一些方法包括使用特征选择、正则化、特征缩放和批量归一化等技术。特征选择不仅减少了计算成本,还简化了损失表面,因为损失函数受参数数量的影响。L1/L2 正则化在这个过程中可以帮助:L1 用于特征选择,L2 用于平滑损失表面。特征缩放至关重要,因为不同尺度的特征可能导致步长不均匀,这可能会减慢收敛速度或完全阻止收敛。通过将特征缩放到相似的范围内,我们确保了更均匀的步长,从而促进了更快和更一致的收敛。

与特征缩放类似,批量归一化旨在在层之间归一化输入。这种方法引入了额外的超参数进行调优。批量归一化在层输出成为后续层的输入之前对其进行标准化,通过计算整个批次的输出均值和方差,在批次中的样本之间建立依赖关系。因此,选择合适的批量大小至关重要,因为批量大小为 1 通常对批量归一化无效。论文《批量归一化如何帮助优化?》指出,这项技术将使损失表面更加平滑,同时最小地改变全局最小值的位置。需要注意的是,在预测阶段,批量归一化使用训练阶段计算出的移动平均和方差,而不是从测试数据中计算批次的统计数据。这与训练和测试阶段之间任何数据转换的相同理念。重要的是要注意,在预测阶段,批量归一化使用训练期间计算的移动平均和方差来归一化批次,而不是从测试数据中计算特定的批次统计数据。这种方法与在数据转换阶段防止训练和测试数据之间数据泄露的标准做法相一致。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/15e5e5caabadc0b2bd33aa9a8fb67a8e.png

来源:qph.cf2.quoracdn.net/main-qimg-591ce5575f71110585d9246bf8c2ca0b-pjlq

加快速度。

有句中国谚语,“天下武功无快不破”(没有快的武术是攻不破的)。这个概念也适用于梯度下降。在传统的梯度下降中,每次迭代都使用全部训练数据来计算损失既耗时又消耗资源。然而,我们可以用更少的数据达到类似的效果。其想法是较小样本的平均损失与整个数据集没有显著差异。通过采用类似小批量梯度下降(使用数据子集)或随机梯度下降(SGD,每次选择随机样本)的方法,我们可以显著加快过程。这些方法使得计算和更新更快,在深度神经网络(DNNs)中尤其有效。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/9eb57df755e2474c8972842e03465ae4.png

来源:editor.analyticsvidhya.com/uploads/58182variations_comparison.png

在机器学习的世界里,“SGD”(随机梯度下降)这个术语已经演变成通常指任何使用每个运行的小数据子集的梯度下降变体。这包括原始的 SGD 和迷你批量梯度下降。相反,“批量梯度下降”表示每次梯度下降迭代都使用整个训练数据集的方法。

在关于梯度下降的讨论中,你将遇到一些常见的术语:

Batch Size:这是用于梯度下降一次迭代的观察值(或训练数据点)的数量。

每个 epoch 的迭代次数:这表示在当前批量大小下,完成整个数据集一次所需的梯度下降迭代次数。

Epoch:一个 epoch 代表对整个训练数据集的一次完整遍历。epoch 的数量是模型设计者做出的选择,并且独立于批量大小和迭代次数。

为了说明,考虑一个包含 1000 个观察值的训练数据集。如果你选择批量大小为 10,你需要 1000/10 = 100 次迭代才能覆盖整个数据集一次。如果你将 epoch 计数设置为 5,模型将整个数据集遍历 5 次。这意味着总共将执行 5 * 100 = 500 次梯度下降迭代。

通过收集更多信息来更智能地移动。

在梯度下降中更智能地移动意味着要超越仅仅寻找最陡下降方向。在我们之前关于梯度下降背后的数学的讨论中,我们了解到使用 f(x) 在 x = a 处的第一导数可以提供一个关于 f(x) 的稳固近似。然而,为了增强这个近似,结合额外的导数项是有益的。在我们的视频游戏类比中,这相当于不仅要找到最陡下降方向,还要移动我们的摄像机来全面了解地形。这种方法特别有用,可以帮助我们确定我们是否处于局部/全局最小值(比如在山谷底部),或者最大值(在山顶),或者鞍点(被山丘和山谷所包围)。然而,我们的有限视野意味着我们并不总能区分局部和全局的。

在这个概念的基础上,我们可以应用牛顿法。这种技术计算目标函数或损失函数的一阶和二阶导数。二阶导数创建了 Hessian 矩阵,提供了对损失函数景观的更详细视图。通过一阶和二阶导数的信息,我们得到了对损失函数的更精确近似。与传统梯度下降不同,牛顿法不使用学习率。然而,如带有线搜索的牛顿法等变体包括学习率,增加了可调整性。虽然牛顿法可能看起来比普通梯度下降更有效,但由于其更高的计算需求,在实践中的应用并不常见。关于为什么牛顿法在机器学习中不太常见,你可以参考这里的讨论。

在移动时调整步长。

这种策略可以使我们的旅程更加高效。最简单的方法是在接近全局最小值时减小步长。这在像 SGD 这样的梯度下降变体中尤其相关,其中学习率在每个 epoch(通过学习率计划)中减少。然而,这种方法在所有参数上均匀调整学习率,考虑到损失景观的复杂性,可能并不理想。在视频游戏领域,这类似于调整不同动作的强度以更有效地导航。这就是像Adagrad这样的方法出现的地方,它提供了一种自适应梯度方法。它是通过累积每个参数的平方梯度历史并使用这个累积的平方根来调整学习率来实现的。这种方法就像根据过去的经验在游戏中微调我们的行动,尤其是在发生不寻常更新时。

然而,虽然直观,Adagrad 可能会因为其激进的速率衰减而减慢。这种方法的各种变体试图平衡这一方面。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/90eeecfb7e87f1805f14f95d95695c34.png

有两种方式来理解为什么 Adagrad 使用平方梯度的和。首先,当当前梯度显著大于历史梯度时,它允许更谨慎的学习。如果我们遇到一个在给定时间显著更大的梯度,将其平方值添加到衰减项会显著增加该项,导致学习率更小,更新更谨慎。其次,这种方法近似函数二阶导数的幅度。较大的平方一阶导数之和表明表面更陡峭,表明需要更小的步长。

选择更好的基本动作。

在梯度下降中优化我们的移动,涉及到根据景观来细化我们的方法。在传统的梯度下降中,我们的路径通常像视频游戏中的不确定步骤一样曲折。这可以通过两个参数轮廓的等高线来可视化,显示出更多的垂直移动和较少的水平移动,尽管水平路径可能更有效。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/4c8fa02ba050b1f7b1d7ef9f745bf515.png

特征缩放可能会有所帮助,但在深度神经网络中的复杂表面上,需要更直接的方法。这就是动量梯度下降发挥作用的地方。它能够识别出某些方向上的移动是否适得其反。它不是直接用当前的梯度来更新参数,而是计算过去梯度的指数移动平均。这种‘动量’有助于在一致的方向上加速进步,并抑制在无效方向上的移动。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/c52fd026f83e05e11e9e518c926f9abb.pnghttps://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/fe614556f1d0dd3aab1ff511d985faf7.png

注意这里,与使用平方梯度的 Adagrad 不同,我们直接累积历史梯度。这种方法至关重要,因为它允许正负移动相互抵消。想象一下,这是在特定方向上建立动量,如果我们持续朝相同方向移动,这将加速学习过程。相反,小的累积值表明在该方向上几乎没有进步,这暗示这可能不是通向最小值的最佳移动。

为了增强这种平滑效果并利用过去的移动,我们赋予累积梯度历史更多的权重。这是通过设置动量系数(通常表示为β)的更高值来实现的。β的一个常见选择是 0.9,它在重视历史移动的同时,仍然对新的梯度信息做出响应。这种方法通过优先考虑具有一致进步的方向并抑制不有效帮助达到目标的振荡,确保了更平滑的旅程。

结合这些策略

将 Adagrad 和动量梯度下降的原则结合起来,为增强梯度下降提供了一种创新的方法。这两种方法都依赖于历史梯度,但它们的方法有一个关键的区别。动量梯度下降使用梯度的时间加权移动平均,而不是简单的平均。这里的优势是,通过调整动量系数β,我们可以在历史梯度趋势的影响和当前梯度之间取得平衡。

  • 受此启发,我们可以将类似的逻辑应用于 Adagrad,从而发展出RMSprop(均方根传播)。RMSprop 本质上是一个 Adagrad 的进化版本,它使用历史梯度的指数移动平均而不是简单平均。这种修改使得历史梯度具有更大的权重,减少了异常大的当前梯度的影响。因此,它导致学习率下降得更加温和,解决了 Adagrad 经常面临的学习率缓慢的问题。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/8d7eed826ee85cb3595c022ff2390afb.png

  • 在此基础上进一步思考,为什么不将 Adagrad/RMSprop 的学习率调整与 Momentum 的梯度调整策略相结合呢?这个想法导致了 Adam(自适应矩估计,我记得它是自适应学习率和 Momentum 的结合体)的创造。Adam 本质上通过两种方式使用历史梯度来结合这两种方法:一种用于调整指数移动平均(动量),另一种用于管理历史梯度的规模(RMSprop)。这种双重应用使得 Adam 成为一个高度有效且稳定的优化器。尽管 Adam 引入了两个额外的超参数用于微调,但它仍然是优化器的一个流行选择。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/5ab02480f6ff54fc88552092ce083b8a.png

在有各种优化器可供选择的情况下,如何在实践中选择合适的优化器?

在实践中,选择合适的优化器取决于你的数据和学习目标的具体情况。以下是我观察和经验中的一些一般性指南:

  • 在线学习中的 SGD:在线学习涉及处理连续流入的数据流,这需要频繁地使用新的、小批量数据更新模型。与其它优化器相比,随机梯度下降(SGD)特别适合这种场景,因为它能够高效地使用小批量数据来更频繁地更新模型。此外,SGD 在数据不稳定或经历微小变化的环境中也非常有效。通过使用适当的学习率以避免过冲,SGD 可以快速适应数据中的微妙变化。然而,需要注意的是,虽然 SGD 能够处理非平稳环境,但在捕捉数据模式中的主要变化时可能并不那么有效。

  • Adam 和稀疏数据。当处理具有大量零条目数据时,它被称为稀疏数据。稀疏数据中的挑战在于某些特征可用的信息有限。Adam 优化器在这种情况下特别有效,因为它结合了动量和自适应学习率机制。这种组合使得 Adam 能够为每个参数单独调整学习率。因此,它为数据稀疏导致的表现不足或信息较少的特征提供更频繁的更新,确保了更平衡和有效的学习过程。

  • **不要混合优化器,但明智地一起使用它们。**虽然在学习过程中可以使用多个优化器,但它们不应该在单个学习阶段内同时应用,因为这可能导致模型混淆并复杂化学习路径。相反,有两种战略方法可以有效地利用多个优化器:

  • **在不同阶段切换优化器。**例如,在训练深度神经网络(DNNs)时,你可能会在初始 epoch 开始时使用 Adam,因为它在初始 epoch 中具有快速进展的能力。随后,随着训练的进行,在后续 epoch 中切换到 SGD 可以提供对学习过程更精确的控制,帮助模型收敛到更优的局部最小值。

  • **使用不同的优化器来训练模型的不同部分。**在向现有预训练模型添加新层的情况下,一种细微的方法可能是有益的。对于预训练层,一个稳定且不太激进的优化器是理想的,以保持已学习特征的完整性。相比之下,对于新添加的层,一个更激进且促进快速学习调整的优化器会更合适。这种方法确保模型的每个部分都根据其特定的学习需求接收最合适的优化技术。

等等,为什么我们不能同时使用 Adam 和 SGD?为什么在后期 epoch 中,尽管 Adam 被认为是更先进的,但 SGD 通常更受青睐,用于更精细的优化?

Adam 和 SGD 在管理学习率方面有显著差异,尤其是 Adam 使用自适应学习率,而 SGD 通常使用固定率或计划调整。这种区别使它们成为根本不同的优化器。

Adam 调整学习率的能力并不总是使其“更先进”。在某些情况下,简单更好。SGD 简单的学习率和稳定的方法在后期 epoch 中更有效,Adam 可能会过于激进地降低学习率,导致不稳定,而 SGD 的稳定率可以更可靠地接近更好的局部最小值并增强稳定性。

此外,SGD 的较慢收敛速度可以帮助防止过拟合。其精细和受控的调整允许对训练数据进行更精确的拟合,可能提高对未见数据的泛化能力。SGD 的固定或计划的学习率也使研究人员能够更好地控制模型的学习过程,强调在模型调整的最后阶段对精度和稳定性的偏好,而不是速度。


如果你喜欢这个系列这个系列,请记住,你的互动——点赞、评论和关注——不仅仅是支持;它们是推动这个系列持续进行并激励我继续分享的动力。

本系列的其他文章:


如果你喜欢这篇文章,你可以在LinkedIn上找到我。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值