梯度累积的隐藏陷阱:Transformer库中梯度累积机制的缺陷与修正

本文涉及的产品
实时计算 Flink 版,5000CU*H 3个月
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
实时数仓Hologres,5000CU*H 100GB 3个月
简介: 在本地微调大规模语言模型时,由于GPU显存限制,通常采用梯度累积技术来模拟大批次训练。然而,实际研究表明,梯度累积方法在主流深度学习框架中会导致模型性能显著下降,尤其是在多GPU环境中。本文详细探讨了梯度累积的基本原理、应用场景及存在的问题,并通过实验验证了修正方案的有效性。研究指出,该问题可能在过去多年中一直存在且未被发现,影响了模型的训练效果。

在本地环境下对大规模语言模型(LLMs)进行微调时,由于GPU显存限制,采用大批量训练通常难以实现。为解决此问题,一般普遍会采用梯度累积技术来模拟较大的批量规模。该方法不同于传统的每批次更新模型权重的方式,而是通过在多个小批量上累积梯度,在达到预设的累积次数后才执行权重更新。这种方法有效地实现了大批量训练的效果,同时避免了常见的内存开销问题。

理论上设置批量大小为1并在32个批次上累积梯度,其效果应等同于直接使用批量大小32进行训练。但是实际研究发现,在使用主流深度学习框架(如Transformers)时,梯度累积方法往往导致模型性能显著低于直接使用大批量训练的结果。

这一问题在reddit上引起了广泛讨论,并且Unsloth AI的Daniel Han成功复现了该问题。他发现这一问题不仅影响单机梯度累积,还影响多GPU训练环境。在多GPU配置中,由于梯度在多设备间隐式累积,会导致模型训练效果不达预期。并且这个问题可能在过去多年的模型训练中一直存在且未被发现。

本文将从以下几个方面展开讨论:首先阐述梯度累积的基本原理,通过实例说明问题的具体表现和错误累积过程;其次分析不同训练场景下该问题的影响程度;最后评估Unsloth提出并已被Hugging Face在Transformers框架中实现的修正方案的有效性。

梯度累积技术详解

神经网络训练过程分析

神经网络的训练过程包含以下关键步骤:通过前向传播生成预测结果,计算预测值与真实值之间的损失,然后通过反向传播计算梯度以优化模型权重。在标准训练流程中,每个批次的梯度计算完成后都会立即用于更新模型权重。

采用较大的批量规模通常能提供更稳定的训练过程,并有助于提升模型性能和泛化能力。但是,大批量训练需要较大的内存空间,特别是在梯度计算和存储方面。在硬件资源受限的情况下,可能无法一次性将大批量数据加载到内存中,这就限制了实际可用的批量大小。

梯度累积的实现机制

梯度累积技术通过将大批量数据分解为多个小批量来实现大规模批量训练。不同于传统方法在每个小批量后更新模型权重,该技术在多个小批量上累积梯度,仅在完成预定的累积步骤后执行一次权重更新。具体实现机制如下:

  1. 首先确定目标有效批量大小和硬件可承载的小批量大小。若目标有效批量大小为64,而硬件每次仅能处理16个样本,则需要在4个规模为16的小批量上进行梯度累积。
  2. 训练过程中,对每个小批量执行前向传播、损失计算和反向传播操作,计算得到梯度。此时不直接更新权重,而是将梯度存入累积缓冲区。
  3. 当处理的小批量数达到预设阈值(如上例中的4个小批量)后,对累积的梯度进行平均,用该平均梯度更新模型权重。随后清空累积缓冲区,进入下一轮累积循环。

梯度累积的应用场景

当前主流的大规模语言模型和视觉语言模型往往规模庞大,其参数量通常超出单个GPU的内存容量。这种情况下梯度累积技术具有显著优势。

主要应用场景包括:

  • 资源受限环境下的大模型训练:对于大型Transformer模型或用于图像处理的卷积神经网络(CNNs),其完整批量训练所需的内存往往超出硬件限制。梯度累积使得在有限资源条件下实现等效的大批量训练成为可能。
  • 分布式训练环境优化:在多设备训练配置中,梯度累积可有效降低设备间的同步频率。各设备可先在本地累积梯度,仅在完成累积周期后进行一次同步,显著减少了通信开销。

实际应用中,梯度累积已成为各类模型训练过程(包括预训练、微调和后训练等阶段)的标准技术之一。

梯度累积中的归一化问题

从理论上讲,使用N个样本的单一批量训练应与使用4个N/4样本小批量的梯度累积训练在数学上等价。

但是其实并不是这样

简单的梯度求和策略无法确保梯度累积与完整批量训练的数学等价性。在大多数LLM训练中使用的交叉熵损失计算过程中,通常需要对非填充或非忽略的token数量进行归一化,确保损失值与训练序列中的有效token数量相匹配。为简化分析,我们假设序列长度等于数据集平均长度。

在实际的梯度累积过程中,各小批量的损失被独立计算后直接相加,这导致最终的总损失比完整批量训练的损失大G倍(G为梯度累积步数)。要修正这一问题,需要对每个累积的梯度进行1/G的缩放,以匹配完整批量训练的结果。然而这种缩放方法的有效性建立在小批量间序列长度一致的假设之上。

在实际训练LLM等模型时,序列长度的变化是常见现象,这种变化会导致损失计算出现偏差。在因果语言模型训练等应用场景中,正确的梯度累积方法应当首先计算累积步骤中所有批次的总体损失,随后将其除以这些批次中非填充token的总数。这与单独计算每个批次损失后取平均的方法有本质区别。

所以当小批量中的序列长度一致且无需填充时,传统的梯度累积方法仍然有效。对于不熟悉填充机制的读者,建议参考相关技术文档以深入理解其对批处理的影响。

从技术实现角度分析,LLM预训练阶段受此问题影响相对较小。尽管预训练过程需要大量GPU资源进行梯度累积,但该阶段通常采用完整的大规模批次,包含连续的文档块,无需填充操作。预训练阶段的设计目标是最大化单个训练步骤的学习效果。这也解释了为什么许多LLM的词汇表中不包含填充token,因为预训练阶段未使用填充操作。

梯度累积问题的实验验证

为量化分析错误梯度累积对训练过程的影响,本研究使用Unsloth对SmolLM-135M(Apache 2.0许可)进行了系统性实验,测试了不同批量大小、梯度累积步骤和序列长度配置下的模型表现。

实验环境采用内存效率优化的Unsloth框架和规模适中的LLM,以便在48GB GPU(RunPod提供的A40)上进行大批量训练实验。

大规模梯度累积步骤的影响分析

首先验证梯度累积的问题存在性。理论上以下训练配置应产生几乎一致的学习曲线:

  • per_device_train_batch_size = 1,gradient_accumulation_steps = 32
  • per_device_train_batch_size = 32,gradient_accumulation_steps = 1
  • per_device_train_batch_size = 2,gradient_accumulation_steps = 16
  • per_device_train_batch_size = 16,gradient_accumulation_steps = 2

这些配置的总体训练批量规模均为32。

本研究关注的是配置间的相对损失差异,而非绝对损失值。在最大序列长度2048 token(SmolLM支持的上限)条件下的学习曲线:

不同批量大小(bs)和梯度累积步骤(gas)配置下的学习曲线对比,可以看到在序列长度512 token条件下的学习曲线:

实验数据显示,批量大小(bs)为32与梯度累积步骤(gas)为32的配置间存在显著差异。当降低梯度累积步骤至16时,这种差异程度有所减小。

数据分析表明,gas=32配置下的损失值无法完全收敛到bs=32的水平。对于2048 token序列长度的配置,损失差异稳定在0.2至0.3区间;而对于512 token序列长度的配置,差异范围在0.1至0.2之间。

2048 token序列长度配置表现出更大的性能差异,这一现象表明小批量中填充序列的增加会显著放大梯度累积的偏差效应。

序列长度高度离散场景的实验分析

为深入研究该问题,作者构造了序列长度高度不均匀的小批量测试场景。以最大序列长度2048 token为例,当一个小批量中包含1个有效token的序列(附带2047个填充token),而另一个包含2048个有效token的完整序列(无填充)时,由于序列长度的极端差异,梯度累积的偏差会被显著放大。

实验中,通过从微调数据集中筛选出序列长度分布的两个极端(仅保留短于256 token和长于1024 token的序列),人为构造了序列长度的高度离散性。

实验获得的学习曲线如下:

如预期所示,序列长度的极端变化和分布稀疏性导致了更显著的性能退化。损失差异维持在0.45至0.70的较大区间内。

实验结论 该问题对于序列长度分布范围广泛的数据集训练配置产生了显著的负面影响。

序列长度一致性场景的实验验证

虽然序列长度的显著变化会加剧梯度累积的问题,但在处理序列长度相对一致的数据集时,这一问题的影响应当显著降低。在这种情况下梯度累积的偏差应被最小化。

为验证这一假设,实验将最大序列长度设定为1024,并仅保留长度不少于1024 token的序列进行微调。在此配置下,所有序列均无需填充,超长序列则被截断至1024 token。

实验中所有小批量的序列长度保持一致:

实验结果符合理论预期,学习曲线呈现出高度的一致性。虽然在约210个训练步骤后出现微小差异,但这可归因于使用8位量化AdamW优化器所引入的数值近似误差。

该实验从实践角度验证了序列长度一致时梯度累积的有效性。这也进一步佐证了之前的推断:LLM预训练阶段受此问题影响相对较小,因为预训练过程中极少使用序列填充,开发者通常会最大化利用每个批次中的token数量以提高内存使用效率。

梯度累积修正方案的实验验证

为验证Unsloth提出并经Hugging Face实现的修正方案的有效性,我们需要评估修正后带梯度累积和不带梯度累积配置的学习曲线一致性。

首先需要更新Transformers库环境。由于该修正方案近期才合并入主分支,我们采用以下命令从源代码更新:

 pipinstall--upgrade--no-cache-dir"git+https://github.com/huggingface/transformers.git"

在最大序列长度2048 token配置下的学习曲线对比:

实验结果表明修正方案取得了预期效果:bs=32, gas=1配置与bs=1, gas=32配置的学习曲线实现了有效对齐。梯度累积的数学等价性得到了恢复。虽然在图中并不明显,但详细数据分析显示在某些训练步骤中仍存在最大约0.0004的微小差异,这可归因于AdamW量化过程中引入的数值近似计算误差。

总结

鉴于该问题影响了跨设备和小批量的梯度累积机制,可以推断过去若干年间的部分模型训练结果可能处于次优状态。

研究结果表明其影响程度主要取决于具体的训练配置,尤其是涉及的GPU数量和梯度累积步骤数。采用大规模梯度累积步骤或高度可变序列长度进行训练的模型可能经历了次优的学习过程,这可能导致了下游任务性能的损失。

随着该问题在Hugging Face Transformers框架中得到识别和修正,未来的模型训练和微调工作有望获得更优且更稳定的效果。对于研究界和工业界此前使用受影响框架的相关工作,建议重新评估使用修正后梯度累积方案进行训练是否能带来显著性能提升。

总体而言,尽管该问题的具体影响范围尚待进一步量化研究,但可以确定的是采用有缺陷梯度累积方案训练的模型存在明显的优化空间。本研究不仅指出了一个长期被忽视的技术问题,也为未来的模型训练实践提供了重要的优化方向。

reddit帖子:https://avoid.overfit.cn/post/abe2d4a766f343d3b7d3906cd2e807a1

作者:Benjamin Marie

相关实践学习
部署Stable Diffusion玩转AI绘画(GPU云服务器)
本实验通过在ECS上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。
目录
相关文章
|
6月前
|
算法 计算机视觉
YOLOv3 的非极大值抑制(NMS)算法是如何工作的,它对最终检测结果有何影响?
YOLOv3 的非极大值抑制(NMS)算法是如何工作的,它对最终检测结果有何影响?
|
3月前
|
存储 机器学习/深度学习 物联网
基于重要性加权的LLM自我改进:考虑分布偏移的新框架
本文提出一种新的大型语言模型(LLM)自我改进框架——基于重要性加权的自我改进(IWSI),旨在优化自动生成数据的质量。通过引入DS权重指标衡量数据的分布偏移程度(DSE),该方法不仅能确保答案正确性,还能过滤掉那些虽正确但分布上偏离较大的样本,以提升自我训练的效果。IWSI使用一个小的有效数据集来估算每个自生成样本的DS权重,并据此进行筛选。实验结果显示,相比于仅依赖答案正确性的传统方法,IWSI能更有效地提高LLM在多种任务上的表现。特别是在数学问题解答任务上,相较于基线方法,IWSI带来了显著的性能提升,证实了过滤高DSE样本的重要性及该方法的有效性。
62 0
基于重要性加权的LLM自我改进:考虑分布偏移的新框架
|
5月前
|
机器学习/深度学习 算法
**反向传播算法**在多层神经网络训练中至关重要,它包括**前向传播**、**计算损失**、**反向传播误差**和**权重更新**。
【6月更文挑战第28天】**反向传播算法**在多层神经网络训练中至关重要,它包括**前向传播**、**计算损失**、**反向传播误差**和**权重更新**。数据从输入层流经隐藏层到输出层,计算预测值。接着,比较预测与真实值计算损失。然后,从输出层开始,利用链式法则反向计算误差和梯度,更新权重以减小损失。此过程迭代进行,直到损失收敛或达到训练次数,优化模型性能。反向传播实现了自动微分,使模型能适应训练数据并泛化到新数据。
69 2
|
6月前
|
机器学习/深度学习 算法
LSTM时间序列预测中的一个常见错误以及如何修正
在使用LSTM进行时间序列预测时,常见错误是混淆回归和预测问题。LSTM需将时间序列转化为回归问题,通常使用窗口或多步方法。然而,窗口方法中,模型在预测未来值时依赖已知的未来值,导致误差累积。为解决此问题,应采用迭代预测和替换输入值的方法,或者在多步骤方法中选择合适的样本数量和训练大小以保持时间结构。编码器/解码器模型能更好地处理时间数据。
304 1
|
5月前
|
机器学习/深度学习 算法 网络架构
**深度学习中的梯度消失与爆炸影响模型训练。梯度消失导致输入层参数更新缓慢,梯度爆炸使训练不稳。
【6月更文挑战第28天】**深度学习中的梯度消失与爆炸影响模型训练。梯度消失导致输入层参数更新缓慢,梯度爆炸使训练不稳。解决办法包括:换激活函数(如ReLU)、权重初始化、残差连接、批量归一化(BN)来对抗消失;梯度裁剪、权重约束、RMSProp或Adam优化器来防止爆炸。这些策略提升网络学习能力和收敛性。**
56 0
|
6月前
|
机器学习/深度学习 计算机视觉
【YOLOv8改进】MPDIoU:有效和准确的边界框损失回归函数 (论文笔记+引入代码)
YOLO目标检测专栏介绍了YOLO的有效改进和实战案例,包括卷积、主干网络、注意力机制和检测头的创新。提出了一种新的边界框回归损失函数MPDIoU,它基于最小点距离,能更好地处理不同宽高比的预测框,包含重叠、中心点距离和尺寸偏差的全面考虑。MPDIoU损失函数在YOLACT和YOLOv7等模型上的实验显示了优于现有损失函数的性能。此外,还介绍了WIoU_Scale类用于计算加权IoU,以及bbox_iou函数实现不同IoU变体的计算。详细实现和配置可在相应链接中查阅。
|
6月前
|
机器学习/深度学习 算法 网络架构
大模型开发:什么是梯度消失和梯度爆炸问题?如何解决这些问题?
深度学习中的梯度消失和爆炸问题影响模型学习和收敛。梯度消失导致深层网络参数更新缓慢,而梯度爆炸使训练不稳。解决方法包括:使用ReLU类激活函数、权重初始化策略(如He或Xavier)、残差连接、批量归一化。针对梯度爆炸,可采用梯度裁剪、权重约束和优化器如RMSProp、Adam。结合这些技术能改善网络训练效果和稳定性。
1870 3
|
6月前
|
Windows
R语言有状态依赖强度的非线性、多变量跳跃扩散过程模型似然推断分析股票价格波动
R语言有状态依赖强度的非线性、多变量跳跃扩散过程模型似然推断分析股票价格波动
|
6月前
|
算法 Windows
R语言广义二次跳跃、非线性跳跃扩散过程转移函数密度的估计及其应用
R语言广义二次跳跃、非线性跳跃扩散过程转移函数密度的估计及其应用
|
6月前
|
机器学习/深度学习 计算机视觉
YOLOv8改进 | 损失函数篇 | QualityFocalLoss质量焦点损失(含代码 + 详细修改教程)
YOLOv8改进 | 损失函数篇 | QualityFocalLoss质量焦点损失(含代码 + 详细修改教程)
1316 2