本文对比了全参数微调和LoRA,并分析了这两种技术各自的优势和劣势。作者使用了三个真实用例来训练LLaMA 2模型,这提供了比较特定任务的性能、硬件要求和训练成本的基准。本文证明了使用LoRA需要在serving效率和模型质量之间做出权衡,而这取决于具体的任务。

此外,本文还提供了关于如何通过智能提示技术来稳定LoRA训练的深入见解,并进一步验证了采用较低的学习率可以增强最终模型检查点的可靠性。实验是基于经LoRA调整的脚本版本进行的。

最近几个月,开源语言大模型(LLM)之间展开了与OpenAI专有模型的竞争。提升开源LLM性能的一种常用策略是全参数微调,这种方法对模型的所有参数进行了优化。在之前的博客文章中,我们分析了这种全参数微调与GPT-4的提示工程和少样本提示的比较效果。

正如你所料,全参数微调是一项资源密集型任务,需要强大的计算能力来管理优化器状态和检查点。一些上下文信息:通常情况下,优化器状态和梯度所占的内存空间约为模型本身的12倍。即便是拥有70亿参数的最小LLaMA-2模型,也需要大量计算资源来进行微调。因此,该领域出现了所谓的"参数高效微调(也被称为peft)"。在这些策略中,如LoRA(LLM的低秩适配)旨在优化较小的参数子集,从而最大限度地减少资源利用并加速训练周期。

本文比较了全参数微调和LoRA微调,突出了各自的优缺点。我们的讨论基于之前的博客文章,其中针对三个数据集进行了基准测试,并对基准线以及通过全参数微调获得的改进有了深入理解。鉴于LoRA仍是一项相对较新的技术,我们还详细讨论了使用LoRA进行训练的经验,并分享了一些实用技巧和方法,以帮助你更好地优化LoRA训练体验。

当应用于LLaMA-2时,基于LoRA的微调与全参数微调的效果几乎相当。因此,在生成SQL查询或基于文本的功能表征等专有任务中,它可以胜过GPT-4,但在数学推理任务上稍显逊色。上图中,粉色条形代表GPT-4的表现;颜色最深的条形代表基准的聊天调优模型;颜色较深的条形表示LoRA微调所带来的收益;颜色最浅的条形表示全参数微调结果。

在我们比较LoRA和全参数微调之前,先简要解释LoRA背后的基本概念。

什么是LoRA

LoRA,即LLM的低秩适配(Low-Rank Adaptation),它基于一个重要洞察:专有任务的微调权重与初始预训练权重之间的差异往往表现出“低固有秩(low intrinsic rank)”差异,这意味着它可以很好地近似为一个低秩矩阵。那什么是低秩矩阵?低秩矩阵具有较少的线性独立列,简单来说,就是矩阵的“复杂度”较低。低秩矩阵还具备一个酷炫的属性,它们可以表示为两个较小矩阵的乘积。这引出了这样一个假设:即微调权重和初始预训练权重之间的这种差距可以表示为两个较小矩阵的乘积。通过注重更新这两个较小的矩阵,而非整个原始权重矩阵,可以大幅提升计算效率。

在实际操作中,微调过程中的原始权重矩阵保持不变,而是通过两个附加矩阵A和B进行微调,这些矩阵作为微调权重矩阵的分解。见以下引自原始LoRA论文的示意图:

这张来自原始论文的示意图展示了模型中一个矩阵的张量运算。A和B即上文中提到的小矩阵。输入向量d会同时经过原始的预训练权重和经LoRA微调的低秩分解矩阵的并行处理。

值得注意的是,通过在训练过程中保持原始的“预训练权重”不变,并选择 r << d,相较于全参数微调,可显著减少优化器的内存占用和检查点尺寸。这种方法可应用于模型架构中的任何密集层。自原始LoRA论文发布以来,已陆续提出了许多基于LoRA的技术,此处对此不展开讨论。

尤其在管理多个专用模型时,更高效的模型部署是这些类似LoRA的参数高效方法的主要优势。随着业界向着开发一系列用于各种任务的专用LLM的方向发展,这一点变得越来越重要。

超参数

在深入讨论实验结果之前,先简要介绍一下在本文中作为LoRA配置基准所使用的超参数。

关于每种选择背后的理由仍然是LLM社区中的讨论热点,下文将对我们的决策进行阐述:

秩:8

选择更高秩的分解矩阵将抵消LoRA的效率优势。我们的初步测试表明,即使将秩提高到16,性能提升也微乎其微。因此,我们选择秩为8以维持更小的检查点尺寸,避免人为地扩大检查点文件。

Alpha:16

Alpha用于对学习到的权重进行扩展。包括原始的LoRA论文在内的现有文献,通常建议固定Alpha的值为16,而不将其作为可调节的超参数。

目标模块:所有密集层

最初的LoRA论文专注于仅对“Q”和“V”注意力矩阵进行微调,并取得了可观的成果,证明了该技术的有效性。但随后的研究表明,对其他层甚至所有层进行微调能够改善效果。我们推测,将LoRA应用于更多的层可以使我们更接近于实现全参数微调的能力。因此,我们选择在所有层上实施LoRA。

基础学习率:1e-4

学习率1e-4已成为使用LoRA微调LLM的标准。尽管我们在训练过程中偶尔会遇到训练损失不稳定的情况,但将学习率降低到3e-5等较低的值可有效稳定训练过程,关于这一点将在下文中详细讨论。

模型质量结果

在之前的博文中,我们展示了在GSM8k、ViGGO和SQL数据集上微调小型模型的有效性,本文我们就使用之前获得的结果作为基准来评估LoRA。关于使用的数据集和我们的评估技术的更多细节,我们推荐感兴趣的读者参考那篇文章。此处我们将重点关注全参数微调和LoRA微调的比较结果。

非结构化文本的功能性表征(ViGGO)

我们用于训练模型的第一个数据集是ViGGO。任务是从一个句子中提取功能表征。下图为一次失败预测中的一个数据点:

上图所示的数据点说明这个任务并不需要较高级别的逻辑或推理能力,它的本质是将模型从一种表征映射到另一种表征。这是一个小型模型通过全参数微调能够学得很好的任务。现在的问题是,LoRA是否能够同样出色地学习这一任务。

在ViGGO数据集上不同模型大小和微调方法的预测准确率。上图结果显示,我们的LoRA微调模型表现仅略低于全参数微调模型,在ViGGO测试集上几乎实现了100%的准确率。

根据这些结果,我们可以得出结论,尽管进行了一定程度的超参数优化,LoRA实验还是需要在准确率上做一些取舍。举一个具体的例子,在13B模型上我们牺牲了2%的准确率(95% vs 97%)。在大多数实际应用场景中,我们部署经微调的LLM来完成工作时,LoRA将成为首选技术,它可以提供更高效的服务,而2%的准确率损失可能并不是一个大问题。

小学数学(GSM8k)

该学术数据集测试了模型针对数学问题的逻辑推理能力。问题和答案结构类似下表所示:

值得注意的是,我们有许多方法可以得出这些问题的正确答案,这与我们测试的其他数据集形成了鲜明对比。考虑到这一点,在评估模型时,我们只考虑了在“####”之前的最终答案。那么,LoRA的表现如何呢?以下是我们针对GSM8k数据集训练的模型准确率示例:

在GSM8k数据集上,根据不同的模型大小和微调方法预测准确率。与全参数微调的对照组相比,两个LoRA微调模型的表现较差。但在70B模型上,情况则完全不同,LoRA几乎达到了与全参数微调相当的准确率。尽管如此,与基准模型相比,70B模型的改进仍然相对较小。

无论使用哪种微调技术,基础模型的参数大小对于模型在逻辑/数学推理方面的能力起着重要作用。然而,LoRA微调模型的表现始终明显低于全参数微调。这是因为LoRA是一种低秩近似,可能无法很好地体现数学技能。需要注意的是,与其他任务相比,即便进行了全参数微调,模型的表现也不够出色。学习数学并非一项简单任务,仅凭借几千个示例对模型进行微调,无法培养出强大的数学推理能力。

结构化查询语言(SQL)

我们最终评估了与实际用例相关的数据集。该SQL数据集将自然语言查询映射到了函数式SQL查询。具体而言,每个数据点都包含以下三个字段:

从SQL任务与ViGGO任务的相似性可以看出,经微调的LLM很有希望能够解决这一问题。同样,这个模型需要学习一组形式化原则来解决这一任务,而不是应用高级逻辑或推理。

在SQL数据集上,根据模型大小和微调方法预测准确率,LoRA微调模型的表现几乎可与全参数微调模型相当。需要注意的是,LoRA微调的13B模型的表现略优于全参数微调的7B模型。

LoRA与全参数微调:值得考虑的因素

尽管LoRA的设计初衷是作为全参数微调的替代方案,但在训练过程中,还是有一些值得注意的细微差别。

任务类型至关重要

需要强调的是,LoRA在微调时充当理想权重的低阶近似非常重要,这有效限制了网络的“适应能力(adaptation capacity)”。从数学角度来看,我们可以将LLM的原始权重视为矩阵“X”。对于任何给定任务,经过最优微调的LLM权重可以表示为矩阵“Y”。微调的目标是发现一个增量矩阵“Z”,使得X+Z=Y。然而,在LoRA的情况下,这个增量矩阵“Z”是通过低秩分解来近似的。因此,对于某些类型的任务来说,实现最优解可能具有一定的挑战性。某些数据集可能更容易适应,而其他数据集则可能会带来困难。相比之下,全参数微调不存在这样的限制,其学习到的权重保留了原始模型的表达能力,可能简化了适应各种数据的任务。这是一个需要通过实际测试来探索的实证问题。

实验中,我们观察到在GSM8k数学数据集上,全参数微调和LoRA微调之间的表现差距最大。这个任务需要学习一项具有挑战性的新技能,而这个技能可能并不适合用低秩近似来描述。然而,对于其他任务,这两种微调方式的差距则小得多。

LoRA对学习率的敏感度

即便对于LoRA表现良好的任务,我们仍需要调整学习率以确保训练的稳定性。由于参数数量有限,使用LoRA进行优化比全参数微调更加复杂。参考以下SQL实验图表:

上图展示了学习率对训练稳定性和验证集上困惑度(perplexity)的影响。在这一特定任务中,为稳定学习过程,我们将学习率从1e-4降低到了3e-5。

训练损失的变化自然会导致评估损失的巨大差异,这可能造成经LoRA微调的模型表现出现显著下降。虽然可能存在稳定性问题,但只要选择适当的学习率,与全参数微调相比,LoRA微调模型几乎可以实现最佳的收敛结果。

让我们在生产环境中探讨这一微调问题。下图展示了使用LoRA对一个70B模型进行微调的结果,除学习率外,所有超参数保持不变。

如上表所示,两个训练过程达到了大致相同的困惑度。对于较低的学习率,在训练损失稳定下降的同时困惑度达到了最小值;而对于较高的学习率,训练损失则急剧增加,这让我们对检查点的最优性更加缺乏信心。

这两个模型在GSM8k数据集上的成功率都为61%。尽管较低的学习率产生了一个典型的学习曲线,但较高的学习率却不够稳定。因此,虽然将学习率保持在1e-4可以节省训练成本,但我们必须意识到潜在的不稳定性。解决这个问题对于在生产环境中确保微调的成本效益和效果可靠性至关重要。

提示的作用

你可能会想:“我真的需要进行超参数调优吗?LoRA的一大关键优势是其在内存和服务效率方面的高效性,但如果要进行多次作业启动和网格搜索以找到最优配置,它可能会显得不那么吸引人。在这种情况下,提示可有效缓解这一问题。

在之前关于全参数微调的博客文章中,我们讨论了在用特殊的学习词元分割的情况下,如何有效利用输入和期望输出的简单拼接来代替提示。然而,在LoRA中,我们发现这种盲目地合并输入和输出的方式(即便使用了特殊词元)可能并不是最稳定的方法。这与我们之前的说法一致,即数据偏离分布外太远可能会导致LoRA难以处理。

在没有提示的ViGGO任务中,数据可能如下图所:

一个正确提示的数据点应该包含任务描述,这在某种程度上类似于没有少样本示例的提示工程:

聊天格式可作为一个通用的框架应用于各种任务。而关键在于任务描述会使得答案中的词元更有可能取决于问题中存在的词元,从而使问题优化变得更容易,微调效果更有效。

以上图表展示了在ViGGO任务的微调过程中,任务描述提示对模型性能的影响。在其他超参数不变的情况下,任务描述提示显著提高了模型学习的稳定性。

虽然任务描述可提高微调效率,但它可能会削弱微调的一个目标,即缩短提示长度。当使用LoRA作为微调策略时,这种权衡更加明显,因此,我们可能会陷入不断尝试各种提示来优化微调模型的循环之中。

LoRA与嵌入层特殊词元的相互作用

正如在之前的博客文章中强调的那样,我们已经集成了额外的特殊词元以更好地结构化数据。这些词元将我们正在使用的LLaMA 2模型的词汇表大小从32000扩展到了32004。这自然引发了一个问题:我们是否应该训练这些额外的词元?如果是的话,我们是否应该将LoRA应用于整个层或者使额外的嵌入可训练?

针对我们的微调目标,简单地将这些额外嵌入层随机初始化,然后将LoRA应用于整个嵌入层似乎就足够了。然而,重要的是要记住将这些随机初始化的新词汇嵌入包含在模型的检查点中,以便之后进行准确的推理。

LoRA嵌入层的检查点结构可视化,上图展示的是LoRA秩为8的示例。除LoRA特定的矩阵A和B之外,在词汇扩展期间保存创建的额外嵌入也非常重要,这些嵌入是随机初始化的。

LoRA的训练速度优势

LoRA在模型中引入了新参数和计算,这稍微减慢了前向传播的速度。另一方面,由于GPU之间需要进行的梯度通信较少,较少的可训练参数加快了反向传播速度。

我们发现,如果不利用减少的内存占用(通过增加批次大小),那么相对于全参数微调,LoRA并没有很明显的速度优势。不过,如果你的工作负载不受计算限制,那么增加批次大小确实可以提高训练吞吐量。

例如,当在一个p4de.24xlarge节点上微调一个LLaMA-7B模型时,全参数微调需要将批量大小设置为8,以充分利用可用的GRAM内存。然而,LoRA可以将批大小增加到64,这仍然在内存限制范围内,从而优化训练速度。

在p4de.24xlarge节点上,对比上下文长度为512的7B模型的训练吞吐量(每秒处理的词元数)。LoRA的较低内存占用允许使用更大的批大小,从而使吞吐量提高约30%。

还有一个需要考虑的因素:尽管LoRA可以提高吞吐量,但并不一定意味着相对于全参数微调,可以更快地达到收敛。LoRA虽然在内存方面十分高效,但可能会影响模型达到收敛的速度。为说明这一点,让我们来看一下之前实验中的训练损失曲线。

我们并排比较了LoRA和全参数训练损失,实时测量显示出相似的收敛速度。

测试结果显示,经过20分钟的训练,这两种方法产生的困惑度相当。因此,在达到类似质量的检查点时,从成本效益的角度考虑,LoRA和全参数微调方法可以说几乎相当。然而,如果要同时操作多个模型,那么LoRA更高效的资源部署可能会产生重要影响。

LoRA的内存使用优势

减少了内存占用是LoRA在训练过程中的最大优势,这使得我们可以选择更便宜且内存更小的实例进行微调,或者在更大的上下文长度下进行微调等。为说明这一点,我们尝试对所有模型大小(7B、13B和70B)进行训练。以下是应用全参数微调和LoRA进行一轮训练时的内存消耗并列对比:

训练过程中GPU内存(顶部)和CPU内存(底部)的总集群利用率(total cluster utilization)。左侧运行表示一个全参数微调的训练轮次,右侧运行表示一个LoRA微调的训练轮次。图表顶部的每种颜色都代表了一个GPU内存利用率。

从这两张图中可以看出,在检查点保存过程中,内存消耗在一个轮次结束时达到峰值。我们可以通过测算检查点保存期间GPU内存和CPU内存的消耗来估算所需的最大内存。

下面的图表进一步说明了这些微调技术之间的差异:

上图展示了在单个p4de.24xlarge节点上,使用512个词元上下文长度,批大小设置为8,对LLaMA 2模型系列进行微调时所需的总内存差异。对于7B和13B模型,LoRA消耗的内存要少得多,因此可以在更少或更便宜的实例上运行。而针对全参数微调的“缺失”图表则强调了内存需求超过p4de.24xlarge实例的规格。

对于70B模型,由于其较小的内存占用,我们能够在单个p4de.24xlarge节点上使用LoRA运行微调任务。这凸显了LoRA的另一个优势:显著降低的内存需求使我们能够利用更少的资源。

检查点大小和LoRA的服务优势

下表详细说明了全参数微调和两种不同LoRA配置之间的检查点大小差异。后一种LoRA配置将LoRA应用于所有层,使我们能够实现之前在本文中详细介绍的令人期待的准确度。

这些数据强调了LoRA在同时服务多个微调模型方面的实际优势。背景补充:存储20个完全微调的7B模型大约需要280GB内存。相比之下,基于我们选择的LoRA参数,同样的存储空间可以容纳包含基础模型在内的约700个经LoRA微调的70B模型。

就提供服务而言,LoRA较小的检查点允许高效存储和快速加载各种模型。当需要为每个服务请求使用独特模型时,这一点极为有利。此外,能够在同一批次的请求中重复使用基础模型,使我们能够使用更大的批大小,从而通过增加吞吐量、减少时延和降低成本来提高服务效率。

总结

通过比较硬件要求和预测准确率,我们希望说服读者相信以下观点:

  • LoRA的主要权衡十分明确:你可能会牺牲一部分模型质量,但将获得更高效地提供多个模型服务的能力。
  • 虽然LoRA在特定的应用领域中表现出色,但可能在需要逻辑推理等更广泛的任务中表现欠佳。
  • 对于盲目连接输入与输出的方式,我们应该调整学习率以获得可靠的训练检查点。
  • 不要低估数据提示的作用,它可以提高训练稳定性,使我们能够选择更高的学习率,且保持训练稳定。
  • 没有A100?有了LoRA,你仍然可以在较小的GPU上对模型进行微调。
  • 与常规检查点相比,LoRA检查点明显更小,更便于扩展服务,特别是在管理多个经微调的模型时。

Source: https://www.anyscale.com/blog/fine-tuning-llms-lora-or-full-parameter-an-in-depth-analysis-with-llama-2