解析大模型常用微调方法:P-Tuning、Prefix Tuning、Adapter、LoRA
作者:王海
原文:https://zhuanlan.zhihu.com/p/7474042360
预训练大模型虽然具有强大的泛化能力和广泛的知识,但它们通常是针对大量通用数据集进行训练的,这使得它们在处理特定任务时可能无法达到最佳效果,比如ChatGPT、混元、文心一言在回答一些常识性问题时表现的非常出色,但在物理、化学或编程等专业性问题上往往变的傻了吧唧。怎样让大模型更好地适用于特定场景?此时我们就需要利用特定任务的数据集来进一步训练模型,通过模型精调让全能型大模型变的专而精。这种针对性的精调训练能够使模型更加专注于目标任务的特征,从而提高其在特定任务上的准确性和效率。
目前精调大模型有两种方案,一是基于特定数据对模型的全量参数进行调整,这种方式充分利用了基础模型的表示能力,通过调整所有参数使其更好地适应特定任务。全量精调的完整过程是怎么样的呢?首先,需要准备一个针对特定任务的数据集,该数据集应包含输入和相应的标签,以便模型能够学习任务相关的特征和模式。接着加载预训练模型,然后基于前向+反向传播不断的更新调整模型参数直至收敛。在全量精调过程中,所有模型参数都会被优化,这意味着模型的每一层都会根据特定任务的数据进行调整。
虽说全量精调的优势在于能够最大限度地发挥模型的潜力,实现较高的性能。然而,它也存在一些缺点,如计算资源需求大、存储和内存占用较高,且在某些情况下可能导致过拟合,如一些百亿或千亿参数规模的大模型(GPT-3:175B;Grok-1:314B;Llama 3:400+B),全量精调一次可能要花费几十上百万美金,费时费力、成本非常高。
因此近两年使用更多是另一种方法:部分参数微调,它是一种更为高效的精调方法,会先冻结预训练模型的参数,每次只会对模型新增的一部分参数进行更新,通常是通过引入低秩矩阵分解或额外添加一些可训练的参数模块来实现的。因此相比预训练模型,微调更新的参数总量小很多,可能就百万、千万级别,相差2~3个数量级以上。这种方法旨在减少计算资源和存储需求,同时保持较高的性能,还减少了过拟合的风险。接下来会对目前大模型常用的一些微调方法进行简单的介绍,包括Prompt Tuning、P-Tuning、Prefix Tuning、Adapter、LoRA等。
一、Prompt Tuning
大模型的运行机制是“下一个字词预测”,用户输入的提示词作为模型的上下文,模型会根据提示词进行续写,因此提示词的质量将极大地影响模型的返回结果。例如,“写一篇关于Transformer大模型发展的文章”比“写一篇好文章”更能明确指导模型生成相关内容。
因此Prompt Tuning就通过在输入数据中添加任务相关的提示(Prompt),使模型能够更好地适应特定任务。“Prompt”部分其实是由若干 Tunable 的Token组成,作为输入文本的前缀。在 Prompt Tuning 过程中,只有 Tunable 的Token的Embeddings被训练,其他所有参数都被固定住。
常用的初始化Prompt Token 的方式有三种:1)随机初始化,比如全0;2)或词表随机抽样;3)或用类标签初始化,类别标签不足时可以补充词表抽样或随机初始化。
还有Prompt Token的长度并不是越长越好,之前有些同学做过实验,在一些中小模型上,Prompt Tokens增加,精调效果确实会变得更好,但是当Prompt的Token数量超过 20 以后,增益就越来越小;在一些超大模型上,因为模型本身的能力非常强,此次即使是单个Prompt Token,也能达到中小模型20+个Prompt Token的相近效果。
与传统的微调方法相比,Prompt Tuning不需对预训练模型进行任何修改,只需要在输入数据中加入与任务相关的提示信息。这种方法既保留了预训练模型的优势,又能够提高模型在特定任务上的性能。
二、P-Tuning
P-Tuning是 Prompt Tuning 的一种变体,其核心思想是在Prompt Tuning的基础上,在模型的输入层插入可训练的编码Token,加速收敛,并且使模型能够更好地理解下游任务的需求。P-Tuning中支持的编码格式主要有LSTM和MLP。
三、P-Tuning v2
之前的Prompt Tuning和P-Tuning方法存在一个主要的问题,就是缺少深度提示优化,因为前缀向量只被插入到Transformer第一层的输入Embedding序列中,在接下来的Transformer层中,插入前缀向量位置的Embedding都是由之前的Transformer层计算出来的,这可能导致输入的前缀向量对模型预测只有相对间接的影响。
针对此问题,有人提出了P-Tuning v2,它利用深度提示优化对Prompt Tuning和P-Tuning进行了改进,在每一层Transformer中都加入了Prompts tokens作为前缀输入。这样一来,在模型精调时,可训练的参数就增多了,从而使得P-Tuning v2精调后的模型在应对复杂的NLU任务方面,相比原始P-Tuning具有更出色的表现。
四、Prefix Tuning
Prefix-tuning对应的论文是《Prefix-Tuning: Optimizing Continuous Prompts for Generation(2021)》,其核心思想是通过在输入序列前添加一组可训练的前缀向量(Prefix),这些前缀向量作为额外的上下文信息,与输入序列共同通过模型的注意力机制进行处理。不过详细的计算过程,建议阅读ICLR 2022的论文《TOWARDS A UNIFIED VIEW OF PARAMETER-EFFICIENT TRANSFER LEARNING》。
接下来还是针对Prefix Tuning稍微展开介绍一下。Prefix向量通常会注入到Attention模块的键(Key)和值(Value)部分,并且对于每一层 Transformer 模型,都会有独立的一组前缀向量,这些向量会被注入到对应的层中。
假设输入序列是,第 层、矩阵的前缀向量是 、 ,那么第 l 层的自注意力计算过程即为
前缀向量、通常随机初始化,或基于预训练模型的某些特征进行初始化。在精调训练时,输入序列与前缀向量共同通过模型进行前向传播,生成输出;然后根据任务要求计算损失结果(如交叉熵损失);再反向传播更新前缀向量、 的值,重复多次直至收敛。
为什么Prefix向量只键(Key)和值(Value)部分?个人认为有两个原因:1)单纯保留 Q 矩阵不变,使其能继续确定要关注输入序列的哪些位置信息;2)目前很多大模型是基于Decoder结构的,推理时会依赖之前Token的KV值,因此模型实现时已经带了KV缓存模块,现在再加上KV矩阵的前缀向量,实现起来会更简单方便一些。
五、Adapter
Adapter精调方法最早由Houlsby等人在2019年提出,已被广泛应用于自然语言处理(NLP)领域。Adapter是一种高效的参数微调方法,旨在提高模型在特定任务上的性能,同时显著减少计算资源和时间成本。这种方法的核心思想是在预训练模型的每层中插入适配器模块(可以在Attention和FFN之后各插入一个Adapter;也可以在FNN的Add&Norm之后插入一个Adapter),这些模块由一到两个相对较小的神经网络层组成,例如降维和升维的前馈网络,使得整体结构变得紧凑且可扩展。在训练过程中,只有这些Adapter模块的参数会被更新,而预训练模型的其他部分保持不变。
之前论文中的一些实验结果表明,通过仅使用0.5%到8%的训练参数,Adapter精调就能逼近甚至达到全量参数精调的效果。尽管由于引入了额外的模块,模型的推理速度会略微下降,但这种下降幅度通常在4%到6%之间,可以通过优化设计来进一步降低影响。
Adapter精调还具有一些显著优势。首先,它只需要为每个任务添加少量的可训练参数,从而保持模型的参数效率。其次,可以为新任务添加新的Adapter模块而无需重新访问以前的任务,原始网络的参数保持固定,这有助于实现任务的独立性和可扩展性。此外,还有AdapterFusion和AdapterDrop等变体方法,分别在提高模型性能和推理速度方面做出了创新。
Adapter Fusion
AdapterFusion 在 Adapter 的基础上进行优化, 通过将学习过程分为两阶段来提升下游任务表现,有点MoE的味道。
-
阶段一:知识提取。训练 Adapter 模块学习下游任务的特定知识,将不同知识封装在不同的Adapter模块参数中。
-
阶段二:知识组合。将预训练模型参数与多个特定于不同任务的 Adapter 参数固定, 引入新参数学习组合多个Adapter 中的知识,提高模型在目标任务中的表现。
来自论文:https://arxiv.org/pdf/2005.00247
如上图所示。首先会对多个不同的下游任务训练多个不同的Adapter模块;接下来使用AdapterFusion组合多个Adapter中的知识,此时会先将预训练模型参数和全部的Adapter参数固定;最后引入新的AdapterFusion参数,使用多个下游任务的数据集进行AdapterFusion模块参数的训练,让AdapterFusion学习怎样组合多个适配器来解决特定的任务。
AdapterFusion模块的参数情况+计算逻辑都跟Attention类似,最大的区别是Attention中计算是基于 Q、K 的叉乘结果;而在AdapterFusion中,这里换成了点乘。因此每一层AdapterFusion模块的参数也主要包含Key、Value和Query三大块,Query的输入来自Transformer的前馈网络层,多个Adapter会共享Query数据;Value和Key的输入是各自Adapter的输出。之后将Query和Key做点积传入Softmax函数中,得到各个Adapter的权重分数,再对各个适配器进行加权输出。
还是再用数学语言简单描述一下会更直观一点。AdapterFusion的权重矩阵是 、、 ,其内部包含个Adapter,若第 个Adapter的输出是 ,AdapterFusion对应的前馈网络层的输出是 ,那当前第个Adapter对应的Query、Key和Value值为:
在AdapterFusion中,每次有任务数据进来后,第个Adapter的完整处理过程如下:
AdapterDrop
AdapterDrop比较简单,顾名思义就是在不影响任务性能的情况下,对Adapter进行动态高效的移除,尽可能的减少模型的参数量,提高模型在反向传播(训练)和正向传播(推理)时的效率。如下图所示,就是删除了第一个Transformer中的Adapter。并且在论文《AdapterDrop: On the Efficiency of Adapters in Transformers》中,作者也进行了实验对比,在删除了前五层的Adapter后,在对八个任务进行推理时,效率提高了很多。
AdapterDrop还可以与AdapterFusion结合使用,具体怎样结合?一般有两种方案:1)直接完全删掉一些Transformer中的AdapterFusion层,简答粗暴;2)将AdapterFusion中一些不重要的Adapter删除掉,如下图所示,就是将每个AdapterFusion中发挥作用最小的那个Adapter剔除掉。
六、LoRA
LoRA(Low-Rank Adaptation)是一种高效的大模型微调方法,特别适用于大规模语言模型和其他深度学习模型。其核心思想是通过引入低秩矩阵来模拟参数的变化,从而显著减少微调过程中需要更新的参数数量。具体而言,LoRA方法在预训练模型的线性变换层中注入两个低秩矩阵 A 和 B ,这两个矩阵通过矩阵乘法相乘后加到原始权重矩阵上,实现对模型的微调。由于 A 和 B 的秩远小于原始权重矩阵的秩,因此这种方法大幅降低了内存需求和计算开销。目前常用的LoRA方法一般是在Attention模块中的Quey、Key的线性变换层插入旁路LoRA模块,这块其实没有强制要求和固定标准,也可以根据实际任务情况选择其他合适的插入位置,如需要时也可以在FFN中的线性变换层插入LoRA模块。
在微调过程中,LoRA方法冻结预训练模型的原始权重,只训练低秩矩阵 和 。这样做的好处是可以在保持预训练模型原有能力的同时,快速适应新的任务或数据集。由于需要更新的参数数量大幅减少,LoRA方法的训练速度比传统的全参数微调方法快得多。比如之前的权重矩阵维度是 ,若要全量更新,那需要训练调整的参数量就是44236800;可通过LoRA,假定 ,那需要训练调整的参数量就仅为1489600,只是之前参数量的三十分之一,减少了非常多。
LoRA方法还具有很好的灵活性,可以轻松地在不同任务之间切换。通过简单的矩阵操作,就可以将一个任务的LoRA权重切换到另一个任务,实现模型的快速复用。此外,LoRA方法在推理阶段不引入额外的计算延迟,因为适配器权重可以与基本模型合并,确保模型在生产环境中的高效运行,而且旁路插入推理时还能并行处理,可进一步提升计算效率。
针对LoRA现在也有很多的变体优化方案,如QLoRA(Quantized LoRA)通过将模型权重进行量化,通常达到4位或更低的精度,从而在保持模型性能的同时,显著减少模型的存储和计算需求;LoRA+通过为矩阵 和设置不同的学习率来优化微调训练过程,因为在传统的LoRA中,所有权重矩阵使用相同的学习率,而LoRA+通过为矩阵设置更高的学习率,从而提高微调训练的收敛效率和模型性能;LoRA-FA(Frozen-A)则通过冻结矩阵,微调时只训练矩阵,从而将更新参数数量减半,效率更高,同时具有与普通LoRA相当的性能;还有LoRA-drop通过引入的算法来决定哪些层由LoRA微调,哪些层不需要;AdaLoRA则针对不同的LoRA层设置不同的秩(在原始的LoRA方法中,秩固定),有些层重要一些,对应的、矩阵的秩高一些,有的层发挥的作用较低,对应、矩阵的秩就低一些。
最后总结一下,微调通过在大模型上进行针对性、细致化的调整,有效提升了模型的性能,使其在特定任务中表现的更加准确、高效。同时,微调增强了模型的泛化能力,让模型在面对新数据时仍能保持良好的效果,适应复杂多变的应用场景。更重要的是,微调推动了大模型相关技术的创新与发展,为人工智能领域带来了新的突破和机遇,具有广泛的应用前景和重要的战略意义。
参考资料:
https://zhuanlan.zhihu.com/p/643406783
https://aclanthology.org/2021.emnlp-main.243.pdf
https://aclanthology.org/2021.acl-long.353.pdf
https://www.sohu.com/a/498726971_121119001
https://arxiv.org/pdf/2110.04366
https://aclanthology.org/2021.emnlp-main.626.pdf
https://arxiv.org/pdf/2005.00247
https://arxiv.org/pdf/2110.07602