翻譯自:Fine-tuning a model with the Trainer API
Transformers
提供了一個 Trainer
類,處理微調在資料集上提供的任何預訓練模型。 完成所有資料預處理工作後,只需執行幾個步驟即可定義 Trainer。 最困難的部分可能是準備執行 Trainer.train()
的環境,因為它在 CPU 上執行速度非常慢。 如果沒有設定 GPU,可以在 Google Colab 上存取免費的 GPU 或 TPU。
下面的程式碼範例假設已經完成了資料預處理的操作:
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)
map函數與DataCollatorWithPadding函數請查閱:Processing the data
定義 Trainer
之前的第一步是定義一個 TrainingArguments
類,該類將包含 Trainer
用於訓練和評估的所有超引數。 必須提供的唯一引數是儲存訓練模型的目錄以及checkpoint。 對於其餘所有內容,可以保留預設值,這對於基本的微調應該非常有效。
from transformers import TrainingArguments
training_args = TrainingArguments("test-trainer")
第二步是定義我們的模型。 使用 AutoModelForSequenceClassification 類,它帶有兩個標籤:
from transformers import AutoModelForSequenceClassification
model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2)
一旦我們有了模型,我們就可以通過傳遞迄今為止構建的所有物件來定義 Trainer
---Model
、training_args
、training
和validation datasets
、data_collator
和 tokenizer
:
from transformers import Trainer
trainer = Trainer(
model,
training_args,
train_dataset=tokenized_datasets["train"],
eval_dataset=tokenized_datasets["validation"],
data_collator=data_collator,
tokenizer=tokenizer,
)
要在資料集上微調模型,我們只需呼叫訓練器的 train() 方法:
trainer.train()
這將開始微調(在 GPU 上應該需要幾分鐘)並每 500 步報告一次訓練損失。 但是,它不會告訴你模型的表現有多好(或多差)。 這是因為:
evaluation_strategy
設定為「steps
」(評估每個eval_steps
)或「epoch
」(在每個epoch
結束時評估)來進行評估。compute_metrics()
函數來在所述評估期間計算指標(否則評估只會列印損失,這不是一個非常直觀的數位)。讓我們看看如何構建一個有用的compute_metrics()
函數並在下次訓練時使用它。 該函數必須採用 EvalPrediction
物件(這是一個帶有預測欄位和 label_ids 欄位的命名元組),並將返回一個將字串對映到浮點數的字典(字串是返回的指標的名稱,浮點數是它們的值)。 為了從我們的模型中獲得一些預測,我們可以使用 Trainer.predict()
方法:
predictions = trainer.predict(tokenized_datasets["validation"])
print(predictions.predictions.shape, predictions.label_ids.shape)
## 輸出
(408, 2) (408,)
Predict()
方法的輸出是另一個具有三個欄位的命名元組:預測、label_ids 和指標。 指標欄位將僅包含傳遞的資料集的損失,以及一些時間指標(預測所需的總時間和平均時間)。 一旦我們完成了compute_metrics()
函數並將其傳遞給Trainer,該欄位還將包含compute_metrics()
返回的指標。
結果所展示的預測是一個形狀為 408 x 2 的二維陣列(408 是我們使用的資料集中的元素數量)。 這些是我們傳遞給predict()
的資料集每個元素的logits。 為了將它們轉換為可以與標籤進行比較的預測,我們需要在第二個軸上獲取最大值的索引:
import numpy as np
preds = np.argmax(predictions.predictions, axis=-1)
我們現在可以將這些預測與標籤進行比較。 為了構建我們的compute_metric()
函數,我們將依賴於HuggingFace 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}
獲得的確切結果可能會有所不同,因為Model Head
部分的隨機初始化可能會改變它實現的指標。 在這裡,我們可以看到我們的模型在驗證集上的準確率為 85.78%,F1 得分為 89.97。 這些是用於評估 GLUE 基準的 MRPC 資料集結果的兩個指標。 BERT 論文中的表格報告了基本模型的 F1 分數為 88.9,這是非case的模型,而我們目前使用的是case的模型,這解釋了更好的結果。
將所有內容包裝在一起,我們得到了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結束時報告指標的實際使用情況,下面是我們如何使用這個compute_metrics()
函數定義一個新的Trainer
:
training_args = TrainingArguments("test-trainer", evaluation_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,
tokenizer=tokenizer,
compute_metrics=compute_metrics,
)
請注意,我們建立了一個新的 TrainingArguments
,其評估策略設定為「epoch
」和一個新模型 - 否則,我們將繼續訓練已經訓練過的模型。 要啟動新的訓練執行,我們執行:
trainer.train()
這次,除了訓練損失之外,它將在每個時期結束時報告驗證損失和指標。 同樣,由於模型的Model Head初始化,你達到的確切準確度/F1 分數可能與我們發現的有所不同,但它應該處於相同的範圍內。
Trainer 將在多個 GPU 或 TPU 上開箱即用,並提供許多選項,例如混合精度訓練(在訓練引數中使用 fp16 = True)。