在快速發(fā)展的人工智能領(lǐng)域中,有效地利用大型語(yǔ)言模型(LLM)變得越來(lái)越重要。然而,有許多不同的方式可以使用大型語(yǔ)言模型,這可能會(huì)讓我們感到困惑。實(shí)際上,可以使用預(yù)訓(xùn)練的大型語(yǔ)言模型進(jìn)行新任務(wù)的上下文學(xué)習(xí)并進(jìn)行微調(diào)。
那么,什么是上下文學(xué)習(xí)?又如何對(duì)大模型進(jìn)行微調(diào)呢?
1. 上下文學(xué)習(xí)與索引
自從GPT-2和GPT-3出現(xiàn)以來(lái),可以發(fā)現(xiàn)在預(yù)訓(xùn)練的通用文本語(yǔ)料庫(kù)上的生成式大型語(yǔ)言模型(LLM)具備了上下文學(xué)習(xí)的能力,這意味著如果我們想要執(zhí)行LLM沒(méi)有明確訓(xùn)練的特定或新任務(wù),不需要進(jìn)一步訓(xùn)練或微調(diào)預(yù)訓(xùn)練的LLM。同時(shí),我們可以通過(guò)輸入提示直接提供一些目標(biāo)任務(wù)的示例。
In Context Learning(ICL)的關(guān)鍵思想是從類比中學(xué)習(xí)。下圖給出了一個(gè)描述語(yǔ)言模型如何使用 ICL 進(jìn)行決策的例子。首先,ICL 需要一些示例來(lái)形成一個(gè)演示上下文。這些示例通常是用自然語(yǔ)言模板編寫的。然后 ICL 將查詢的問(wèn)題(即需要預(yù)測(cè)標(biāo)簽的 input)和一個(gè)上下文演示(一些相關(guān)的 cases)連接在一起,形成帶有提示的輸入,并將其輸入到語(yǔ)言模型中進(jìn)行預(yù)測(cè)。
如果無(wú)法直接訪問(wèn)模型,例如通過(guò) API 使用模型,上下文學(xué)習(xí)非常有用。與上下文學(xué)習(xí)相關(guān)的是“硬提示微調(diào)”的概念,可以通過(guò)修改輸入來(lái)期望改善輸出。將直接修改輸入的單詞或標(biāo)記的微調(diào)稱為“硬”提示微調(diào),另一種微調(diào)方式稱為“軟”提示微調(diào)或通常稱為“提示微調(diào)”。這種提示微調(diào)方法提供了一種更為節(jié)省資源的參數(shù)微調(diào)替代方案。然而,由于它不會(huì)更新模型參數(shù)以適應(yīng)特定任務(wù)的微小差異,因此可能會(huì)限制其適應(yīng)能力。此外,由于通常需要手動(dòng)比較不同提示的質(zhì)量,提示微調(diào)可能需要耗費(fèi)大量人力。
另一種利用純粹的上下文學(xué)習(xí)方法的方法是索引。在LLM的范圍內(nèi),索引可以被視為一個(gè)上下文學(xué)習(xí)的解決方法,它使得LLM可以轉(zhuǎn)換為信息檢索系統(tǒng),用于從外部資源和網(wǎng)站中提取數(shù)據(jù)。在此過(guò)程中,索引模塊將文檔或網(wǎng)站分解為較小的段落,并將它們轉(zhuǎn)換為可以存儲(chǔ)在向量數(shù)據(jù)庫(kù)中的向量。然后,當(dāng)用戶提交查詢時(shí),索引模塊計(jì)算嵌入式查詢與數(shù)據(jù)庫(kù)中每個(gè)向量之間的向量相似度。最終,索引模塊獲取前k個(gè)最相似的嵌入式向量以生成響應(yīng)。索引的示意圖如下:
2. 基于三種特征的微調(diào)方法
上下文學(xué)習(xí)是一種有價(jià)值且用戶友好的方法,適用于直接訪問(wèn)大型語(yǔ)言模型受限的情況,例如通過(guò)API或用戶界面與LLM進(jìn)行交互。然而,如果可以訪問(wèn)LLM,則使用來(lái)自目標(biāo)領(lǐng)域的數(shù)據(jù)對(duì)其進(jìn)行適應(yīng)和微調(diào)通常會(huì)導(dǎo)致更好的結(jié)果。那么,我們?nèi)绾螌⒛P瓦m應(yīng)到目標(biāo)任務(wù)?下圖概述了三種常規(guī)的基于特征的微調(diào)方法。
除了微調(diào)編碼器風(fēng)格的LLM之外,相同的方法也適用于GPT般的解碼器風(fēng)格LLM。此外,還可以微調(diào)解碼器風(fēng)格的LLM生成多句話的答案,而不僅僅是分類文本。
2.1 基于特征的方法
在基于特征的方法中,需要加載預(yù)訓(xùn)練的LLM,并將其應(yīng)用于目標(biāo)數(shù)據(jù)集。在這里,需要特別關(guān)注生成訓(xùn)練集的輸出嵌入,這些嵌入可以用作訓(xùn)練分類模型的輸入特征。雖然這種方法在以嵌入為重點(diǎn)的模型(如BERT)中特別常見,但也可以從生成式GPT-style模型中提取嵌入。
分類模型可以是邏輯回歸模型、隨機(jī)森林或XGBoost ,也可以任何我們想要的模型。一般地,在這里線性分類器如邏輯回歸表現(xiàn)最佳。
從概念上講,可以用以下代碼說(shuō)明基于特征的方法:
model = AutoModel.from_pretrained("distilbert-base-uncased")
# ...
# tokenize dataset
# ...
# generate embeddings
@torch.inference_mode()
def get_output_embeddings(batch):
output = model(
batch["input_ids"],
attention_mask=batch["attention_mask"]
).last_hidden_state[:, 0]
return {"features": output}
dataset_features = dataset_tokenized.map(
get_output_embeddings, batched=True, batch_size=10)
X_train = np.array(imdb_features["train"]["features"])
y_train = np.array(imdb_features["train"]["label"])
X_val = np.array(imdb_features["validation"]["features"])
y_val = np.array(imdb_features["validation"]["label"])
X_test = np.array(imdb_features["test"]["features"])
y_test = np.array(imdb_features["test"]["label"])
# train classifier
from sklearn.linear_model import LogisticRegression
clf = LogisticRegression()
clf.fit(X_train, y_train)
print("Training accuracy", clf.score(X_train, y_train))
print("Validation accuracy", clf.score(X_val, y_val))
print("test accuracy", clf.score(X_test, y_test))
2.2 基于輸出層更新的微調(diào)
與上述基于特征的方法相關(guān)的一種流行方法是微調(diào)輸出層。與基于特征的方法類似,保持預(yù)訓(xùn)練LLM的參數(shù)不變,只訓(xùn)練新添加的輸出層,類似于在嵌入特征上訓(xùn)練邏輯回歸分類器或小型多層感知器。在代碼中,將如下所示:
model = AutoModelForSequenceClassification.from_pretrained(
"distilbert-base-uncased",
num_labels=2
)
# freeze all layers
for param in model.parameters():
param.requires_grad = False
# then unfreeze the two last layers (output layers)
for param in model.pre_classifier.parameters():
param.requires_grad = True
for param in model.classifier.parameters():
param.requires_grad = True
# finetune model
lightning_model = CustomLightningModule(model)
trainer = L.Trainer(
max_epochs=3,
...
)
trainer.fit(
model=lightning_model,
train_dataloaders=train_loader,
val_dataloaders=val_loader)
# evaluate model
trainer.test(lightning_model, dataloaders=test_loader)
理論上,這種方法應(yīng)該具有與基于特征的方法同樣的良好建模性能和速度。然而,由于基于特征的方法使預(yù)計(jì)算和存儲(chǔ)嵌入特征更加容易,因此在特定的實(shí)際情況下,記憶特征的方法可能更加方便。
2.3 面向所有層更新的微調(diào)
盡管原始的BERT論文聲稱,僅微調(diào)輸出層可以實(shí)現(xiàn)與微調(diào)所有層相當(dāng)?shù)慕P阅埽笳呱婕案鄥?shù),因此成本更高。例如,BERT基本模型約有1.1億個(gè)參數(shù)。然而,BERT基本模型用于二元分類的最后一層僅包含1,500個(gè)參數(shù)。此外,BERT基本模型的最后兩層占據(jù)60,000個(gè)參數(shù),僅占總模型大小的約0.6%。]
由于目標(biāo)任務(wù)和目標(biāo)領(lǐng)域與模型預(yù)訓(xùn)練的數(shù)據(jù)集相似程度的不同,幾乎總是通過(guò)微調(diào)所有層來(lái)獲得更優(yōu)秀的模型性能。因此,當(dāng)優(yōu)化模型性能時(shí),使用預(yù)訓(xùn)練LLM的黃金標(biāo)準(zhǔn)是更新所有層。從概念上講,這種方法與輸出層更新非常相似。唯一的區(qū)別是不凍結(jié)預(yù)訓(xùn)練LLM的參數(shù),而是對(duì)其進(jìn)行微調(diào)。
model = AutoModelForSequenceClassification.from_pretrained(
"distilbert-base-uncased",
num_labels=2
)
# don't freeze layers
# for param in model.parameters():
# param.requires_grad = False
# finetune model
lightning_model = LightningModel(model)
trainer = L.Trainer(
max_epochs=3,
...
)
trainer.fit(
model=lightning_model,
train_dataloaders=train_loader,
val_dataloaders=val_loader)
# evaluate model
trainer.test(lightning_model, dataloaders=test_loader)
多層微調(diào)通常會(huì)導(dǎo)致更好的性能,但代價(jià)也會(huì)增加,各種方法的計(jì)算和模型性能如下圖所示。
上面的情景突出了微調(diào)的三種極端情況:基于特征,僅訓(xùn)練最后一層或幾層,或者訓(xùn)練所有層。當(dāng)然,根據(jù)模型和數(shù)據(jù)集的不同,在各種選項(xiàng)之間探索也可能是值得的。
3. 參數(shù)高效微調(diào)
參數(shù)高效微調(diào)允許我們?cè)谧钚』?jì)算和資源占用的同時(shí)重復(fù)使用預(yù)訓(xùn)練模型??偟膩?lái)說(shuō),參數(shù)高效微調(diào)至少有以下5個(gè)優(yōu)點(diǎn):
- 減少計(jì)算成本(需要更少的GPU和GPU時(shí)間);
- 更快的訓(xùn)練時(shí)間(更快地完成訓(xùn)練);
- 更低的硬件要求(可以使用更小的GPU和更少的存儲(chǔ)器);
- 更好的模型性能(減少過(guò)擬合);
- 更少的存儲(chǔ)空間(大部分權(quán)重可以在不同任務(wù)之間共享)。
如前所述,微調(diào)更多的層通常會(huì)導(dǎo)致更好的結(jié)果。如果想要微調(diào)更大的模型,例如重新生成的LLM,這些模型只能勉強(qiáng)適合GPU內(nèi)存,該怎么辦呢?人們開發(fā)了幾種技術(shù),只需訓(xùn)練少量參數(shù)便可通過(guò)微調(diào)提升LLM的性能。這些方法通常被稱為參數(shù)高效微調(diào)技術(shù)(PEFT)。
在huggingface提供的PEFT工具中,可以很方便地實(shí)現(xiàn)將普通的HF模型變成用于支持輕量級(jí)微調(diào)的模型,使用非常便捷,目前支持4種策略,分別是:
- LoRA
- Prefix Tuning
- P-Tuning
- Prompt Tuning
下圖總結(jié)了一些最廣泛使用的PEFT技術(shù)。
那么這些技術(shù)是如何工作的呢?簡(jiǎn)而言之,它們都涉及引入少量的額外參數(shù),而不是對(duì)所有層都進(jìn)行修改。從某種意義上講,輸出層微調(diào)也可以被視為一種參數(shù)高效的微調(diào)技術(shù)。然而,像前綴微調(diào)、適配器和低秩適應(yīng)等技術(shù),它們“修改”多個(gè)層,以極低的成本實(shí)現(xiàn)更好的預(yù)測(cè)性能。
4.RHLF
在人類反饋增強(qiáng)學(xué)習(xí)中,預(yù)訓(xùn)練模型使用監(jiān)督學(xué)習(xí)和強(qiáng)化學(xué)習(xí)相結(jié)合進(jìn)行微調(diào)。這種方法是由原始的ChatGPT模型推廣而來(lái),而該模型又基于InstructGPT。RLHF通過(guò)讓人類對(duì)不同的模型輸出進(jìn)行排名或評(píng)分來(lái)收集人類反饋,從而提供獎(jiǎng)勵(lì)信號(hào)。然后,可以使用收集的獎(jiǎng)勵(lì)標(biāo)簽來(lái)訓(xùn)練獎(jiǎng)勵(lì)模型,進(jìn)而指導(dǎo)LLM對(duì)人類偏好的適應(yīng)。
獎(jiǎng)勵(lì)模型本身是通過(guò)監(jiān)督學(xué)習(xí)進(jìn)行學(xué)習(xí)的,通常使用預(yù)訓(xùn)練的LLM作為基本模型。接下來(lái),獎(jiǎng)勵(lì)模型用于更新預(yù)訓(xùn)練的LLM,以適應(yīng)人類的偏好。訓(xùn)練使用了一種稱為近端策略優(yōu)化的強(qiáng)化學(xué)習(xí)方法。InstructGPT論文中概述了RLHF的過(guò)程。
為什么要使用獎(jiǎng)勵(lì)模型而不是直接訓(xùn)練預(yù)先訓(xùn)練好的模型并使用人類反饋?主要原因是將人類納入學(xué)習(xí)過(guò)程會(huì)造成瓶頸,我們無(wú)法實(shí)時(shí)獲取反饋。
5.小結(jié)
微調(diào)預(yù)訓(xùn)練LLM的所有層仍然是適應(yīng)新目標(biāo)任務(wù)的黃金準(zhǔn)則。但是,諸如基于特征的方法、上下文學(xué)習(xí)和參數(shù)高效微調(diào)技術(shù)等方法,可以在最小化計(jì)算成本和資源的同時(shí),有效地將LLM應(yīng)用到新任務(wù)中。此外,帶有人類反饋的強(qiáng)化學(xué)習(xí)(RLHF)作為有監(jiān)督微調(diào)的替代方法,也可以提高模型性能。
【參考資料】
- A Survey on In-context Learning,https://arxiv.org/pdf/2301.00234.pdf
- LORA: LOW-RANK ADAPTATION OF LARGE LANGUAGE MODELS,https://arxiv.org/pdf/2106.09685.pdf
- Prefix-Tuning: Optimizing Continuous Prompts for Generation, https://aclanthology.org/2021.acl-long.353
- P-Tuning v2: Prompt Tuning Can Be Comparable to Fine-tuning Universally Across Scales and Tasks,https://arxiv.org/pdf/2110.07602.pdf
- The Power of Scale for Parameter-Efficient Prompt Tuning,https://arxiv.org/pdf/2104.08691.pdf
- BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding,https://arxiv.org/abs/1810.04805
- https://github.com/huggingface/peft
- https://github.com/rasbt