本篇主要介绍早期的PEFT
方法,包括Adapter
适配器方法、PET
、Prefix Tuning
以及Prompt Tuning
。
一、前言
当前主流微调方法分为:Fine-tune
和PEFT
。
Fine-tune
,也叫全参微调。在LLM
出现之前,Bert
系列微调模型一直用的这种方法,即模型的全部参数权重参与更新以适配领域数据(有硬件条件的话自然是最好的选择)。
PEFT
, 包括Prefix Tuning
、P-Tuning V1/V2
、LoRA
、AdaLoRA
、QLoRA
等方法,即部分模型参数参与微调。这种方式训练快,显存占用少,但是效果可能跟FT(fine-tune)
比会稍有损失。
二、Adapter适配器方法
谷歌的研究人员于2019年在论文《Parameter-Efficient Transfer Learning for NLP》
提出针对 BERT
的 PEFT
微调方式,拉开了 PEFT
研究的序幕。他们指出:
- 在面对特定的下游任务时,如果进行
Full-fintuning
(即预训练模型中的所有参数都进行微调),过于低效 - 而如果采用固定预训练模型的某些层,只微调接近下游任务的那几层参数,又难以达到较好的效果
于是他们设计了如下图所示的 Adapter
结构,作为全模型微调的一种替代方案:
%E7%B3%BB%E5%88%97%E8%AE%BA%E6%96%87%E6%80%BB%E7%BB%93/image-20231226185027290.png)
在预训练模型每一层(或某些层)中添加Adapter
模块(如上图左侧结构所示),微调时冻结预训练模型主体,由Adapter
模块学习特定下游任务的知识。每个Adapter
模块由两个前馈子层组成,第一个前馈子层将Transformer
块的输出作为输入,将原始输入维度d
投影到m
,通过控制m
的大小来限制Adapte
r模块的参数量,通常情况下m<<d
。在输出阶段,通过第二个前馈子层还原输入维度,将m
重新投影到d
,作为Adapter
模块的输出(如上图右侧结构)。
可以看到每一个Adapter Layer
需要训练的参数,包括偏置的话是: 2md + m + d
通过添加Adapter
模块来产生一个易于扩展的下游模型,每当出现新的下游任务,通过添加Adapter
模块来避免全模型微调与灾难性遗忘的问题。Adapter
方法不需要微调预训练模型的全部参数,通过引入少量针对特定任务的参数,来存储有关该任务的知识,降低对模型微调的算力要求。
%E7%B3%BB%E5%88%97%E8%AE%BA%E6%96%87%E6%80%BB%E7%BB%93/image-20231226192458146.png)
%E7%B3%BB%E5%88%97%E8%AE%BA%E6%96%87%E6%80%BB%E7%BB%93/image-20240101220641347.png)
从实验结果来看,该方法能够在只额外对增加的3.6%
参数规模(相比原来预训练模型的参数量)的情况下取得和Full-finetuning
接近的效果(GLUE
指标在0.4%
以内)
三、Pattern-Exploiting Training(PET)
想要更好的理解下文将讲的Prefix Tuning/P-Tuning
,便不得不提Pattern-Exploiting Training(PET)
,所谓PET
,主要的思想是借助由自然语言构成的模版(英文常称Pattern
或Prompt
),将下游任务也转化为一个完形填空任务,这样就可以用BERT
的MLM
模型来进行预测了。
比如下图中通过条件前缀来实现情感分类和主题分类的例子:
%E7%B3%BB%E5%88%97%E8%AE%BA%E6%96%87%E6%80%BB%E7%BB%93/957788384.png)
当然,这种方案也不是只有MLM
模型可行,用GPT
这样的单向语言模型其实也很简单:
%E7%B3%BB%E5%88%97%E8%AE%BA%E6%96%87%E6%80%BB%E7%BB%93/2581387139.png)
不过由于语言模型是从左往右解码的,因此预测部分只能放在句末了(但还可以往补充前缀说明,只不过预测部分放在最后)
这种人为构造提示模板,就是在输入上加Prompt
文本,再对输出进行映射。但这种方式怎么想都不是很优雅,无法避免人工的介入。即使有方法可以批量挖掘,但也有些复杂(有这个功夫能标不少高质量语料),而且模型毕竟是黑盒,对离散文本输入的鲁棒性很差。
四、Prefix Tuning
在Prefix Tuning
之前的工作主要是人工设计离散的template
或者自动化搜索离散template,问题在于最终的性能对人工设计的template
的特别敏感:加一个词或者少一个词,或者变动位置,都会造成很大的变化,所以这种离散化的token
的搜索出来的结果可能并不是最优的,下图给出的是一个例子:
论文摘要:微调是利用大型预训练语言模型执行下游任务的实际方法。然而,它修改了所有语言模型参数,因此需要为每个任务存储一个完整的副本。在本文中,我们提出了一种名为“前缀调优”的轻量级微调替代方法,用于自然语言生成任务。这种方法保持语言模型参数不变,但优化了一个小型的连续任务特定向量(称为前缀)。前缀调优从提示方法中获得灵感,允许后续标记关注这个前缀,就像它们是”虚拟标记”。我们将前缀调优应用于GPT-2
进行表格到文本的生成,以及使用BART进行摘要生成。我们发现,通过仅学习0.1%
的参数,前缀调优在完整数据集中获得了与微调相当的性能,在低数据设置中表现更好,并且能够更好地推广到训练中未见的主题。
Prefix Tuning
是PEFT
方法之一,Prefix Tuning
之前的工作主要是人工设计模板或者自动化搜索模板,也是prompt
范式的第一阶段,就是在输入上加上prompt
文本,再对输出进行映射。这种离散模板对模型的鲁棒性很差。所以后续的研究都将离散的方式转成连续。Prefix Tuning
在模型输入前添加一个连续的且任务特定的向量序列称之为prefix
,固定PLM(预训练模型)
的所有参数,只更新优化特定任务的prefix
。
%E7%B3%BB%E5%88%97%E8%AE%BA%E6%96%87%E6%80%BB%E7%BB%93/image-20231226200610499.png)
4.1 适配不同任务的prefix构造形式
针对不同的模型结构,需要构造不同的 Prefix
。
- 针对自回归架构模型:在句子前面添加前缀,得到
z = [PREFIX; x; y]
,合适的上文能够在固定LM
的情况下去引导生成下文(比如:GPT3
的上下文学习)。 - 针对编码器-解码器架构模型:
Encoder
和Decoder
都增加了前缀,得到z = [PREFIX; x; PREFIX'; y]
。 Encoder
端增加前缀是为了引导输入部分的编码,Decoder
端增加前缀是为了引导后续token
的生成。
%E7%B3%BB%E5%88%97%E8%AE%BA%E6%96%87%E6%80%BB%E7%BB%93/image-20231228111353270.png)
4.2 对virtual token的编码方式
同时,为了防止直接更新 Prefix
的参数导致训练不稳定和性能下降的情况,在 Prefix
层前面加了 MLP
结构,训练完成后,只保留 Prefix
的参数。
除此之外,通过消融实验证实,只调整embedding
层的表现力不够,将导致性能显著下降,因此,在每层Transformer
的输入部分都加了prompt
的参数,改动较大。
四、Prompt Tuning
2021年4月,Google Research
通过此篇论文《The Power of Scale for Parameter-Efficient Prompt Tuning》提出了Prompt Tuning
,论文中指出,该方法可以看作是Prefix Tuning
的简化版本。
Prefix Tuning
在每层Transformer
的输入部分都加了prompt
的参数,相比之下,Prompt Tuning
使用单个提示表示,该表示前置于嵌入式输入。除了需要更少的参数外,所提出方法允许Transformer
更新中间层任务表示。此外,
Prefix tuning
也依赖于前缀的重新参数化来稳定学习,这在训练期间增加了大量参数,而Prefix tuning
的配置不需要这种重新参数化,并且在SuperGLUE
任务和模型尺寸上都是鲁棒的。它冻结整个预训练模型,只允许每个下游任务在输入文本前添加额外的k个可调
tokens
(意味着它给每个任务都定义了自己的Prompt
,在输入层加入prompt tokens
)
具体而言,如下图所示:
%E7%B3%BB%E5%88%97%E8%AE%BA%E6%96%87%E6%80%BB%E7%BB%93/image-20240107102116261.png)
Model Tuning
需要为每个下游任务生成整个预训练模型的任务特定副本,并且推理必须分批执行Prompt Tuning
只需要为每个任务存储一个小的特定于任务的提示,并使用原始的预训练模型支持混合任务推理
且通过实验发现,随着预训练模型参数量的增加,Prompt Tuning
的方法会逼近全参数微调的结果
%E7%B3%BB%E5%88%97%E8%AE%BA%E6%96%87%E6%80%BB%E7%BB%93/image-20240107103047631.png)