參數(shù)高效微調(diào)-Prefix Tuning、Adapter Tuning、LoRA 原創(chuàng)
回顧一下三種參數(shù)高效微調(diào)方法-Prefix Tuning、Adapter Tuning、LoRA
Prefix Tuning
Prefix Tuning
在prefix-tuning之前的工作主要是人工設(shè)計(jì)離散的template或者自動(dòng)化搜索離散template,問題在于最終的性能對(duì)人工設(shè)計(jì)的template的特別敏感:加一個(gè)詞或者少一個(gè)詞,或者變動(dòng)位置,都會(huì)造成很大的變化,所以這種離散化的token的搜索出來的結(jié)果可能并不是最優(yōu)的。Prefix Tuning方法使用連續(xù)的virtual token embedding來代替離散的token,且與Full-finetuning更新所有參數(shù)的方式不同。簡(jiǎn)而言之就是Prefix Tuning在原始文本進(jìn)行詞嵌入之后,在前面拼接上一個(gè)前綴矩陣,或者將前綴矩陣拼在模型每一層的輸入前。
Prefix Tuning的兩種示例
Prefix Tuning相關(guān)設(shè)置:
- 前綴初始化時(shí),[前綴長(zhǎng)度, 嵌入維度],其中嵌入維度與模型詞嵌入的維度相同。前綴長(zhǎng)度可以根據(jù)任務(wù)需求進(jìn)行調(diào)整。
- 更長(zhǎng)的前綴意味著更多的可微調(diào)參數(shù),效果也變好,不過長(zhǎng)度還是有閾值限制的(table-to-text是10,summarization是200)
(上):針對(duì)表格描述(Table-to-text)、文章總結(jié)(Summarization)、翻譯(Translation)三種任務(wù),F(xiàn)ine-Tuning需微調(diào)三個(gè)LM,且需保存每個(gè)特定任務(wù)的LM參數(shù),臃腫和低效;(下):然而,Prefix Tuning要清爽得多,針對(duì)三類任務(wù),只需訓(xùn)練三個(gè)Prefix生成器,原LM參數(shù)可直接復(fù)用。
推理階段,只需要將任務(wù)相關(guān)的輸入序列與訓(xùn)練好的前綴嵌入進(jìn)行拼接,然后輸入到模型中即可得到預(yù)測(cè)結(jié)果。
代碼過程,下面這個(gè)類旨在將輸入的前綴有效地編碼為適合后續(xù)處理的向量形式。
參考:https://github.com/THUDM/P-tuning-v2/blob/main/model/prefix_encoder.py
import torch
class PrefixEncoder(torch.nn.Module):
r'''
The torch.nn model to encode the prefix
Input shape: (batch-size, prefix-length)
Output shape: (batch-size, prefix-length, 2*layers*hidden)
'''
def __init__(self, config):
super().__init__()
self.prefix_projection = config.prefix_projection
if self.prefix_projection:
# Use a two-layer MLP to encode the prefix
self.embedding = torch.nn.Embedding(config.pre_seq_len, config.hidden_size)
self.trans = torch.nn.Sequential(
torch.nn.Linear(config.hidden_size, config.prefix_hidden_size),
torch.nn.Tanh(),
torch.nn.Linear(config.prefix_hidden_size, config.num_hidden_layers * 2 * config.hidden_size)
)
else:
self.embedding = torch.nn.Embedding(config.pre_seq_len, config.num_hidden_layers * 2 * config.hidden_size)
def forward(self, prefix: torch.Tensor):
if self.prefix_projection:
prefix_tokens = self.embedding(prefix)
past_key_values = self.trans(prefix_tokens)
else:
past_key_values = self.embedding(prefix)
return past_key_values
Adapter Tuning
通過引入少量可訓(xùn)練參數(shù)(適配器模塊)來進(jìn)行特定任務(wù)的優(yōu)化。適配器模塊是一組輕量級(jí)的參數(shù),被添加到模型的中間層,以保護(hù)原有預(yù)訓(xùn)練模型的參數(shù)。這種方法的目標(biāo)是在不改變整體模型結(jié)構(gòu)的情況下,通過調(diào)整適配器模塊的參數(shù)來適應(yīng)新任務(wù)。
Adapter Tuning針對(duì)Transformer的添加方式。左:針對(duì)每個(gè)Transformer層,Adapter參數(shù)在兩個(gè)殘差前插入。在Tuning中,圖中的綠色模塊是可訓(xùn)練的,其他模塊的參數(shù)固定。
Adapter Tuning的核心思想是在預(yù)訓(xùn)練模型的中間層中插入小的可訓(xùn)練層或“適配器”。這些適配器通常包括一些全連接層、非線性激活函數(shù)等,它們被設(shè)計(jì)用來捕獲特定任務(wù)的知識(shí),而不需要對(duì)整個(gè)預(yù)訓(xùn)練模型進(jìn)行大規(guī)模的微調(diào)。
下面舉個(gè)例子看下Adapter Tuning過程:
Adapters還可以和HuggingFace的Transformer包無縫整合,可以直接加載HuggingFace上的模型進(jìn)行Adapter微調(diào)。
以文本分類為例,BERT預(yù)訓(xùn)練模型加載:
from transformers import AutoTokenizer, AutoConfig
from adapters import AutoAdapterModel
model_path = "bert-base-chinese"
tokenizer = AutoTokenizer.from_pretrained(model_path)
config = AutoConfig.from_pretrained(model_path, num_labels=3)
model = AutoAdapterModel.from_pretrained(model_path, cnotallow=config)
然后為預(yù)訓(xùn)練模型設(shè)置適配器。這里需要注意,在Adapters包里,本節(jié)所介紹的適配器結(jié)構(gòu)被稱為瓶頸適配器(Bottleneck adapters)(如上圖1),使用BnConfig類來配置。這里需要為適配器取一個(gè)名字,之后可以通過這個(gè)名字來激活或者禁用這個(gè)適配器。
from adapters import BnConfig
adapter_name = "trouble_shooting"
# 添加一個(gè)新的adapter,類型為Bn adapter,即bottleneck adapter
config = BnConfig(mh_adapter=True, output_adapter=True, reduction_factor=16, non_linearity="relu")
model.add_adapter(adapter_name, cnotallow=config)
# 添加一個(gè)分類頭
model.add_classification_head(adapter_name,num_labels=3, activation_functinotallow="relu")
# 激活這個(gè)adapter
model.train_adapter(adapter_name)
主要參數(shù):
- mh_adapter:設(shè)置是否要在多頭注意力模塊之后添加適配器。
- output_adapter:設(shè)置是否要在Transformer模塊的輸出層添加適配器。
- reduction_factor:模型參數(shù)量與需調(diào)整的適配器參數(shù)量的比值。
- non_linearity:設(shè)置非線性部分使用的激活函數(shù)。
trainer訓(xùn)練模型:
from transformers import TrainingArguments
from adapters import AdapterTrainer
training_args = TrainingArguments(
num_train_epochs=5,
per_device_train_batch_size = 16,
logging_steps=2,
save_steps = 10,
gradient_accumulation_steps = 4,
output_dir="bert-adapter",
)
trainer = AdapterTrainer (
model=model, tokenizer=tokenizer
args=training_args, train_dataset=train_dataset,
optimizers=(optimizer, None)
)
trainer.train() # 開始訓(xùn)練
trainer.save_model() # 保存訓(xùn)練好的模型
LoRA
矩陣的秩(Rank):衡量了矩陣中行或列向量的線性無關(guān)性。
低秩:秩遠(yuǎn)小于矩陣的行數(shù)或列數(shù)。
LoRA(Low-Rank Adaptation)假設(shè)模型在任務(wù)適配過程中權(quán)重的改變量可以是低秩的。 LoRA通過在預(yù)訓(xùn)練模型中引入一個(gè)額外的線性層(由低秩矩陣A和B組成),并使用特定任務(wù)的訓(xùn)練數(shù)據(jù)來微調(diào)這個(gè)線性層,從而實(shí)現(xiàn)對(duì)模型的高效微調(diào)。
假設(shè)預(yù)訓(xùn)練參數(shù)為,那么全量微調(diào)時(shí)的更新量自然也 是一個(gè)矩陣,LoRA將更新量約束為低秩矩陣來降低訓(xùn)練時(shí)的參數(shù)量,即設(shè),其中以及,用新的替換模型原參數(shù),并固定不變,只訓(xùn)練,如下圖所示:
為了使得LoRA的初始狀態(tài)跟預(yù)訓(xùn)練模型一致,通常會(huì)將之一全零初始化,這樣可以得到,那么初始的就是。但這并不是必須的,如果都是非全零初始化,那么我們只需要將設(shè)置為
也就是說將固定不變的權(quán)重從換為,同樣可以滿足初始等于這一條件。
影響LoRA微調(diào)的相關(guān)參數(shù)如下:
- 秩(Rank)
參數(shù):lora_rank
描述:秩是LoRA中最重要的參數(shù)之一,它決定了低秩矩陣的維度。秩的大小直接影響模型的性能和訓(xùn)練時(shí)間。
常用值:對(duì)于小型數(shù)據(jù)集或簡(jiǎn)單任務(wù),秩可以設(shè)置為1或2;對(duì)于更復(fù)雜的任務(wù),秩可能需要設(shè)置為4、8或更高。 - 縮放系數(shù)(Alpha)
參數(shù):lora_alpha
描述:縮放系數(shù)用于在訓(xùn)練開始時(shí)對(duì)低秩矩陣的更新進(jìn)行縮放,以確保訓(xùn)練過程的穩(wěn)定性。
常用值:縮放系數(shù)的具體值取決于秩的大小和任務(wù)的復(fù)雜度。 - Dropout系數(shù)
參數(shù):lora_dropout
描述:Dropout是一種正則化技術(shù),用于防止模型過擬合。在LoRA Fine-tuning中,Dropout系數(shù)決定了在訓(xùn)練過程中隨機(jī)丟棄低秩矩陣中元素的概率。
常用值:Dropout系數(shù)的常用值范圍在0到1之間,具體值取決于模型的復(fù)雜度和數(shù)據(jù)的規(guī)模。 - 學(xué)習(xí)率
參數(shù):learning_rate
描述:學(xué)習(xí)率決定了模型在訓(xùn)練過程中權(quán)重更新的步長(zhǎng)。適當(dāng)?shù)膶W(xué)習(xí)率可以幫助模型在訓(xùn)練過程中更快地收斂到最優(yōu)解。
常用值:學(xué)習(xí)率的具體值取決于多個(gè)因素,包括模型的復(fù)雜度、數(shù)據(jù)的規(guī)模以及訓(xùn)練過程中的其他超參數(shù)設(shè)置。
LoRA微調(diào)如今是高效微調(diào)LLM的重要手段,PEFT庫也集成了相關(guān)方法: PEFT庫:https://github.com/huggingface/peft
參考文獻(xiàn)
- Prefix-Tuning: Optimizing Continuous Prompts for Generation
- Parameter-Efficient Transfer Learning for NLP
- LoRA: Low-Rank Adaption of Large Language Models
本文轉(zhuǎn)載自公眾號(hào)大模型自然語言處理 作者:余俊暉
