目录
梯度下降
为了拟合模型,我们需要一个输入/输出对的训练集 $\{x_i, y_i\}$。我们寻求模型的参数 $\phi$,使得 $f[x_i, \phi]$ 能够尽可能接近地将输入 $x_i$ 映射到输出 $y_i$。为此,我们定义了一个损失函数 $L[\phi]$,它返回一个量化此映射中不匹配程度的单一数值。优化算法的目标是找到使损失最小化的参数 $\hat{\phi}$:
\[\hat{\phi} = \underset{\phi}{\operatorname{argmin}} \left[ L[\phi] \right] \quad(1)\]优化算法有许多族,但训练神经网络的标准方法是迭代的。这些算法启发式地初始化参数,然后重复调整它们,使损失减小。
这类方法中最简单的是梯度下降。它从初始参数 $\phi = [\phi_0, \phi_1, \ldots, \phi_N]^T$ 开始,并迭代以下两个步骤:
步骤 1. 计算损失相对于参数的导数:
\[\frac{\partial L}{\partial \phi} = \begin{bmatrix} \frac{\partial L}{\partial \phi_0} \\ \frac{\partial L}{\partial \phi_1} \\ \vdots \\ \frac{\partial L}{\partial \phi_N} \end{bmatrix} \quad(2)\]步骤 2. 根据以下规则更新参数:
\[\phi \leftarrow \phi - \alpha \cdot \frac{\partial L}{\partial \phi} \quad(3)\]其中,正标量 $\alpha$ 决定了变化的大小。
第一步计算损失函数在当前位置的梯度。这决定了损失函数的“上坡”方向。第二步以一个小的距离 $\alpha$ “下坡”移动(因此是负号)。参数 $\alpha$ 可以是固定的(在这种情况下,我们称之为学习率),或者我们可以执行线搜索,尝试几个 $\alpha$ 值以找到最能减小损失的值。
在损失函数的最小值处,曲面必须是平坦的(否则我们可以通过“下坡”进一步改进)。因此,梯度将为零,参数将停止变化。实际上,我们监测梯度的大小,并在其变得太小时终止算法。
线性回归示例
考虑将梯度下降应用于一维线性回归模型。模型 $f[x, \phi]$ 将标量输入 $x$ 映射到标量输出 $y$,并具有参数 $\phi = [\phi_0, \phi_1]^T$,它们表示 $y$ 轴截距和斜率:
\[y = f[x, \phi] = \phi_0 + \phi_1 x \quad(4)\]给定包含 $I$ 个输入/输出对的数据集 $\{x_i, y_i\}$,我们选择最小二乘损失函数:
\[L[\phi] = \sum_{i=1}^{I} \ell_i = \sum_{i=1}^{I} (f[x_i, \phi] - y_i)^2 = \sum_{i=1}^{I} (\phi_0 + \phi_1 x_i - y_i)^2 \quad(5)\]其中,项 $\ell_i = (\phi_0 + \phi_1 x_i - y_i)^2$ 是第 $i$ 个训练示例对损失的单独贡献。
损失函数相对于参数的导数可以分解为各个贡献的导数之和:
\[\frac{\partial L}{\partial \phi} = \frac{\partial}{\partial \phi} \sum_{i=1}^{I} \ell_i = \sum_{i=1}^{I} \frac{\partial \ell_i}{\partial \phi} \quad(6)\]其中这些由下式给出:
\[\frac{\partial \ell_i}{\partial \phi} = \begin{bmatrix} \frac{\partial \ell_i}{\partial \phi_0} \\ \frac{\partial \ell_i}{\partial \phi_1} \end{bmatrix} = \begin{bmatrix} 2(\phi_0 + \phi_1 x_i - y_i) \\ 2x_i(\phi_0 + \phi_1 x_i - y_i) \end{bmatrix} \quad(7)\]图 1 展示了此算法的进展,我们根据公式6和7 迭代计算导数,然后使用公式3 中的规则更新参数。在这种情况下,我们使用了线搜索过程来找到在每次迭代中使损失减少最多的 $\alpha$ 值。
图 1 线性回归模型的梯度下降。a) 包含 $I = 12$ 个输入/输出对 $\{x_i, y_i\}$ 的训练集。b) 展示梯度下降迭代过程的损失函数。我们从点 0 开始,沿着最陡峭的下坡方向移动,直到无法再改进为止,到达点 1。然后重复这个过程。我们在点 1 测量梯度并沿下坡方向移动到点 2,以此类推。c) 这可以更好地通过热力图来可视化,其中亮度代表损失。仅仅经过四次迭代,我们已经非常接近最小值。d) 参数在点 0 的模型(最亮的线)对数据的描述非常糟糕,但每一次后续迭代都改善了拟合。参数在点 4 的模型(最暗的线)已经对训练数据进行了合理的描述。
Gabor 模型示例
线性回归问题的损失函数(图 1c)总是具有一个明确定义的全局最小值。更正式地说,它们是凸的,这意味着每条弦(曲面上两点之间的线段)都位于函数上方并且不与其相交。凸性意味着无论我们在哪里初始化参数,如果我们一直“下坡”行走,我们都必然会达到最小值;训练过程不会失败。
不幸的是,大多数非线性模型的损失函数,包括浅层和深层网络,都是非凸的。由于参数数量众多,可视化神经网络损失函数具有挑战性。因此,我们首先探索一个具有两个参数的更简单的非线性模型,以深入了解非凸损失函数的特性:
\[f[x, \phi] = \sin[\phi_0 + 0.06 \cdot \phi_1 x] \cdot \exp \left[ -\frac{(\phi_0 + 0.06 \cdot \phi_1 x)^2}{32.0} \right] \quad(8)\]这个 Gabor 模型将标量输入 $x$ 映射到标量输出 $y$,由一个正弦分量(产生振荡函数)乘以一个负指数分量(导致振幅随我们远离中心而减小)组成。它有两个参数 $\phi = [\phi_0, \phi_1]^T$,其中 $\phi_0 \in \mathbb{R}$ 确定函数的平均位置,$\phi_1 \in \mathbb{R}^+$ 沿着 $x$ 轴拉伸或压缩它(图 2)。
图 2 Gabor 模型。这个非线性模型将标量输入 x 映射到标量输出 y,其参数为 $\phi = [\phi_0, \phi_1]^T$。它描述了一个正弦函数,该函数的振幅随其中心距离的增加而减小。参数 $\phi_0 \in \mathbb{R}$ 决定了中心的
位置
。当 $\phi_0$ 增加时,函数向左移动。参数 $\phi_1 \in \mathbb{R}^+$ 沿着 x 轴相对于中心挤压函数。当 $\phi_1$ 增加时,函数变窄。a–c) 具有不同参数的模型。(交互式图)
考虑包含 $I$ 个示例的训练集 $\{x_i, y_i\}$(图 3)。$I$ 个训练示例的最小二乘损失函数定义为:
\[L[\phi] = \sum_{i=1}^{I} (f[x_i, \phi] - y_i)^2 \quad(9)\]同样,目标是找到使此损失最小化的参数 $\hat{\phi}$。
图 3 用于拟合 Gabor 模型的训练数据。该训练数据集包含 28 个输入/输出示例 $\{x_i, y_i\}$。这些数据是通过在 $x_i \in [-15, 15]$ 范围内均匀采样,将样本通过参数为 $\phi = [0.0, 16.6]^T$ 的 Gabor 模型,并添加正态分布噪声而创建的。
局部最小值和鞍点
图 4 Gabor 模型的损失函数。a) 损失函数是非凸的,除了全局最小值(灰色圆圈)之外,还存在多个局部最小值(青色圆圈)。它还包含鞍点,这些点的梯度局部为零,但函数在一个方向上增加而在另一个方向上减小。蓝色十字就是一个鞍点的例子;当我们水平向任一方向移动时,函数减小,但当我们垂直移动时,函数增加。b-f) 与不同最小值相关的模型。在每种情况下,都没有能够降低损失的微小变化。面板 (c) 显示了全局最小值,其损失为 0.64。(交互式图)
图 4 描绘了与该数据集相关的 Gabor 模型的损失函数。存在许多局部最小值(青色圆圈)。在这里,梯度为零,如果我们向任何方向移动,损失都会增加,但我们并未处于函数的整体最小值。损失最低的点被称为全局最小值,并由灰色圆圈表示。
如果我们从一个随机位置开始,并使用梯度下降“下坡”,不能保证我们会到达全局最小值并找到最佳参数(图 5a)。算法同样甚至更有可能终止于其中一个局部最小值。此外,无法知道在其他地方是否存在更好的解决方案。
图 5 梯度下降与随机梯度下降的比较。a) 带线搜索的梯度下降。只要梯度下降算法在损失函数的正确“谷底”初始化(例如,点 1 和 3),参数估计将稳定地向全局最小值移动。然而,如果它在这个“谷底”之外初始化(例如,点 2),它将下降到其中一个局部最小值。b) 随机梯度下降在优化过程中增加了噪声,因此有可能从错误的“谷底”(例如,点 2)中逃脱并仍然达到全局最小值。
此外,损失函数包含鞍点(例如,图 4 中的蓝色十字)。在这里,梯度为零,但函数在某些方向上增加,在其他方向上减少。如果当前参数不完全在鞍点,则梯度下降可以通过“下坡”移动来逃脱。然而,鞍点附近的曲面是平坦的,因此很难确定训练是否收敛;如果我们在梯度很小时终止算法,我们可能会错误地停留在鞍点附近。
随机梯度下降
Gabor 模型有两个参数,因此我们可以通过 (i) 穷尽搜索参数空间或 (ii) 从不同位置重复启动梯度下降并选择损失最低的结果来找到全局最小值。然而,神经网络模型可以有数百万个参数,因此这两种方法都不实用。简而言之,使用梯度下降来找到高维损失函数的全局最优值是具有挑战性的。我们可以找到一个最小值,但无法判断这是否是全局最小值,甚至是否是一个好的最小值。
主要问题之一是梯度下降算法的最终目的地完全由起始点决定。随机梯度下降 (SGD) 试图通过在每一步向梯度添加一些噪声来弥补这个问题。解决方案平均仍然“下坡”移动,但在任何给定的迭代中,选择的方向不一定是最陡峭的“下坡”方向。实际上,它可能根本不是“下坡”。SGD 算法有可能暂时“上坡”移动,从而从损失函数的一个“谷底”跳到另一个“谷底”(图 5b)。
批次与周期
引入随机性的机制很简单。在每次迭代中,算法选择训练数据的一个随机子集,并仅根据这些示例计算梯度。这个子集被称为小批量或简称为批次。因此,在迭代 $t$ 时,模型参数 $\phi_t$ 的更新规则是:
\[\phi_{t+1} \leftarrow \phi_t - \alpha \cdot \sum_{i \in B_t} \frac{\partial \ell_i[\phi_t]}{\partial \phi} \quad(10)\]其中 $B_t$ 是包含当前批次中输入/输出对索引的集合,和以前一样,$\ell_i$ 是由于第 $i$ 对造成的损失。项 $\alpha$ 是学习率,它与梯度大小一起,决定了每次迭代移动的距离。学习率在过程开始时选择,不依赖于函数的局部特性。
批次通常从数据集中无放回地抽取。算法遍历训练示例,直到使用了所有数据,此时它再次开始从完整的训练数据集中采样。对整个训练数据集的一次遍历称为一个周期 (epoch)。一个批次可以小到单个示例,也可以大到整个数据集。后一种情况称为全批次梯度下降,它与常规(非随机)梯度下降相同。
对 SGD 的另一种解释是,它在每次迭代中计算不同的损失函数的梯度;损失函数取决于模型和训练数据,因此对于每个随机选择的批次都会有所不同。在这种观点下,SGD 在不断变化的损失函数上执行确定性梯度下降(图 6)。然而,尽管存在这种可变性,但在任何一点的预期损失和预期梯度与梯度下降保持不变。
图 6 批量大小为三的 Gabor 模型的 SGD 替代视图。a) 整个训练数据集的损失函数。 在每次迭代中,会有一个可能的参数变化概率分布(插图显示了样本)。这些变化对应于三种不同的批量元素选择。b) 一个可能批量的损失函数。 SGD 算法在此函数上沿着下坡方向移动,移动距离由学习率和局部梯度大小决定。当前模型(插图中的虚线函数)发生改变,以更好地拟合批量数据(实线函数)。c) 不同的批量会产生不同的损失函数,并导致不同的更新。d) 对于这个批量,算法相对于批量损失函数是下坡移动,但相对于面板 (a) 中的全局损失函数则是上坡移动。这就是 SGD 能够逃离局部最小值的方式。
随机梯度下降的特性
SGD 具有几个吸引人的特性。首先,尽管它向轨迹添加了噪声,但它在每次迭代中仍然改善了对数据子集的拟合。因此,即使更新不是最优的,它们也倾向于合理。其次,因为它无放回地抽取训练示例并遍历数据集,所以训练示例仍然都平等地做出贡献。第三,仅从训练数据的子集计算梯度计算成本更低。第四,它(原则上)可以逃脱局部最小值。第五,它减少了停留在鞍点附近的机会;很可能至少有一些可能的批次在损失函数上的任何点都有显著的梯度。最后,有证据表明 SGD 实际上能找到使神经网络很好地推广到新数据的参数。
SGD 不一定以传统意义上的方式“收敛”。然而,我们希望当我们接近全局最小值时,所有数据点都能被模型很好地描述。因此,无论选择哪个批次,梯度都会很小,并且参数将不会有太大变化。实际上,SGD 通常与学习率调度一起应用。学习率 $\alpha$ 从高值开始,每 $N$ 个周期按一个常数因子减小。其逻辑是,在训练的早期阶段,我们希望算法探索参数空间,从一个“谷底”跳到另一个“谷底”以找到一个合理的区域。在后期阶段,我们大致处于正确的位置,更关注微调参数,因此我们减小 $\alpha$ 以进行更小的更改。
动量
对随机梯度下降的一种常见修改是添加一个动量项。我们用从当前批次计算的梯度与上一步移动方向的加权组合来更新参数:
\[m_{t+1} \leftarrow \beta \cdot m_t + (1 - \beta) \sum_{i \in B_t} \frac{\partial \ell_i[\phi_t]}{\partial \phi } \quad(11)\] \[\phi_{t+1} \leftarrow \phi_t - \alpha \cdot m_{t+1} \quad(12)\]其中 $m_t$ 是动量(驱动迭代 $t$ 的更新),$\beta \in [0, 1)$ 控制梯度随时间平滑的程度,$\alpha$ 是学习率。
动量计算的递归公式意味着梯度步长是所有先前梯度的无限加权和,其中权重随着我们时间回溯而减小。如果所有这些梯度在多次迭代中对齐,则有效学习率会增加,但如果梯度方向反复变化(因为和中的项相互抵消),则会减小。总体效果是轨迹更平滑,并且在“谷底”中的振荡行为减少(图 7)。
图 7 带有动量的随机梯度下降。a) 常规的随机梯度下降朝着最小值方向走的路径非常间接。b) 引入动量项后,当前步骤的变化是前一步的变化和根据当前批量计算的梯度的加权组合。这可以平滑轨迹并提高收敛速度。
Nesterov 加速动量
图 8 Nesterov 加速动量。解决方案沿着虚线到达点 1。传统的动量更新在点 1 测量梯度,沿着这个方向移动一段距离到达点 2,然后加上来自前一次迭代的动量项(即与虚线方向相同),最终到达点 3。Nesterov 动量更新则首先应用动量项(从点 1 移动到点 4),然后测量梯度并应用更新,最终到达点 5。
动量项可以被认为是 SGD 算法下一步将移动到哪里的粗略预测。Nesterov 加速动量(图 8)在此预测点而不是当前点计算梯度:
\[m_{t+1} \leftarrow \beta \cdot m_t + (1 - \beta) \sum_{i \in B_t} \frac{\partial \ell_i[\phi_t - \alpha\beta \cdot m_t]}{\partial \phi} \quad(13)\] \[\phi_{t+1} \leftarrow \phi_t - \alpha \cdot m_{t+1} \quad(14)\]其中现在梯度在 $\phi_t - \alpha\beta \cdot m_t$ 处进行评估。一种思考方式是,梯度项现在只校正了由动量提供的路径。
Adam
固定步长的梯度下降存在一个不理想的特性:它对与大梯度相关的参数进行大调整(我们可能应该更谨慎),而对与小梯度相关的参数进行小调整(我们可能应该进一步探索)。当损失曲面在一个方向上的梯度比另一个方向陡峭得多时,很难选择一个既能(i)在两个方向上都取得良好进展,又能(ii)保持稳定的学习率(图 9a-b)。
图 9 自适应矩估计 (Adam)。a) 这个损失函数在垂直方向变化很快,但在水平方向变化很慢。如果我们使用一个在垂直方向上能取得良好进展的学习率来运行全批量梯度下降,那么算法需要很长时间才能达到最终的水平位置。b) 如果选择的学习率使得算法在水平方向上取得良好进展,那么它会在垂直方向上过冲并变得不稳定。c) 一种直接的方法是在每一步沿每个轴移动固定距离,以便在两个方向上都下坡。这通过标准化梯度幅值并仅保留符号来实现。然而,这通常不会收敛到精确的最小值,而是围绕它来回振荡(这里在最后两点之间)。d) Adam 算法在估计梯度和归一化项中都使用了动量,这创建了一条更平滑的路径。
一种直接的方法是标准化梯度,以便我们在每个方向上移动一个固定距离(由学习率控制)。为此,我们首先测量梯度 $m_{t+1}$ 和逐点平方梯度 $v_{t+1}$:
\[m_{t+1} \leftarrow \frac{\partial L[\phi_t]}{\partial \phi} \quad(15)\] \[v_{t+1} \leftarrow \left(\frac{\partial L[\phi_t]}{\partial \phi}\right)^2 \quad(16)\]然后应用更新规则:
\[\phi_{t+1} \leftarrow \phi_t - \alpha \cdot \frac{m_{t+1}}{\sqrt{v_{t+1}} + \epsilon} \quad(17)\]其中平方根和除法都是逐点进行的,$\alpha$ 是学习率,$\epsilon$ 是一个小的常数,用于防止梯度幅度为零时出现除以零的情况。项 $v_{t+1}$ 是平方梯度,其正根用于标准化梯度本身,因此只剩下每个坐标方向的符号。结果是算法沿每个坐标移动固定距离 $\alpha$,方向由“下坡”方向决定(图 9c)。这种简单的算法在两个方向上都取得了良好的进展,但除非它恰好精确地落在最小值处,否则不会收敛。相反,它会在最小值附近来回震荡。
自适应矩估计 (Adam) 采用了这个想法,并为梯度的估计和平方梯度都添加了动量:
\[m_{t+1} \leftarrow \beta \cdot m_t + (1 - \beta) \frac{\partial L[\phi_t]}{\partial \phi} \quad(18)\] \[v_{t+1} \leftarrow \gamma \cdot v_t + (1 - \gamma) \left(\frac{\partial L[\phi_t]}{\partial \phi}\right)^2 \quad(19)\]其中 $\beta$ 和 $\gamma$ 是这两个统计量的动量系数。
使用动量等同于对每个统计量的历史进行加权平均。在过程开始时,所有先前的测量值都有效地为零,导致不切实际的小估计。因此,我们使用以下规则修改这些统计量:
\[\tilde{m}_{t+1} \leftarrow \frac{m_{t+1}}{1 - \beta^{t+1}} \quad(20)\] \[\tilde{v}_{t+1} \leftarrow \frac{v_{t+1}}{1 - \gamma^{t+1}} \quad(21)\]由于 $\beta$ 和 $\gamma$ 在 $[0, 1)$ 范围内,指数为 $t+1$ 的项会随着时间步的增加而变小,分母会更接近于一,这种修改的效果会逐渐减弱。
最后,我们像以前一样更新参数,但使用修改后的项:
\[\phi_{t+1} \leftarrow \phi_t - \alpha \cdot \frac{\tilde{m}_{t+1}}{\sqrt{\tilde{v}_{t+1}} + \epsilon} \quad(22)\]结果是一种能够收敛到整体最小值并在参数空间的每个方向上都取得良好进展的算法。请注意,Adam 通常在随机设置中使用,其中梯度及其平方是从小批量计算的:
\[m_{t+1} \leftarrow \beta \cdot m_t + (1 - \beta) \sum_{i \in B_t} \frac{\partial \ell_i[\phi_t]}{\partial \phi} \quad(23)\] \[v_{t+1} \leftarrow \gamma \cdot v_t + (1 - \gamma) \left(\sum_{i \in B_t} \frac{\partial \ell_i[\phi_t]}{\partial \phi}\right)^2 \quad(24)\]因此,在实践中,轨迹是带噪声的。
正如我们将在第 7 章中看到的那样,神经网络参数的梯度幅度可能取决于它们在网络中的深度。Adam 有助于补偿这种趋势,并平衡不同层之间的变化。实际上,Adam 还具有对初始学习率不那么敏感的优点,因为它避免了图 9a-b 中的情况,因此不需要复杂的学习率调度。
AdamW
Adam (Adaptive Moment Estimation) 和 AdamW (Adam with Weight Decay Decoupling) 都是流行的自适应学习率优化器,但它们在处理 L2 正则化 (L2 Regularization),也就是权重衰减 (Weight Decay) 的方式上存在一个关键的区别。
理解 L2 正则化和权重衰减
在深入 Adam 和 AdamW 的区别之前,我们先来回顾一下 L2 正则化和权重衰减:
- 目的: 这两种技术都是为了防止模型过拟合 (overfitting)。它们通过惩罚模型中的大权重,鼓励模型学习更简单、泛化能力更好的参数。
- 传统 SGD 中的等价性: 在标准的随机梯度下降 (SGD) 中,L2 正则化和权重衰减在数学上是等价的。
- L2 正则化: 将一个惩罚项 $\frac{1}{2}\lambda \vert \vert \theta \vert \vert^2_2$(其中 $\lambda$ 是正则化系数,$\theta$ 是模型权重)添加到损失函数中。计算梯度时,这个惩罚项会产生一个梯度 $\lambda \theta$,从而在更新时将权重拉向零。
- 权重衰减: 直接在权重更新步骤中,将权重乘以一个小于 1 的因子,或者减去一个与权重成比例的值。例如,$\theta_{t+1} = \theta_t - \eta \cdot \nabla L(\theta_t) - \eta \cdot \lambda \theta_t$,其中 $\eta$ 是学习率。
在传统 SGD 中,因为学习率是固定的,所以这两种方式殊途同归,都会使得权重在每次更新时都有一个趋向于零的趋势。
Adam 和 AdamW 的区别
核心区别:Adam 将权重衰减与梯度更新耦合在一起,而 AdamW 将其解耦。
1. Adam (原始版本)
- 权重衰减的实现方式: 在原始的 Adam 算法中,L2 正则化通常是通过在损失函数中添加 L2 惩罚项来实现的。
- 这意味着,当计算梯度时,权重衰减的效应(即 $\lambda \theta$)会被加到原始梯度中,然后这个“被修改的梯度”再用于 Adam 的自适应学习率更新规则。
- 存在的问题:
- 与自适应学习率的冲突: Adam 算法为每个参数维护了自适应学习率,这意味着不同的参数会有不同的有效学习率。当 L2 惩罚项的梯度($\lambda \theta$)被直接添加到这些自适应梯度中时,它们也受到了这种自适应缩放的影响。
- 这导致了权重衰减的强度不再是统一的,对于那些更新频率高(导致自适应学习率小)的参数,权重衰减的效果可能会被削弱,而对于那些更新频率低(导致自适应学习率大)的参数,权重衰减的效果可能被放大。
- 结果是,L2 正则化的效果不稳定且不一致,可能导致泛化性能下降。
2. AdamW (Decoupled Weight Decay Regularization)
- 权重衰减的实现方式: AdamW (由 Loshchilov & Hutter 在 2017 年提出) 的主要创新是解耦 (decoupled) 了权重衰减。
- 它不再将 L2 惩罚项的梯度添加到损失函数中。
- 相反,权重衰减作为一个独立的步骤,在 Adam 的自适应更新完成后,直接应用于权重本身。
- 具体来说,更新规则大致变为:
- 先用标准的 Adam 更新规则计算出权重的新值(不含权重衰减)。
- 然后,从这个新值中直接减去一个与权重自身成比例的量:$\theta_{t+1} = \theta_t - \eta \cdot \text{Adam_Update_Term} - \eta \cdot \lambda \theta_t$。
- 解决了什么问题:
- 统一的权重衰减: 通过将权重衰减与自适应梯度更新解耦,确保了权重衰减的强度对所有参数来说是统一且可控的,不再受到各参数自适应学习率的影响。
- 更好的泛化性能: 这种更“纯粹”的权重衰减方式被证明能带来更好的模型泛化能力,尤其是在训练大型深度神经网络时。
- 与 SGD 的一致性: AdamW 的权重衰减行为与 SGD 中的权重衰减行为更加一致。
总结比较
特性 | Adam (L2正则化耦合) | AdamW (权重衰减解耦) |
---|---|---|
权重衰减处理 | 将 L2 惩罚项加到损失函数中,影响梯度计算。 | 将权重衰减作为独立步骤,直接作用于权重更新后。 |
权重衰减效果 | 效果不一致,受自适应学习率影响,可能削弱或放大。 | 效果更统一、可控,独立于自适应学习率。 |
泛化性能 | 某些情况下可能不如 SGD 或 AdamW。 | 通常能达到更好的泛化性能,与 SGD 具有竞争力。 |
理论基础 | 原始设计未充分考虑自适应学习率与 L2正则化的交互。 | 修正了原始 Adam 在 L2正则化处理上的缺陷。 |
推荐使用 | 对于简单的模型或快速原型验证仍可用。 | 推荐用于大多数深度学习任务,尤其是有 L2 正则化需求时。 |
在现代深度学习实践中,AdamW 通常是带有权重衰减需求时的首选,因为它在泛化性能和训练稳定性方面都有显著改进。许多流行的深度学习框架(如 PyTorch)已经默认在其优化器实现中包含了 AdamW,或者强烈推荐使用它来替代带有 L2 正则化的 Adam。
Pytorch的实现比较
对比可以发现,它们的区别就是。Adam计算梯度时直接把L2损失放到梯度里:
\[g_t \leftarrow g_t + \lambda \theta_{t-1}\]而AdamW则是直接用$\lambda \theta_{t-1}$更新参数$\theta_t$,从而不影响累积统计量。
\[\theta_t \leftarrow \theta_{t-1} - \gamma \lambda \theta_{t-1}\]SGD和Adam的比较
关于 SGD 和 Adam 相对优劣的讨论一直很活跃。Wilson 等人 (2017) 提供了证据,表明带有动量的 SGD 可以找到比 Adam 更低的最小值,并且在各种深度学习任务上泛化能力更好。然而,这很奇怪,因为一旦修正项(公式 6.16)变为 1(这发生得很快),SGD 就是 Adam 的一个特例(当 $\beta=0, \gamma=1$ 时)。因此,更有可能的情况是,当我们使用 Adam 的默认超参数时,SGD 的表现优于 Adam。Loshchilov 和 Hutter (2019) 提出了 AdamW,它在存在 L2 正则化的情况下显著改善了 Adam 的性能(参见第 9.1 节)。Choi 等人 (2019) 提供的证据表明,如果我们寻找最佳的 Adam 超参数,它的表现与 SGD 一样好,并且收敛速度更快。Keskar 和 Socher (2017) 提出了一种名为 SWATS 的方法,该方法开始时使用 Adam(以实现快速初始进展),然后切换到 SGD(以获得更好的最终泛化性能)。
- “关于 SGD 和 Adam 相对优劣的讨论一直很活跃。”
- 这是背景。在深度学习实践中,选择合适的优化器非常关键。Adam 及其变体一度成为主流,因为它通常更容易上手,收敛速度快。但 SGD 及其变体(尤其是带动量的 SGD)也一直被认为是实现最佳性能和泛化能力的关键。
- “Wilson 等人 (2017) 提供了证据,表明带有动量的 SGD 可以找到比 Adam 更低的最小值,并且在各种深度学习任务上泛化能力更好。”
- 这是争论的起始点之一。Wilson 等人的论文(”The Marginal Value of Adaptive Gradient Methods in Deep Learning”)在当时引起了广泛关注,因为它挑战了 Adam 总是最优选择的普遍看法。他们指出,虽然 Adam 可能收敛更快,但 SGD 在训练结束时能够达到更低的损失值,并且在测试集上的表现(即泛化能力)更好。
- “找到更低的最小值”:在损失函数曲面上,SGD 似乎能找到更平坦、更宽的局部最小值区域,而 Adam 倾向于找到更尖锐、更深的局部最小值。
- “泛化能力更好”:通常认为,更宽更平坦的最小值区域对模型泛化更有利,因为它对参数的微小扰动更不敏感。
- “然而,这很奇怪,因为一旦修正项(公式 6.16)变为 1(这发生得很快),SGD 就是 Adam 的一个特例(当 $\beta=0, \gamma=1$ 时)。”
- 这指出了一个理论上的矛盾。Adam 的公式中包含动量项($\beta$)和平方梯度项($\gamma$)。如果将 $\beta$ 设为 0(没有一阶动量),$\gamma$ 设为 1(没有二阶动量,即只保留原始梯度平方),并且 Adam 的初始化偏差修正项(公式 6.16,用于校正训练初期的统计偏差)在训练早期迅速趋近于 1,那么 Adam 的更新规则就退化成了带有动量的 SGD。
- 核心疑问: 如果 SGD 是 Adam 的一个特例,为什么 SGD 还能表现得更好呢?这似乎不合逻辑。
- “因此,更有可能的情况是,当我们使用 Adam 的默认超参数时,SGD 的表现优于 Adam。”
- 这是对上述矛盾的一种解释。Wilson 等人观察到的现象可能不是 Adam 本身固有的缺陷,而是因为 Adam 的默认超参数(尤其是学习率和 $\beta_1, \beta_2$)在某些任务上不是最优的。如果花费时间对 Adam 的超参数进行精细调优,它可能也能达到甚至超越 SGD 的表现。这个观点暗示了 Adam 对超参数选择的敏感性。
- “Loshchilov 和 Hutter (2019) 提出了 AdamW,它在存在 L2 正则化的情况下显著改善了 Adam 的性能(参见第 9.1 节)。”
- 这是对 Adam 改进的一个重要贡献。原始的 Adam 算法在 L2 正则化(或权重衰减)的处理上存在一些理论上的问题,因为它将权重衰减项与自适应学习率混淆在一起。AdamW 修正了这个问题,将权重衰减从自适应梯度更新中解耦出来,使其效果更加稳定和有效,从而提高了 Adam 的泛化能力。这间接支持了 Adam 在正确设置下的潜力。
- “Choi 等人 (2019) 提供的证据表明,如果我们寻找最佳的 Adam 超参数,它的表现与 SGD 一样好,并且收敛速度更快。”
- 这进一步强化了“Adam 表现不佳可能源于默认超参数”的观点。他们的研究表明,通过适当的超参数搜索,Adam 能够达到与精心调优的 SGD 相同的最终性能,并且在训练速度上具有优势。这强调了超参数调优对于 Adam 的重要性。
- “Keskar 和 Socher (2017) 提出了一种名为 SWATS 的方法,该方法开始时使用 Adam(以实现快速初始进展),然后切换到 SGD(以获得更好的最终泛化性能)。”
- 这是对两者优点的结合。SWATS (Switching from Adam to SGD) 策略利用了 Adam 在训练初期的快速收敛能力,以及 SGD 在后期可能找到更好泛化解的潜力。这种混合策略试图“鱼和熊掌兼得”,先快速抵达一个不错的区域,然后精细化优化以获得更好的最终模型。
总结来说:
- SGD 和 Adam 各有优缺点: SGD 可能找到更好的泛化解,而 Adam 通常收敛更快。
- 超参数的重要性: Adam 默认超参数可能不是最优的,通过调优可以显著提升其性能。
- AdamW 等改进: 针对 Adam 固有问题(如 L2 正则化处理)的改进可以提升其性能。
- 混合策略: 结合 Adam 和 SGD 优势的策略(如 SWATS)也是一种有效的方法。
Adam(AdamW)的优点是收敛更快,这个在LLM时代非常重要。但是我个人觉得有点时候也不用滥用Adam(AdamW),比如微调的时候训练数据通常较少,我们可以用SGD来找到更好的解,而且SGD比AdamW使用的显存要小很多,这对于很多没有太多计算资源的团队来说也非常友好。
学习率预热 (learning rate warm-up)
自适应训练算法的一个潜在问题是学习率是基于观察到的梯度的累积统计量。在训练开始时,当样本很少时,这些统计量可能非常嘈杂。这可以通过学习率预热 (learning rate warm-up) 来解决,其中学习率在前几千次迭代中逐渐增加。这样刚开始统计量不准,我们让学习率小一点,这样累积统计量也较小。等到后面变准了,我们再把学习率恢复到正常的大小。它的效果为:
-
稳定训练初期: 在数据统计不准确的初期,使用小学习率可以防止模型参数剧烈震荡或发散,帮助模型找到一个相对稳定的起始点。
-
累积准确统计: 在小学习率阶段,模型有足够的时间去观察更多的梯度样本,从而累积更准确的梯度一阶和二阶矩统计数据。
-
平稳过渡: 当统计数据变得更可靠时,学习率也逐渐提高到正常水平,使模型能够更快地收敛。
- 显示Disqus评论(需要科学上网)