赞
踩
目录
在Prefix Tuning之前的工作主要是人工设计离散的模版或者自动化搜索离散的模版。对于人工设计的模版,模版的变化对模型最终的性能特别敏感,加一个词、少一个词或者变动位置都会造成比较大的变化。而对于自动化搜索模版,成本也比较高;同时,以前这种离散化的token搜索出来的结果可能并不是最优的。
除此之外,传统的微调范式利用预训练模型去对不同的下游任务进行微调,对每个任务都要保存一份微调后的模型权重,一方面微调整个模型耗时长;另一方面也会占很多存储空间。
基于上述两点,Prefix Tuning提出固定预训练LM,为LM添加可训练,任务特定的前缀,这样就可以为不同任务保存不同的前缀,微调成本也小;同时,这种Prefix实际就是连续可微的Virtual Token(Soft Prompt/Continuous Prompt),相比离散的Token,更好优化,效果更好。
Prefix Tuning(论文:Prefix-Tuning: Optimizing Continuous Prompts for Generation),在输入token之前构造一段任务相关的virtual tokens作为Prefix,然后训练的时候只更新Prefix部分的参数,而PLM中的其他部分参数固定。
针对不同的模型结构,需要构造不同的Prefix。
z = [PREFIX; x; y]
,合适的上文能够在固定 LM 的情况下去引导生成下文(比如:GPT3的上下文学习)。z = [PREFIX; x; PREFIX0; y]
。Encoder端增加前缀是为了引导输入部分的编码,Decoder 端增加前缀是为了引导后续token的生成。该方法其实和构造Prompt类似,只是Prompt是人为构造的“显式”的提示,并且无法更新参数,而Prefix则是可以学习的“隐式”的提示。
同时,为了防止直接更新Prefix的参数导致训练不稳定和性能下降的情况,在Prefix层前面加了MLP结构,训练完成后,只保留Prefix的参数。
除此之外,通过消融实验证实,只调整embedding层的表现力不够,将导致性能显著下降,因此,在每层都加了prompt的参数,改动较大。
另外,实验还对比了位置对于生成效果的影响,Prefix-tuning也是要略优于Infix-tuning的。其中,Prefix-tuning形式为 [PREFIX; x; y]
,Infix-tuning形式为 [x; INFIX; y]
。
- (prompt_encoder): ModuleDict(
- (default): PrefixEncoder(
- (embedding): Embedding(30, 1024)
- (transform): Sequential(
- (0): Linear(in_features=1024, out_features=1024, bias=True)
- (1): Tanh()
- (2): Linear(in_features=1024, out_features=49152, bias=True)
- )
- )
- )
- (word_embeddings): Embedding(250880, 1024)
大模型全量微调对每个任务训练一个模型,开销和部署成本都比较高。同时,离散的prompts(指人工设计prompts提示语加入到模型)方法,成本比较高,并且效果不太好。
基于此,作者提出了Prompt Tuning,通过反向传播更新参数来学习prompts,而不是人工设计prompts;同时冻结模型原始权重,只训练prompts参数,训练完以后,用同一个模型可以做多任务推理。
Prompt Tuning(论文:The Power of Scale for Parameter-Efficient Prompt Tuning),该方法可以看作是Prefix Tuning的简化版本,它给每个任务定义了自己的Prompt,然后拼接到数据上作为输入,但只在输入层加入prompt tokens,并且不需要加入 MLP 进行调整来解决难训练的问题。
通过实验发现,随着预训练模型参数量的增加,Prompt Tuning的方法会逼近全参数微调的结果。
同时,Prompt Tuning 还提出了 Prompt Ensembling,也就是在一个批次(Batch)里同时训练同一个任务的不同 prompt(即采用多种不同方式询问同一个问题),这样相当于训练了不同模型,比模型集成的成本小多了。
除此之外,Prompt Tuning 论文中还探讨了 Prompt token 的初始化方法和长度对于模型性能的影响。通过消融实验结果发现,与随机初始化和使用样本词汇表初始化相比,Prompt Tuning采用类标签初始化模型的效果更好。不过随着模型参数规模的提升,这种gap最终会消失。
Prompt token 的长度在20左右时的表现已经不错(超过20之后,提升Prompt token长度,对模型的性能提升不明显了),同样的,这个gap也会随着模型参数规模的提升而减小(即对于超大规模模型而言,即使 Prompt token 长度很短,对性能也不会有太大的影响)。
- (prompt_encoder): ModuleDict(
- (default): PromptEmbedding(
- (embedding): Embedding(8, 1024)
- )
- )
- (word_embeddings): Embedding(250880, 1024)
该方法的提出主要是为了解决这样一个问题:大模型的Prompt构造方式严重影响下游任务的效果。比如:GPT-3采用人工构造的模版来做上下文学习(in context learning),但人工设计的模版的变化特别敏感,加一个词或者少一个词,或者变动位置都会造成比较大的变化。
同时,近来的自动化搜索模版工作成本也比较高,以前这种离散化的token的搜索出来的结果可能并不是最优的,导致性能不稳定。
基于此,作者提出了P-Tuning,设计了一种连续可微的virtual token(同Prefix-Tuning类似)。
P-Tuning(论文:GPT Understands, Too),该方法将Prompt转换为可以学习的Embedding层,并用MLP+LSTM的方式来对Prompt Embedding进行一层处理。
相比Prefix Tuning,P-Tuning加入的可微的virtual token,但仅限于输入层,没有在每一层都加;另外,virtual token的位置也不一定是前缀,插入的位置是可选的。这里的出发点实际是把传统人工设计模版中的真实token替换成可微的virtual token。
经过预训练的LM的词嵌入已经变得高度离散,如果随机初始化virtual token,容易优化到局部最优值,而这些virtual token理论是应该有相关关联的。因此,作者通过实验发现用一个prompt encoder来编码会收敛更快,效果更好。即用一个LSTM+MLP去编码这些virtual token以后,再输入到模型。
从对比实验证实看出,P-Tuning获得了与全参数一致的效果。甚至在某些任务上优于全参数微调。
并且在实验中还发现,相同参数规模,如果进行全参数微调,Bert的在NLU任务上的效果,超过GPT很多;但是在P-Tuning下,GPT可以取得超越Bert的效果。
- (prompt_encoder): ModuleDict(
- (default): PromptEncoder(
- (embedding): Embedding(20, 1024)
- (lstm_head): LSTM(1024, 128, num_layers=2, batch_first=True, bidirectional=True)
- (mlp_head): Sequential(
- (0): Linear(in_features=256, out_features=256, bias=True)
- (1): ReLU()
- (2): Linear(in_features=256, out_features=1024, bias=True)
- )
- )
- )
- (word_embeddings): Embedding(250880, 1024)
之前的Prompt Tuning和P-Tuning等方法存在两个主要的问题:
第一,缺乏模型参数规模和任务通用性。
第二,缺少深度提示优化,在Prompt Tuning和P-tuning中,连续提示只被插入transformer第一层的输入embedding序列中,在接下来的transformer层中,插入连续提示的位置的embedding是由之前的transformer层计算出来的,这可能导致两个可能的优化挑战。
考虑到这些问题,作者提出了Ptuning v2,它利用深度提示优化(如:Prefix Tuning),对Prompt Tuning和P-Tuning进行改进,作为一个跨规模和NLU任务的通用解决方案。
P-Tuning v2(论文: P-Tuning v2: Prompt Tuning Can Be Comparable to Fine-tuning Universally Across Scales and Tasks),该方法在每一层都加入了Prompts tokens作为输入,而不是仅仅加在输入层,这带来两个方面的好处:
具体做法基本同Prefix Tuning,可以看作是将文本生成的Prefix Tuning技术适配到NLU任务中,然后做了一些改进:
论文中展示了P-tuning v2在不同模型规模下的表现。对于简单的NLU任务,如SST-2(单句分类),Prompt Tuning和P-Tuning在较小的规模下没有显示出明显的劣势。但是当涉及到复杂的挑战时,如:自然语言推理(RTE)和多选题回答(BoolQ),它们的性能会非常差。相反,P-Tuning v2在较小规模的所有任务中都与微调的性能相匹配。并且,P-tuning v2在RTE中的表现明显优于微调,特别是在BERT中。
上面讨论了P-Tuning v2无论何种规模都可以与微调相媲美。然而,GLUE和SuperGLUE的大多数任务都是相对简单的NLU问题。
为了评估P-Tuning v2在一些困难的NLU挑战中的能力,作者选择了三个典型的序列标注任务(名称实体识别、抽取式问答(QA)和语义角色标签(SRL)),共八个数据集。我们观察到P-Tuning v2在所有任务上都能与全量微调相媲美。
论文还通过消融实验研究了不同任务上Prompt Length的影响:
总之,P-Tuning v2是一种在不同规模和任务中都可与微调相媲美的提示方法。P-Tuning v2对从330M到10B的模型显示出一致的改进,并在序列标注等困难的序列任务上以很大的幅度超过了Prompt Tuning和P-Tuning。P-Tuning v2可以成为微调的综合替代方案和未来工作的基线(Baseline)。
- (prompt_encoder): ModuleDict(
- (default): PrefixEncoder(
- (embedding): Embedding(30, 49152)
- )
- )
- (word_embeddings): Embedding(250880, 1024)
可以简单的将P-Tuning认为是针对Prompt Tuning的改进,P-Tuning v2认为是针对Prefix Tuning的改进。
神经网络包含很多全连接层,其借助于矩阵乘法得以实现,然而,很多全连接层的权重矩阵都是满秩的。当针对特定任务进行微调后,模型中权重矩阵其实具有很低的本征秩(intrinsic rank),因此,论文的作者认为权重更新的那部分参数矩阵尽管随机投影到较小的子空间,仍然可以有效的学习,可以理解为针对特定的下游任务这些权重矩阵就不要求满秩。
LoRA(论文:LoRA: LOW-RANK ADAPTATION OF LARGE LANGUAGE MODELS),该方法的核心思想就是通过低秩分解来模拟参数的改变量,从而以极小的参数量来实现大模型的间接训练。
在涉及到矩阵相乘的模块,在原始的PLM旁边增加一个新的通路,通过前后两个矩阵A,B相乘,第一个矩阵A负责降维,第二个矩阵B负责升维,中间层维度为r,从而来模拟所谓的本征秩(intrinsic rank)。
可训练层维度和预训练模型层维度一致为d,先将维度d通过全连接层降维至r,再从r通过全连接层映射回d维度,其中,r<<d,r是矩阵的秩,这样矩阵计算就从d x d变为d x r + r x d,参数量减少很多。
在下游任务训练时,固定模型的其他参数,只优化新增的两个矩阵的权重参数,将PLM跟新增的通路两部分的结果加起来作为最终的结果(两边通路的输入跟输出维度是一致的),即h=Wx+BAx。第一个矩阵的A的权重参数会通过高斯函数初始化,而第二个矩阵的B的权重参数则会初始化为零矩阵,这样能保证训练开始时新增的通路BA=0从而对模型结果没有影响。
在推理时,将左右两部分的结果加到一起即可,h=Wx+BAx=(W+BA)x,所以只要将训练完成的矩阵乘积BA跟原本的权重矩阵W加到一起作为新权重参数替换原本PLM的W即可,对于推理来说,不会增加额外的计算资源。
此外,Transformer的权重矩阵包括Attention模块里用于计算query, key, value的Wq,Wk,Wv以及多头attention的Wo,以及MLP层的权重矩阵,LoRA只应用于Attention模块中的4种权重矩阵,而且通过消融实验发现同时调整 Wq 和 Wv 会产生最佳结果。
实验还发现,保证权重矩阵的种类的数量比起增加隐藏层维度r更为重要,增加r并不一定能覆盖更加有意义的子空间。
那么关于秩的选择,通常情况下,rank为4,8,16即可。
通过实验也发现,在众多数据集上LoRA在只训练极少量参数的前提下,最终在性能上能和全量微调匹配,甚至在某些任务上优于全量微调。
- PeftModelForCausalLM(
- (base_model): LoraModel(
- (model): BloomForCausalLM(
- (transformer): BloomModel(
- (word_embeddings): Embedding(250880, 1024)
- (word_embeddings_layernorm): LayerNorm((1024,), eps=1e-05, elementwise_affine=True)
- (h): ModuleList(
- (0): BloomBlock(
- (input_layernorm): LayerNorm((1024,), eps=1e-05, elementwise_affine=True)
- (self_attention): BloomAttention(
- (query_key_value): Linear(
- in_features=1024, out_features=3072, bias=True
- (lora_dropout): ModuleDict(
- (default): Dropout(p=0.1, inplace=False)
- )
- (lora_A): ModuleDict(
- (default): Linear(in_features=1024, out_features=8, bias=False)
- )
- (lora_B): ModuleDict(
- (default): Linear(in_features=8, out_features=3072, bias=False)
- )
- (lora_embedding_A): ParameterDict()
- (lora_embedding_B): ParameterDict()
- )
- (dense): Linear(in_features=1024, out_features=1024, bias=True)
- (attention_dropout): Dropout(p=0.0, inplace=False)
- )
- (post_attention_layernorm): LayerNorm((1024,), eps=1e-05, elementwise_affine=True)
- (mlp): BloomMLP(
- (dense_h_to_4h): Linear(in_features=1024, out_features=4096, bias=True)
- (gelu_impl): BloomGelu()
- (dense_4h_to_h): Linear(in_features=4096, out_features=1024, bias=True)
- )
- )
在NLP领域,对于下游任务进行大型预训练语言模型的微调已经成为一种重要的做法。一般而言,我们会采用对原有的预训练模型进行全量微调的方法来适配下游任务,但这种方法存在两个问题。
为了解决这些问题,研究者提出了两个主要研究方向,以减少微调参数的数量,同时保持甚至提高预训练语言模型的性能。
基于以上问题进行总结:
为了弥补这一差距,作者提出了AdaLoRA,它根据权重矩阵的重要性得分,在权重矩阵之间自适应地分配参数预算。
AdaLoRA(论文:ADAPTIVE BUDGET ALLOCATION FOR PARAMETEREFFICIENT FINE-TUNING),是对LoRA的一种改进,它根据重要性评分动态分配参数预算给权重矩阵。具体做法如下:
通过实验证明,AdaLoRA 实现了在所有预算、所有数据集上与现有方法相比,性能更好或相当的水平。 例如,当参数预算为 0.3M 时,AdaLoRA 在RTE数据集上,比表现最佳的基线(Baseline)高 1.8%。
微调大型语言模型 (LLM) 是提高其性能以及添加所需或删除不需要的行为的一种非常有效的方法。然而,微调非常大的模型非常昂贵;以 LLaMA 65B 参数模型为例,常规的 16 bit微调需要超过 780 GB 的 GPU 内存。
虽然最近的量化方法可以减少 LLM 的内存占用,但此类技术仅适用于推理场景。
基于此,作者提出了QLoRA,并首次证明了可以在不降低任何性能的情况下微调量化为 4 bit的模型。
QLoRA(论文: QLORA: Efficient Finetuning of Quantized LLMs),使用一种新颖的高精度技术将预训练模型量化为 4 bit,然后添加一小组可学习的低秩适配器权重,这些权重通过量化权重的反向传播梯度进行微调。QLORA 有一种低精度存储数据类型(4 bit),还有一种计算数据类型(BFloat16)。实际上,这意味着无论何时使用 QLoRA 权重张量,我们都会将张量反量化为 BFloat16,然后执行 16 位矩阵乘法。QLoRA提出了两种技术实现高保真 4 bit微调——4 bit NormalFloat(NF4) 量化和双量化。此外,还引入了分页优化器,以防止梯度检查点期间的内存峰值,从而导致内存不足的错误,这些错误在过去使得大型模型难以在单台机器上进行微调。具体说明如下:
实验证明,无论是使用16bit、8bit还是4bit的适配器方法,都能够复制16bit全参数微调的基准性能。这说明,尽管量化过程中会存在性能损失,但通过适配器微调,完全可以恢复这些性能。
实验还比较了不同的4bit数据类型对效果(zero-shot均值)的影响,其中,NFloat 显著优于Float,而NFloat + DQ略微优于NFloat,虽然DQ对精度提升不大,但是对于内存控制效果更好。
除此之外,论文中还对不同大小模型、不同数据类型、在 MMLU数据集上的微调效果进行了对比。使用QLoRA(NFloat4 + DQ)可以和Lora(BFloat16)持平,同时, 使用QLORA( FP4)的模型效果落后于前两者一个百分点。
作者在实验中也发现了一些有趣的点,比如:指令调优虽然效果比较好,但只适用于指令相关的任务,在聊天机器人上效果并不佳,而聊天机器人更适合用Open Assistant数据集去进行微调。通过指令类数据集的调优更像是提升大模型的推理能力,并不是为聊天而生的。
总之,QLoRA的出现给大家带来一些新的思考,不管是微调还是部署大模型,之后都会变得更加容易。每个人都可以快速利用自己的私有数据进行微调;同时,又能轻松的部署大模型进行推理。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。