如何解决混合精度训练大模型的局限性问题

本文涉及的产品
模型在线服务 PAI-EAS,A10/V100等 500元 1个月
模型训练 PAI-DLC,5000CU*H 3个月
交互式建模 PAI-DSW,每月250计算时 3个月
简介: 混合精度已经成为训练大型深度学习模型的必要条件,但也带来了许多挑战。在这篇文章中,我们将讨论混合精确训练的数值稳定性问题。

混合精度已经成为训练大型深度学习模型的必要条件,但也带来了许多挑战。将模型参数和梯度转换为较低精度数据类型(如FP16)可以加快训练速度,但也会带来数值稳定性的问题。使用进行FP16 训练梯度更容易溢出或不足,导致优化器计算不精确,以及产生累加器超出数据类型范围的等问题。

在这篇文章中,我们将讨论混合精确训练的数值稳定性问题。为了处理数值上的不稳定性,大型训练工作经常会被搁置数天,会导致项目的延期。所以我们可以引入Tensor Collection Hook来监控训练期间的梯度条件,这样可以更好地理解模型的内部状态,更快地识别数值不稳定性。

在早期训练阶段了解模型的内部状态可以判断模型在后期训练中是否容易出现不稳定是非常好的办法,如果能够在训练的头几个小时就能识别出梯度不稳定性,可以帮助我们提升很大的效率。所以本文提供了一系列值得关注的警告,以及数值不稳定性的补救措施。

混合精度训练

随着深度学习继续向更大的基础模型发展。像GPT和T5这样的大型语言模型现在主导着NLP,在CV中对比模型(如CLIP)的泛化效果优于传统的监督模型。特别是CLIP的学习文本嵌入意味着它可以执行超过过去CV模型能力的零样本和少样本推理,训练这些模型都是一个挑战。

这些大型的模型通常涉及深度transformers网络,包括视觉和文本,并且包含数十亿个参数。GPT3有1750亿个参数,CLIP则是在数百tb的图像上进行训练的。模型和数据的大小意味着模型需要在大型GPU集群上进行数周甚至数月的训练。为了加速训练减少所需gpu的数量,模型通常以混合精度进行训练。

混合精确训练将一些训练操作放在FP16中,而不是FP32。在FP16中进行的操作需要更少的内存,并且在现代gpu上可以比FP32的处理速度快8倍。尽管在FP16中训练的大多数模型精度较低,但由于过度的参数化它们没有显示出任何的性能下降。

随着英伟达在Volta架构中引入Tensor Cores,低精度浮点加速训练更加快速。因为深度学习模型有很多参数,任何一个参数的确切值通常都不重要。通过用16位而不是32位来表示数字,可以一次性在Tensor Core寄存器中拟合更多参数,增加每个操作的并行性。

但FP16的训练是存在挑战性的。因为FP16不能表示绝对值大于65,504或小于5.96e-8的数字。深度学习框架例如如PyTorch带有内置工具来处理FP16的限制(梯度缩放和自动混合精度)。但即使进行了这些安全检查,由于参数或梯度超出可用范围而导致大型训练工作失败的情况也很常见。深度学习的一些组件在FP32中发挥得很好,但是例如BN通常需要非常细粒度的调整,在FP16的限制下会导致数值不稳定,或者不能产生足够的精度使模型正确收敛。这意味着模型并不能盲目地转换为FP16。

所以深度学习框架使用自动混合精度(AMP),它通过一个预先定义的FP16训练安全操作列表。AMP只转换模型中被认为安全的部分,同时将需要更高精度的操作保留在FP32中。另外在混合精度训练中模型中通过给一些接近于零梯度(低于FP16的最小范围)的损失乘以一定数值来获得更大的梯度,然后在应用优化器更新模型权重时将按比例向下调整来解决梯度过小的问题,这种方法被称为梯度缩放。

下面是PyTorch中一个典型的AMP训练循环示例。

梯度缩放器scaler会将损失乘以一个可变的量。如果在梯度中观察到nan,则将倍数降低一半,直到nan消失,然后在没有出现nan的情况下,默认每2000步逐渐增加倍数。这样会保持梯度在FP16范围内,同时也防止梯度变为零。

训练不稳定的案例

尽管框架都尽了最大的努力,但PyTorch和TensorFlow中内置的工具都不能阻止在FP16中出现的数值不稳定情况。

在HuggingFace的T5实现中,即使在训练之后模型变体也会产生INF值。在非常深的T5模型中,注意力值会在层上累积,最终达到FP16范围之外,这会导致值无穷大,比如在BN层中出现nan。他们是通过将INF值改为在FP16的最大值解决了这个问题,并且发现这对推断的影响可以忽略不计。

另一个常见问题是ADAM优化器的限制。作为一个小更新,ADAM使用梯度的第一和第二矩的移动平均来适应模型中每个参数的学习率。

这里Beta1 和 Beta2 是每个时刻的移动平均参数,通常分别设置为 .9 和 .999。用 beta 参数除以步数的幂消除了更新中的初始偏差。在更新步骤中,向二阶矩参数添加一个小的 epsilon 以避免被零除产生错误。epsilon 的典型默认值是 1e-8。但 FP16 的最小值为 5.96e-8。这意味着如果二阶矩太小,更新将除以零。所以在 PyTorch 中为了训练不会发散,更新将跳过该步骤的更改。但问题仍然存在尤其是在 Beta2=.999 的情况下,任何小于 5.96e-8 的梯度都可能会在较长时间内停止参数的权重更新,优化器会进入不稳定状态。

ADAM的优点是通过使用这两个矩,可以调整每个参数的学习率。对于较慢的学习参数,可以加快学习速度,而对于快速学习参数,可以减慢学习速度。但如果对多个步骤的梯度计算为零,即使是很小的正值也会导致模型在学习率有时间向下调整之前发散。

另外PyTorch目前还一个问题,在使用混合精度时自动将epsilon更改为1e-7,这可以帮助防止梯度移回正值时发散。但是这样做会带来一个新的问题,当我们知道梯度在相同的范围内时,增加ε会降低了优化器适应学习率的能力。所以盲目的增加epsilon也不能解决由于零梯度而导致训练停滞的情况。

CLIP训练中的梯度缩放

为了进一步证明训练中可能出现的不稳定性,我们在CLIP图像模型上构建了一系列实验。CLIP是一种基于对比学习的模型,它通过视觉转换器和描述这些图像的文本嵌入同时学习图像。对比组件试图在每批数据中将图像匹配回原始描述。由于损失是在批次中计算的,在较大批次上的训练已被证明能提供更好的结果。

CLIP同时训练两个transformers模型,一个类似GPT的语言模型和一个ViT图像模型。两种模型的深度都为梯度增长创造了超越FP16限制的机会。OpenClip(arxiv 2212.07143)实现描述了使用FP16时的训练不稳定性。

Tensor Collection Hook

为了更好地理解训练期间的内部模型状态,我们开发了一个Tensor Collection Hook (TCH)。TCH可以包装一个模型,并定期收集关于权重、梯度、损失、输入、输出和优化器状态的摘要信息。

例如,在这个实验中,我们要找到和记录训练过程中的梯度条件。比如可能想每隔10步从每一层收集梯度范数、最小值、最大值、绝对值、平均值和标准差,并在 TensorBoard 中可视化结果。

然后可以用out_dir作为--logdir输入启动TensorBoard。

实验

为了重现CLIP中的训练不稳定性,用于OpenCLIP训练Laion 50亿图像数据集的一个子集。我们用TCH包装模型,定期保存模型梯度、权重和优化器时刻的状态,这样就可以观察到不稳定发生时模型内部发生了什么。

从vvi - h -14变体开始,OpenCLIP作者描述了在训练期间存在稳定性问题。从预训练的检查点开始,将学习率提高到1-e4,与CLIP训练后半段的学习率相似。在训练进行到300步时,有意连续引入10个难度较大的训练批次。

损失会随着学习率的增加而增加,这是可预期的。当在第300步引入难度较大的情况时,损失会有一个小的,但不是很大的增加。该模型发现难度较大的情况,但没有更新这些步骤中的大部分权重,因为nan出现在梯度中(在第二个图中显示为三角形)。通过这组难度较大的情况后,梯度降为零。

PyTorch梯度缩放

这里发生了什么?为什么梯度是零?问题就出在PyTorch的梯度缩放。梯度缩放是混合精度训练中的一个重要工具。因为在具有数百万或数十亿个参数的模型中,任何一个参数的梯度都很小,并且通常低于FP16的最小范围。

当混合精确训练刚刚提出时,深度学习的科学家发现他们的模型在训练早期通常会按照预期进行训练,但最终会出现分歧。随着训练的进行梯度趋于变小,一些下溢的 FP16 变为零,使训练变得不稳定。

为了解决梯度下溢,早期的技术只是简单地将损失乘以一个固定的量,计算更大的梯度,然后将权重更新调整为相同的固定量(在混合精确训练期间,权重仍然存储在FP32中)。但有时这个固定的量仍然不够。而较新的技术,如PyTorch的梯度缩放,从一个较大的乘数开始,通常是65536。但是由于这可能很高,导致大的梯度会溢出FP16值,所以梯度缩放器监视将溢出的nan梯度。如果观察到nan,则在这一步跳过权重更新将乘数减半,然后继续下一步。这一直持续到在梯度中没有观察到nan。如果在2000步中梯度缩放器没有检测到nan,它将尝试使乘数加倍。

在上面的例子中,梯度缩放器完全按照预期工作。我们向它传递一组比预期损失更大的情况,这会产生更大的梯度导致溢出。但问题是现在的乘数很低,较小的梯度正在下降到零,梯度缩放器不监视零梯度只监视nan。

上面的例子最初看起来可能有些故意的成分,因为我们有意将困难的例子分组。但是经过数天的训练,在大批量的情况下,产生nan的异常情况的概率肯定会增加。所以遇到足够多的nan将梯度推至零的几率是非常大。其实即使不引入困难的样本,也经常会发现在几千个训练步骤后,梯度始终为零。

产生梯度下溢的模型

为了进一步探索问题何时发生,何时不发生,将CLIP与通常在混合精度下训练的较小CV模型YOLOV5进行了比较。在这两种情况下的训练过程中跟踪了每一层中零梯度的频率。

在前9000步的训练中,CLIP中5-20%的层显示梯度下溢,而Yolo中的层仅显示偶尔下溢。CLIP中的下溢率也随着时间的推移而增加,使得训练不太稳定。

使用梯度缩放并不能解决这个问题,因为CLIP范围内的梯度幅度远远大于YOLO范围内的梯度幅度。在CLIP的情况下,当梯度缩放器将较大的梯度移到FP16的最大值附近时,最小的梯度仍然低于最小值。

如何解决解CLIP中的梯度不稳定性

在某些情况下,调整梯度缩放器的参数可以帮助防止下溢。在CLIP的情况下,可以尝试修改以一个更大的乘数开始,并缩短增加间隔。

但是我们发现乘数会立即下降以防止溢出,并迫使小梯度回到零。

改进缩放比例的一种解决方案是使其更适应参数范围。比如论文 Adaptive Loss Scaling for Mixed Precision Training 建议按层而不是整个模型执行损失缩放,这样可以防止下溢。而我们的实验表明需要一种更具适应性的方法。由于 CLIP 层内的梯度仍然覆盖整个 FP16 范围,缩放需要适应每个单独的参数以确保训练稳定性。但是这种详细的缩放需要大量内存会减少了训练的批大小。

较新的硬件提供了更有效的解决方案。比如BFloat16 (BF16) 是另一种 16 位数据类型,它以精度换取更大的范围。FP16 处理 5.96e-8 到 65,504,而BF16 可以处理 1.17e-38 到 3.39e38,与 FP32 的范围相同。但是 BF16 的精度低于 FP16,会导致某些模型不收敛。但对于大型的transformers模型,BF16 并未显示会降低收敛性。

我们运行相同的测试,插入一批困难的观察结果,在 BF16 中,当引入困难的情况时,梯度会出现尖峰,然后返回到常规训练,因为梯度缩放由于范围增加而从未在梯度中观察到 NaN。

对比FP16和BF16的CLIP,我们发现BF16中只有偶尔的梯度下溢。

在PyTorch 1.12及更高版本中,可以通过对AMP的一个小更改来启动BF16。

如果需要更高的精度,可以试试Tensorfloat32 (TF32)数据类型。TF32由英伟达在安培GPU中引入,是一个19位浮点数,增加了BF16的额外范围位,同时保留了FP16的精度。与FP16和BF16不同,它被设计成直接取代FP32,而不是在混合精度下启用。要在PyTorch中启用TF32,在训练开始时添加两行。

这里需要注意的是:在PyTorch 1.11之前,TF32在支持该数据类型的gpu上默认启用。从PyTorch 1.11开始,它必须手动启用。TF32的训练速度比BF16和FP16慢,理论FLOPS只有FP16的一半,但仍然比FP32的训练速度快得多。

如果你用亚马逊的AWS:BF16和TF32在P4d、P4de、G5、Trn1和DL1实例上是可用的。

在问题发生之前解决问题

上面的例子说明了如何识别和修复FP16范围内的限制。但这些问题往往在训练后期才会出现。在训练早期,模型会产生更高的损失并对异常值不太敏感,就像在OpenCLIP训练中发生的那样,在问题出现之前可能需要几天的时间,这回浪费了昂贵的计算时间。

FP16和BF16都有优点和缺点。FP16的限制会导致不稳定和失速训练。但BF16提供的精度较低,收敛性也可能较差。所以我们肯定希望在训练早期识别易受FP16不稳定性影响的模型,这样我们就可以在不稳定性发生之前做出明智的决定。所以再次对比那些表现出和没有表现出后续训练不稳定性的模型,可以发现两个趋势。

在FP16中训练的YOLO模型和在BF16中训练的CLIP模型都显示出梯度下溢率一般小于1%,并且随着时间的推移是稳定的。

在FP16中训练的CLIP模型在训练的前1000步中下溢率为5-10%,并随着时间的推移呈现上升趋势。

所以通过使用TCH来跟踪梯度下溢率,能够在训练的前4-6小时内识别出更高梯度不稳定性的趋势。当观察到这种趋势时可以切换到BF16。

总结

混合精确训练是训练现有大型基础模型的重要组成部分,但需要特别注意数值稳定性。了解模型的内部状态对于诊断模型何时遇到混合精度数据类型的限制非常重要。通过用一个TCH包装模型,可以跟踪参数或梯度是否接近数值极限,并在不稳定发生之前执行训练更改,从而可能减少不成功的训练运行天数。

https://avoid.overfit.cn/post/eb6b99ec76e3464b8f13d70db588b1f6

作者:Ben Snyder

相关实践学习
部署Stable Diffusion玩转AI绘画(GPU云服务器)
本实验通过在ECS上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。
目录
相关文章
|
2月前
|
机器学习/深度学习 自然语言处理
深度学习中的模型压缩技术:精度与效率的平衡
在深度学习领域,模型压缩技术已经成为一项关键技术。它通过减少模型的参数数量和计算量,实现了模型的轻量化和高效化。本文将介绍几种常见的模型压缩方法,包括参数剪枝、量化、知识蒸馏等,并探讨这些方法如何帮助模型在保持精度的同时提高运行效率。我们将分析每种方法的原理、实现步骤以及优缺点,并通过实验结果对比不同方法的性能表现。最后,我们将讨论模型压缩技术在未来可能的发展方向及其应用前景。
55 1
|
3月前
|
机器学习/深度学习 存储 PyTorch
深度学习训练时混合精度的作用
在深度学习训练过程中,混合精度(Mixed Precision)是指同时使用不同的数值精度(如16位浮点数和32位浮点数)来进行计算。
54 2
|
5月前
|
自然语言处理
什么是大模型的局限性?
【7月更文挑战第25天】什么是大模型的局限性?
263 3
|
5月前
LLM用于时序预测真的不行,连推理能力都没用到
【7月更文挑战第15天】LLM在时序预测上的应用遇挫:研究显示,大型语言模型在多个实验中未显优势,甚至被简单注意力层替代时效果不变或更好。预训练知识未能有效利用,处理时序依赖性不足,且在小样本学习中未见提升。[链接:](https://arxiv.org/pdf/2406.16964)**
88 2
|
7月前
|
机器学习/深度学习 自然语言处理 测试技术
SUPRA:无须额外训练,将Transformer变为高效RNN,推理速度倍增
`Transformers`模型因其在多种任务上的优秀性能而广泛采用,但其内存需求和推理成本随词元数量指数增长。为解决这一问题,论文《Linearizing Large Language Models》提出`SUPRA`方法,将预训练的`Transformers`转换为递归神经网络(RNN),实现有效推理并降低训练成本至原来的5%。`SUPRA`通过将注意力机制线性化并用`GroupNorm`替代`softmax`,保持预训练模型的优势。经过微调,转换后的模型在标准语言理解和长上下文任务中保持高性能,展示了在长序列处理方面的潜力,但仍有改进空间。
150 2
|
7月前
|
机器学习/深度学习 人工智能 自然语言处理
2024年5月大语言模型论文推荐:模型优化、缩放到推理、基准测试和增强性能
本文汇总了2024年5月发布的七篇重要大语言模型论文,涉及模型优化、缩放、推理及性能增强。
409 2
|
6月前
|
机器学习/深度学习 数据采集 人工智能
【机器学习】CLIP模型在有限计算资源下的性能探究:从数据、架构到训练策略
【机器学习】CLIP模型在有限计算资源下的性能探究:从数据、架构到训练策略
350 0
|
7月前
|
算法 异构计算
推测解码:在不降低准确性的情况下将LLM推理速度提高2 - 3倍
在本篇文章我们将详细讨论推测解码,这是一种可以将LLM推理速度提高约2 - 3倍而不降低任何准确性的方法。我们还将会介绍推测解码代码实现,并看看它与原始transformer 实现相比到底能快多少。
238 10
|
7月前
|
数据采集
【大模型】大语言模型训练数据中的偏差概念及其可能的影响?
【5月更文挑战第5天】【大模型】大语言模型训练数据中的偏差概念及其可能的影响?
|
7月前
|
机器学习/深度学习
大模型开发: 解释批量归一化以及它在训练深度网络中的好处。
批量归一化(BN)是2015年提出的加速深度学习训练的技术,旨在解决内部协变量偏移、梯度消失/爆炸等问题。BN通过在每层神经网络的小批量数据上计算均值和方差,进行标准化处理,并添加可学习的γ和β参数,保持网络表达能力。这样能加速训练,降低超参数敏感性,对抗过拟合,简化初始化。BN通过稳定中间层输入分布,提升了模型训练效率和性能。
175 3

热门文章

最新文章