LLM 課程文件
使用 Trainer API 微調模型
並獲得增強的文件體驗
開始使用
使用 Trainer API 微調模型
🤗 Transformers 提供了 Trainer
類,可幫助您使用現代最佳實踐在自己的資料集上微調其提供的任何預訓練模型。完成上一節中的所有資料預處理工作後,您只需幾個步驟即可定義 Trainer
。最困難的部分可能是準備執行 Trainer.train()
的環境,因為它在 CPU 上執行會非常慢。如果您沒有設定 GPU,可以在 Google Colab 上獲得免費的 GPU 或 TPU。
📚 訓練資源:在深入訓練之前,請熟悉全面的 🤗 Transformers 訓練指南,並在 微調操作指南 中探索實際示例。
下面的程式碼示例假設您已經執行了上一節中的示例。以下是您需要的回顧摘要:
from datasets import load_dataset
from transformers import AutoTokenizer, DataCollatorWithPadding
raw_datasets = load_dataset("glue", "mrpc")
checkpoint = "bert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
def tokenize_function(example):
return tokenizer(example["sentence1"], example["sentence2"], truncation=True)
tokenized_datasets = raw_datasets.map(tokenize_function, batched=True)
data_collator = DataCollatorWithPadding(tokenizer=tokenizer)
訓練
在定義 Trainer
之前,第一步是定義一個 TrainingArguments
類,其中包含 Trainer
用於訓練和評估的所有超引數。您必須提供的唯一引數是儲存訓練模型以及沿途檢查點的目錄。對於其餘所有引數,您可以保留預設值,這對於基本微調應該非常有效。
from transformers import TrainingArguments
training_args = TrainingArguments("test-trainer")
如果您想在訓練期間自動將模型上傳到 Hub,請在 TrainingArguments
中傳遞 push_to_hub=True
。我們將在第 4 章中瞭解更多資訊。
🚀 高階配置:有關所有可用訓練引數和最佳化策略的詳細資訊,請檢視 TrainingArguments 文件 和 訓練配置操作指南。
第二步是定義我們的模型。與上一章中一樣,我們將使用 AutoModelForSequenceClassification
類,帶有兩個標籤。
from transformers import AutoModelForSequenceClassification
model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2)
您會注意到,與第 2 章不同,在例項化此預訓練模型後,您會收到警告。這是因為 BERT 尚未在分類句子對上進行預訓練,因此預訓練模型的頭部已被丟棄,並添加了一個適合序列分類的新頭部。警告表明某些權重未使用(對應於丟棄的預訓練頭部),而另一些權重是隨機初始化的(對應於新頭部)。它最後鼓勵您訓練模型,這正是我們現在要做的。
有了模型後,我們可以透過將所有已構建的物件(model
、training_args
、訓練和驗證資料集、我們的 data_collator
以及我們的 processing_class
)傳遞給它來定義 Trainer
。processing_class
引數是最近新增的一個引數,它告訴 Trainer 使用哪個分詞器進行處理。
from transformers import Trainer
trainer = Trainer(
model,
training_args,
train_dataset=tokenized_datasets["train"],
eval_dataset=tokenized_datasets["validation"],
data_collator=data_collator,
processing_class=tokenizer,
)
當您將分詞器作為 processing_class
傳遞時,Trainer
使用的預設 data_collator
將是 DataCollatorWithPadding
。在這種情況下,您可以跳過 data_collator=data_collator
這行程式碼,但我們在此處包含它是為了向您展示處理管道的這一重要部分。
📖 瞭解更多:有關 Trainer 類及其引數的全面詳細資訊,請訪問 Trainer API 文件,並在 訓練操作指南食譜 中探索高階使用模式。
要對我們的資料集進行模型微調,我們只需呼叫 Trainer
的 train()
方法。
trainer.train()
這將開始微調(在 GPU 上應該需要幾分鐘)並每 500 步報告訓練損失。但是,它不會告訴您模型表現如何(或多差)。這是因為:
- 我們沒有透過將
TrainingArguments
中的eval_strategy
設定為"steps"
(每eval_steps
評估一次)或"epoch"
(每個 epoch 結束時評估一次)來告知Trainer
在訓練期間進行評估。 - 我們沒有為
Trainer
提供compute_metrics()
函式來在評估期間計算指標(否則評估只會列印損失,這不是一個非常直觀的數字)。
評估
讓我們看看如何構建一個有用的 compute_metrics()
函式,並在下次訓練時使用它。該函式必須接受一個 EvalPrediction
物件(它是一個帶有 predictions
欄位和 label_ids
欄位的命名元組),並將返回一個將字串對映到浮點數的字典(字串是返回的指標名稱,浮點數是其值)。為了從我們的模型中獲得一些預測,我們可以使用 Trainer.predict()
命令。
predictions = trainer.predict(tokenized_datasets["validation"])
print(predictions.predictions.shape, predictions.label_ids.shape)
(408, 2) (408,)
predict()
方法的輸出是另一個命名元組,包含三個欄位:predictions
、label_ids
和 metrics
。metrics
欄位將僅包含傳遞的資料集上的損失,以及一些時間指標(總共和平均預測所需時間)。一旦我們完成 compute_metrics()
函式並將其傳遞給 Trainer
,該欄位還將包含 compute_metrics()
返回的指標。
如您所見,predictions
是一個形狀為 408 x 2 的二維陣列(408 是我們用於預測的資料集中的元素數量)。這些是傳遞給 predict()
的資料集中每個元素的對數(如您在上一章中看到的那樣,所有 Transformer 模型都返回對數)。為了將它們轉換為可以與標籤進行比較的預測,我們需要在第二個軸上取最大值的索引。
import numpy as np
preds = np.argmax(predictions.predictions, axis=-1)
我們現在可以將這些 preds
與標籤進行比較。為了構建我們的 compute_metric()
函式,我們將依賴於 🤗 Evaluate 庫中的指標。我們可以像載入資料集一樣輕鬆地載入與 MRPC 資料集關聯的指標,這次使用 evaluate.load()
函式。返回的物件有一個 compute()
方法,我們可以用它來計算指標。
import evaluate
metric = evaluate.load("glue", "mrpc")
metric.compute(predictions=preds, references=predictions.label_ids)
{'accuracy': 0.8578431372549019, 'f1': 0.8996539792387542}
在 🤗 Evaluate 文件中瞭解不同的評估指標和策略。
您獲得的確切結果可能會有所不同,因為模型頭部的隨機初始化可能會改變其實現的指標。在這裡,我們可以看到我們的模型在驗證集上的準確率達到 85.78%,F1 分數達到 89.97。這些是 GLUE 基準中用於評估 MRPC 資料集結果的兩個指標。BERT 論文中的表格報告基本模型的 F1 分數為 88.9。那是 uncased
模型,而我們目前使用的是 cased
模型,這解釋了更好的結果。
將所有內容整合在一起,我們得到 compute_metrics()
函式:
def compute_metrics(eval_preds):
metric = evaluate.load("glue", "mrpc")
logits, labels = eval_preds
predictions = np.argmax(logits, axis=-1)
return metric.compute(predictions=predictions, references=labels)
要檢視它在每個 epoch 結束時報告指標的實際應用,我們這樣定義一個新的 Trainer
,並傳入這個 compute_metrics()
函式:
training_args = TrainingArguments("test-trainer", eval_strategy="epoch")
model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2)
trainer = Trainer(
model,
training_args,
train_dataset=tokenized_datasets["train"],
eval_dataset=tokenized_datasets["validation"],
data_collator=data_collator,
processing_class=tokenizer,
compute_metrics=compute_metrics,
)
請注意,我們建立了一個新的 TrainingArguments
,並將其 eval_strategy
設定為 "epoch"
,以及一個新模型——否則,我們將只是繼續訓練我們已經訓練過的模型。要啟動新的訓練執行,我們執行:
trainer.train()
這次,除了訓練損失之外,它還將在每個 epoch 結束時報告驗證損失和指標。同樣,您獲得的確切準確率/F1 分數可能與我們發現的略有不同,這是由於模型頭部隨機初始化造成的,但應該在大致相同的範圍內。
高階訓練功能
Trainer
附帶許多內建功能,使現代深度學習的最佳實踐易於訪問:
混合精度訓練:在訓練引數中使用 fp16=True
以加快訓練速度並減少記憶體使用。
training_args = TrainingArguments(
"test-trainer",
eval_strategy="epoch",
fp16=True, # Enable mixed precision
)
梯度累積:當 GPU 記憶體有限時,有效擴大批次大小。
training_args = TrainingArguments(
"test-trainer",
eval_strategy="epoch",
per_device_train_batch_size=4,
gradient_accumulation_steps=4, # Effective batch size = 4 * 4 = 16
)
學習率排程:Trainer 預設使用線性衰減,但您可以自定義。
training_args = TrainingArguments(
"test-trainer",
eval_strategy="epoch",
learning_rate=2e-5,
lr_scheduler_type="cosine", # Try different schedulers
)
🎯 效能最佳化:有關包括分散式訓練、記憶體最佳化和硬體特定最佳化在內的更高階訓練技術,請探索 🤗 Transformers 效能指南。
Trainer
可以在多個 GPU 或 TPU 上開箱即用,並提供許多分散式訓練選項。我們將在第 10 章中詳細介紹其支援的所有功能。
本節結束了使用 Trainer
API 進行微調的介紹。在第 7 章中將給出針對大多數常見 NLP 任務的示例,但現在讓我們看看如何使用純 PyTorch 訓練迴圈來做同樣的事情。
📝 更多示例:檢視 🤗 Transformers 筆記本的綜合集合。
章節測驗
測試您對 Trainer API 和微調概念的理解。
1. <code> processing_class </code> 引數在 Trainer 中的作用是什麼?
2. 哪個 TrainingArguments 引數控制訓練期間評估的頻率?
3. TrainingArguments 中的 <code> fp16=True </code> 啟用了什麼?
4. <code> compute_metrics </code> 函式在 Trainer 中的作用是什麼?
5. 當您不向 Trainer 提供 <code> eval_dataset </code> 時會發生什麼?
6. 什麼是梯度累積,以及如何啟用它?
💡 要點:
Trainer
API 提供了一個高階介面,可以處理大多數訓練的複雜性。- 使用
processing_class
指定分詞器,以正確處理資料。 TrainingArguments
控制訓練的所有方面:學習率、批處理大小、評估策略和最佳化。compute_metrics
允許自定義訓練損失之外的評估指標。- 混合精度(
fp16=True
)和梯度累積等現代功能可以顯著提高訓練效率。