
优化器是神经网络架构的重要组成部分。在训练过程中,他们在帮助网络学习做出越来越好的预测方面发挥着关键作用。
他们通过找到权重和偏差等模型参数的最佳集合来实现这一点,以便模型可以为他们正在解决的问题产生最佳输出。
大多数神经网络使用的最常见的优化技术是梯度下降。
大多数流行的深度学习库,例如 Pytorch 和 Keras,都具有大量基于梯度下降的内置优化器,例如随机梯度下降 (SGD)、Adadelta、Adagrad、RMSProp、Adam 等等。
为什么有这么多不同的优化算法?我们如何决定选择哪一种?
梯度下降优化回顾
损失曲线
让我们从梯度下降算法工作原理的典型 3D 图开始。

该图显示了具有两个权重参数的网络:
- 水平面有两个轴,分别表示权重 w1 和 w2
- 纵轴表示每个权重组合的损失值
换句话说,曲线的形状显示了神经网络的“损失状况”。它绘制了权重不同值时的损失,同时我们保持输入数据集不变。
蓝线绘制了梯度下降算法在优化过程中的轨迹:
- 它首先为两个权重选择一些随机值并计算损失值
- 在每次迭代中,当它更新权重值时,损失会降低(希望如此),它会沿着曲线移动到较低的点
- 最后,它到达目标,即损失最低的曲线底部
计算梯度
梯度下降算法根据某点的损失曲线的梯度和学习率因子更新权重。

梯度测量的是斜率,等于垂直方向的变化(dL)除以水平方向的变化(dW)。这意味着陡坡的梯度较大,缓坡的梯度较小。

梯度下降的实践
这些损失曲线对于理解梯度下降的概念非常有用。然而,我们应该意识到这是一个理想化的情况,而不是现实的情况:
- 上图显示的是一条平滑的凸形曲线。实际上,该曲线可能非常坎坷。

- 其次,我们不会只有 2 个参数。通常有数千万甚至数亿个参数,这在你的脑海中是无法想象的。
在每次迭代中,梯度下降的工作原理是“查看所有方向以找到可以下降的最佳斜率”。那么当最佳斜率(在那个点)不是最佳方向时会发生什么?
- 如果地貌在一个方向上陡峭倾斜,但最低点却在较缓坡的方向,该怎么办?
- 或者如果周围的地形相当平坦怎么办?
- 或者如果它掉进了一个深沟里,它该如何爬出来?
这是一些给它带来困难的曲线示例,接下来让我们看看。
梯度下降优化的挑战
局部最小值
在典型的损失曲线中,除了全局最小值外,还可能有许多局部最小值。由于梯度下降的设计目的是不断向下,一旦它下降到局部最小值,就很难再爬上斜坡。所以它可能会卡在那里而无法达到全局最小值。

鞍点
另一个关键挑战是“鞍点”的出现。鞍点是指在对应于一个参数的一个方向上,曲线处于局部最小值。另一方面,在对应于另一个参数的第二个方向上,曲线处于局部最大值。

鞍点之所以棘手,是因为鞍点周围的区域通常相当平坦,就像高原一样。这意味着梯度接近于零。这导致优化器在鞍点附近振荡,沿着第一个参数的方向,而不能沿着第二个参数的方向下降。
因此,梯度下降错误地认为它已经找到了最小值。
峡谷
梯度下降法也很难穿越峡谷。峡谷是狭长的山谷,在一个方向(即山谷两侧)坡度陡峭,在第二个方向(即沿着山谷)坡度平缓。这种峡谷通常通向最低点,由于难以穿越,这种形状也称为病态曲率。

想象一下一条狭窄的河谷,从山丘缓缓下降,直到流入湖泊。你想要做的是沿着山谷的方向快速向下游移动。然而,梯度下降很容易沿着山谷的两侧来回反弹,并沿着河流的方向缓慢移动。
尽管优化算法的核心仍然是使用梯度下降,但它们已经在原始梯度下降的基础上开发了一系列改进,以应对这些挑战。
梯度下降的第一个改进——随机梯度下降(SGD)
梯度下降通常意味着“全批量梯度下降”,使用数据集中的所有样本来计算损失和梯度。
相反,小批量随机梯度下降在每次训练迭代中随机选择数据集的子集。这种随机性有助于我们探索损失情况。
前面我们提到过,损失曲线是通过在保持输入数据集不变的情况下改变模型参数而获得的。但是,如果通过在每个小批量中选择不同的数据样本来改变输入,损失值和梯度也会发生变化。换句话说,通过改变输入数据集,你会得到每个小批量略有不同的损失曲线。
因此,即使您在一个小批次中卡在景观中的某个地方,您也可能会在下一个小批次中看到不同的景观,这让您可以继续前进。这可以防止算法卡在景观的特定部分,尤其是在训练的早期阶段。
梯度下降的第二次改进——动量(Momentum)
动态调整更新量
梯度下降法的一个棘手问题是处理陡坡。由于那里的坡度很大,当你真正想缓慢而谨慎地前进时,你可能会迈出一大步。这可能会导致来回反弹,从而减慢训练速度。

理想情况下,您希望动态改变更新的幅度,以便您可以响应周围景观的变化。如果坡度很陡,您需要放慢速度。如果坡度很平缓,您可能希望加快速度。
使用梯度下降,您可以根据梯度和学习率在每一步更新权重。因此,要修改更新的大小,可以做两件事:
- 调整渐变
- 调整学习率
动量 vs. SGD
动量是实现上述前者(即调整梯度)的一种方法。
使用 SGD 时,我们只关注当前梯度,而忽略沿途所有过去的梯度。这意味着,如果损失曲线突然出现异常,你的轨迹可能会偏离轨道。
另一方面,使用动量时,可以让过去的梯度引导整体方向,以便保持正轨。可以利用您之前看到的周围景观的知识,并有助于抑制损失曲线中异常值的影响。
- 第一个问题是,你要追溯到多久以前?追溯得越久远,受异常现象的影响就越小。
- 其次,过去的每一步是否都同样重要?近期发生的事情比远古发生的事情更重要,这很有道理。因此,如果景观的变化不是暂时的异常,而是真正的结构性变化,那么你确实需要对此作出反应,并逐渐改变你的路线。
动量算法使用梯度的指数移动平均值,而不是当前梯度值。
利用动量穿越峡谷
动量可以帮助您解决病态曲率的窄沟问题,其中一个权重参数的梯度非常高,但另一个参数的梯度非常低。

通过使用动量,可以抑制 SGD 发生的之字形振荡。
- 对于第一个陡坡参数,较大的坡度会导致从山谷一侧到另一侧出现“之字形”。然而,在下一步中,这种现象被反方向的“之字形”所抵消。
- 另一方面,对于第二个参数,第一步的小更新会得到第二步小更新的强化,因为它们的方向相同。这是沿着山谷前进的方向。
使用不同公式的动量优化器算法的一些示例包括:
- 带动量的 SGD
- Nestorov 加速梯度
梯度下降的第三次改进——修改学习率(基于梯度)
如上所述,修改参数更新量的第二种方法是通过调整学习率。
到目前为止,我们一直保持学习率在每次迭代中保持不变。其次,梯度更新对所有参数使用相同的学习率。
然而,正如我们所见,不同参数的梯度之间可能存在很大差异。一个参数的斜率可能很陡,而另一个参数的斜率可能很平缓。
我们可以利用这一点来调整学习率以适应每个参数,可以利用过去的梯度(针对每个参数单独计算)来选择该参数的学习率。
有一些优化器算法可以做到这一点,使用的技术略有不同,例如 Adagrad、Adadelta、RMS Prop。
Adagrad 会将过去的梯度平方并将它们相加,并赋予它们相同的权重。RMSProp 也会将过去的梯度平方,但会使用它们的指数移动平均值,因此会更加重视最近的梯度。
现在,通过对梯度求平方,它们都变为正值,即具有相同的方向。这抵消了我们讨论过的动量梯度方向相反的抵消效应。
这意味着,对于具有陡坡度的参数,梯度很大,梯度的平方也很大且始终为正,因此它们会快速累积。为了抑制这种情况,该算法通过将累积的平方梯度除以更大的因子来计算学习率。这使其在陡坡上减速。
类似地,对于较平缓的坡度,累积量较小,因此算法会将累积量的平方除以较小的因子来计算学习率。这可以提高平缓坡度的学习率。
一些优化器算法结合了两种方法——如上所述修改学习率以及使用动量来修改梯度,例如 Adam 及其许多变体 LAMB。
梯度下降的第四个改进——修改学习率(根据你的训练进度)
在上一节中,学习率是根据参数的梯度进行修改的。此外,我们可以根据训练过程的进展来调整学习率。学习率是根据训练时期设置的,与当时模型的参数无关。
这实际上根本不是由优化器完成的。事实上,它是神经网络的一个独立组件,称为调度器。我提到这一点是为了完整性,并展示与我们讨论过的优化技术的关系,但这里不会进一步介绍它们。
结论
我们现在了解了基于梯度下降的优化器所使用的基本技术、使用它们的原因以及它们之间的关系。