如何调试和减少优化失败的情况?
摘要:如果模型遇到优化困难,请务必先解决这些问题,然后再尝试其他方法。诊断和纠正训练失败问题是一个活跃的研究领域。
![比较标准 WideResNet 与 Stride 1x1 WideResNet 的图表。y 轴表示测试错误率;x 轴表示基本学习速率。
随着基本学习速率的提高,标准 WideResNet 的 TestErrorRate 会逐渐下降。相比之下,随着基本学习速率的提高,Stride WideResNet 会出现大幅波动。](https://developers.google.cn/static/machine-learning/guides/deep-learning-tuning-playbook/images/stride_instability.png?authuser=7&hl=uk)
请注意图 4 的以下事项:
- 更改步幅不会在低学习速率下降低性能。
- 高学习速率因不稳定性而无法很好地训练。
- 应用 1000 步的学习速率预热可解决这一特定的不稳定性实例,从而能够以 0.1 的最大学习速率进行稳定训练。
识别不稳定的工作负载
如果学习速率过高,任何工作负载都会不稳定。只有在迫使您使用过小的学习速率时,不稳定才会成为问题。至少有两种类型的训练不稳定性是值得区分的:
- 初始化时或训练初期不稳定。
- 训练过程中突然不稳定。
您可以通过执行以下操作,采用系统方法识别工作负载中的稳定性问题:
- 执行学习速率扫描并找到最佳学习速率 lr*。
- 绘制正好高于 lr* 的学习速率的训练损失曲线。
- 如果学习速率 > lr* 显示损失不稳定(在训练期间损失增加而不是下降),则解决不稳定性问题通常会改善训练效果。
在训练期间记录全损失梯度的 L2 范数,因为离群值可能会导致训练过程中出现虚假的不稳定性。这可以告知裁剪渐变或权重更新的积极程度。
注意:一些模型在早期表现不稳定,随后恢复训练,导致训练速度慢但稳定。由于评估频率不够高,常见的评估时间表可能会漏掉这些问题!
如需检查这一点,您可以使用 lr = 2 * current best
训练一个大约 500 步的缩写运行,但评估每个步骤。
![两个图表:两个图表的 x 轴表示全局步;两个图表的 y 轴表示训练损失。两个图表的转换步长为 (2,2) 和 (1,1)。第一个图显示每 1000 步的评估结果。在第一个图表中,两个转化步长都显示出渐降、且全球步数更多。第二个图显示了前 25 个步骤中的频繁评估。在第二张图中,(2,2) 的转换步长显示在前几个全局步的训练损失中大幅波动,然后逐渐降低到 20 个全局步。(1,1) 的转化步长显示,即使是在第一个全局步骤之后,训练损失也会一直保持较低。](https://developers.google.cn/static/machine-learning/guides/deep-learning-tuning-playbook/images/more_frequent_evals.png?authuser=7&hl=uk)
针对常见不稳定性模式的潜在修复
针对常见的不稳定性模式,请考虑以下可能的解决方法:
- 应用学习速率预热。这最适合解决早期训练不稳定的情况。
- 应用渐变裁剪。这对训练早期和训练期间的不稳定性都很有用,还可以修复一些预热无法实现的错误初始化。
- 试用新的优化器。有时 Adam 可以处理 Momentum 无法解决的不稳定性这是一个积极的研究领域。
- 确保您在模型架构中使用了最佳实践和最佳初始化(示例如下)。如果模型尚未包含残差连接和归一化,请添加这些连接和归一化。
- 归一化为余数之前的最后一项操作。例如:
x + Norm(f(x))
。请注意,Norm(x + f(x))
可能会导致问题。 - 请尝试将残差分支初始化为 0。(请参阅 ReZero 就是您所需的一切:大深度快速收敛)。
- 降低学习速率。这是不得已情况下最后的方法。
学习速率预热
![展示同一实验的两个图表。在第一个图表中,x 轴是全局步,y 轴是训练损失。由于学习速率预热数值较低,训练损失极不稳定。学习速率预热数值越高,训练损失越稳定,](https://developers.google.cn/static/machine-learning/guides/deep-learning-tuning-playbook/images/instability_during_warmup.png?authuser=7&hl=uk)
何时应用学习速率预热
![验证集(y 轴)与基本学习速率(x 轴)上的交叉熵损失的图表。该图表显示了 6 个可行试验,所有这些试验的基本学习速率都相对较低。验证损失会随着基准学习速率的提高而下降,然后在低点开始上升。该图还显示了 4 个不可执行的试验,所有这些试验的基本学习速率都相对较高。](https://developers.google.cn/static/machine-learning/guides/deep-learning-tuning-playbook/images/axis_model_with_instability.png?authuser=7&hl=uk)
![训练集(y 轴)与全局步长(x 轴)上的交叉熵损失图。损失在初始全局步骤中急剧下降。然后,损失急剧增加大约 10,000 步。然后,损失会逐渐减小到 15,000 步左右。](https://developers.google.cn/static/machine-learning/guides/deep-learning-tuning-playbook/images/loss_model_with_instability.png?authuser=7&hl=uk)
图 7a 显示了一个超参数轴图,该图指示模型遇到了优化不稳定性,因为最佳学习速率正好位于不稳定性的边缘。
图 7b 显示了如何通过检查使用比该峰值大 5 倍或 10 倍的学习速率训练的模型的训练损失来核实这一点。如果该曲线图显示损失在稳定下降(例如,在上图中约 10k 的步骤后)突然增加,则模型很可能存在优化不稳定性。
如何应用学习速率预热
![步骤 76619(y 轴)与基本学习速率(x 轴)的验证损失图表。该图比较了在 WMT14 EN-De 上使用 LayerNorm Transformer 的四种不同情况的结果。学习速率预热后,在较低的学习速率下减少了验证损失。](https://developers.google.cn/static/machine-learning/guides/deep-learning-tuning-playbook/images/beneficial_effect_warmup.png?authuser=7&hl=uk)
将 unstable_base_learning_rate
设为模型不稳定时的学习速率(使用前面的过程)。
预热涉及预先设置一个学习速率时间表,该时间表将学习速率从 0 逐渐提升到某个稳定的 base_learning_rate
(比 unstable_base_learning_rate
至少大一个数量级)。默认设置是尝试使用大小为 unstable_base_learning_rate
的 10 倍的 base_learning_rate
。不过请注意,您可以重复为 100x unstable_base_learning_rate
之类的指标运行整个过程。具体时间表如下:
- 通过 weatherup_steps 从 0 上升到 base_learning_rate。
- 以恒定速率训练 post_warmup_steps。
您的目标是找到能够达到远高于 unstable_base_learning_rate
的峰值学习速率的最短 warmup_steps
。因此,对于每个 base_learning_rate
,您需要调整 warmup_steps
和 post_warmup_steps
。通常可以将 post_warmup_steps
设置为 2*warmup_steps
。
预热可以独立于现有的衰减时间表进行调整。warmup_steps
应以几个不同的数量级进行扫描。例如,示例研究可以尝试使用 [10, 1000, 10,000, 100,000]
。最大可行点不应超过 max_train_steps
的 10%。
一旦建立了在 base_learning_rate
处不会造成训练的 warmup_steps
,则应将其应用于基准模型。实际上,请将此时间表附加到现有时间表,并使用上面讨论的最佳检查点选择将此实验与基准进行比较。例如,如果我们最初有 10,000 个 max_train_steps
,然后对 1,000 步执行了 warmup_steps
,则新的训练过程总共应运行 11,000 步。
如果稳定的训练需要长 warmup_steps
(超过 max_train_steps
的 5%),您可能需要增加 max_train_steps
以解决此问题。
在所有工作负载中,并不存在真正的“典型”值。一些模型只需要 100 步,而另一些模型(尤其是转换器)可能需要 4 万步以上。
渐变裁剪
![梯度 l2 范数(y 轴)与全局步长(x 轴)的图表。在早期的全球步骤中,“典型”梯度范数训练非常不稳定。过于激进的裁剪阈值会降低学习速率并减慢训练速度。更好的裁剪阈值(略高于典型的梯度范数)使早期训练变得稳定。](https://developers.google.cn/static/machine-learning/guides/deep-learning-tuning-playbook/images/gradient_clipping.png?authuser=7&hl=uk)
发生较大或离群渐变问题时,渐变裁剪非常有用。渐变裁剪可以解决以下任一问题:
- 早期训练不稳定(早期大梯度范数)
- 训练中期不稳定性(训练期间突然出现梯度峰值)。
有时,较长的预热期可以纠正剪辑无法做到的不稳定性;如需了解详情,请参阅学习速率预热。
🤖? 能否在预热期间进行剪辑?
理想的裁剪阈值刚好高于“典型”梯度范数。
以下示例展示了如何完成渐变裁剪:
- 如果梯度 $\left | g\right |$ 的范数大于梯度裁剪阈值 $\lambda$,则执行 ${g}'= \lambda\times \frac{g}{\left | g\right |}$,其中 ${g}'$ 是新的渐变。
在训练期间记录未裁剪的梯度范数。默认情况下,生成以下内容:
- 梯度范数与步长的曲线图
- 所有步骤汇总的梯度范数直方图
根据梯度范数的第 90 个百分位,选择梯度裁剪阈值。此阈值取决于工作负载,但 90% 是一个不错的起点。如果 90% 不起作用,您可以调整此阈值。
🤖? 如何采用某种自适应策略呢?
如果您尝试进行梯度裁剪,但仍然存在不稳定性问题,则可以再尝试更大难度;也就是说,您可以调小阈值。
极端激进的梯度裁剪(即,超过 50% 的更新被裁剪)实质上是一种降低学习速率的奇怪方式。如果您发现自己使用了过于激进的裁剪,可能应该只降低学习速率。
为什么将学习速率和其他优化参数称为超参数?它们并不是任何先前分布的参数。
术语“超参数”在贝叶斯机器学习中具有确切含义,因此将学习速率和大多数其他可调深度学习参数称为“超参数”可以说是一种对术语的滥用。我们更喜欢使用术语“元参数”来表示深度学习中的学习速率、架构参数以及所有其他可调优的内容。这是因为元参数可以避免因误用“超参数”一词而导致混淆。在讨论贝叶斯优化时,尤其容易造成这种混淆,在贝叶斯优化中,概率响应表面模型有自己的真正的超参数。
遗憾的是,虽然可能令人困惑,但“超参数”一词在深度学习社区中已变得极为常见。因此,本文档的目标受众包括许多可能不了解这种技术的用户,我们选择将这个领域中的一种造成混淆来源,以避免造成另一个混淆。不过,我们在发表研究论文时可能会做出不同的选择,并且我们鼓励其他人在大多数情况下改用“元参数”。
为什么不应通过调整批次大小来直接提高验证集性能?
在不更改训练流水线的任何其他详细信息的情况下更改批次大小通常会影响验证集的性能。但是,如果训练流水线针对每个批次大小独立优化,则两个批次大小之间的验证集性能差异通常会消失。
与批次大小互动最强、因此针对每个批次大小单独调整的最重要超参数是优化器超参数(例如学习速率、动量)和正则化超参数。由于样本方差,批次大小越小,给训练算法带来的噪声就越大。该噪声可能会产生正则化效果。因此,较大的批量大小可能更容易出现过拟合,并且可能需要更强的正则化和/或额外的正则化技术。此外,在更改批次大小时,您可能需要调整训练步数。
一旦考虑了所有这些影响,就没有令人信服的证据表明批次大小会影响可实现的最大验证性能。如需了解详情,请参阅 Shallue 等人,2018 年。
所有常用优化算法的更新规则分别是什么?
本部分将介绍几种常用优化算法的更新规则。
随机梯度下降法 (SGD)
\[\theta_{t+1} = \theta_{t} - \eta_t \nabla \mathcal{l}(\theta_t)\]
其中 $\eta_t$ 是第 $t$ 步的学习速率。
造势
\[v_0 = 0\]
\[v_{t+1} = \gamma v_{t} + \nabla \mathcal{l}(\theta_t)\]
\[\theta_{t+1} = \theta_{t} - \eta_t v_{t+1}\]
其中 $\eta_t$ 是步 $t$ 的学习速率,$\gamma$ 是动量系数。
内斯特罗夫
\[v_0 = 0\]
\[v_{t+1} = \gamma v_{t} + \nabla \mathcal{l}(\theta_t)\]
\[\theta_{t+1} = \theta_{t} - \eta_t ( \gamma v_{t+1} + \nabla \mathcal{l}(\theta_{t}) )\]
其中 $\eta_t$ 是步 $t$ 的学习速率,$\gamma$ 是动量系数。
RMSProp
\[v_0 = 1 \text{, } m_0 = 0\]
\[v_{t+1} = \rho v_{t} + (1 - \rho) \nabla \mathcal{l}(\theta_t)^2\]
\[m_{t+1} = \gamma m_{t} + \frac{\eta_t}{\sqrt{v_{t+1} + \epsilon}}\nabla \mathcal{l}(\theta_t)\]
\[\theta_{t+1} = \theta_{t} - m_{t+1}\]
亚当
\[m_0 = 0 \text{, } v_0 = 0\]
\[m_{t+1} = \beta_1 m_{t} + (1 - \beta_1) \nabla \mathcal{l} (\theta_t)\]
\[v_{t+1} = \beta_2 v_{t} + (1 - \beta_2) \nabla \mathcal{l}(\theta_t)^2\]
\[b_{t+1} = \frac{\sqrt{1 - \beta_2^{t+1}}}{1 - \beta_1^{t+1}}\]
\[\theta_{t+1} = \theta_{t} - \alpha_t \frac{m_{t+1}}{\sqrt{v_{t+1}} + \epsilon} b_{t+1}\]
北美地区
\[m_0 = 0 \text{, } v_0 = 0\]
\[m_{t+1} = \beta_1 m_{t} + (1 - \beta_1) \nabla \mathcal{l} (\theta_t)\]
\[v_{t+1} = \beta_2 v_{t} + (1 - \beta_2) \nabla \mathcal{l} (\theta_t)^2\]
\[b_{t+1} = \frac{\sqrt{1 - \beta_2^{t+1}}}{1 - \beta_1^{t+1}}\]
\[\theta_{t+1} = \theta_{t} - \alpha_t \frac{\beta_1 m_{t+1} + (1 - \beta_1) \nabla \mathcal{l} (\theta_t)}{\sqrt{v_{t+1}} + \epsilon} b_{t+1}\]