第4篇 微調預訓練模型


微調預訓練模型

使用預訓練模型有很多好處。預訓練模型節省了你的計算開銷、你的碳排放,並且讓你能夠使用sota模型而不需要自己從頭訓練。Hugging Face Transformers為你提供了上千種預訓練模型,可廣泛用於各種任務。當你使用一個預訓練模型,你可以在任務特定數據集上訓練。這就是著名的微調,一種非常厲害的訓練技巧。在本篇教程中,你可以用Pytorch微調一個預訓練模型。

准備一個數據集

在你微調一個預訓練模型之前,下載一個數據集並將其處理成可用於訓練的形式。

首先下載一個Yelp Reviews數據集:

from datasets import load_dataset

dataset = load_dataset("yelp_review_full")
dataset[100]

'''
output:
{'label': 0,
 'text': 'My expectations for McDonalds are t rarely high...}
'''

正如你所知道的那樣,你需要一個分詞器來處理文本以及填充、截斷策略來處理可變序列長度。為了一步處理你的數據集,使用Dataset的map方法,將預處理函數應用在整個數據集上。

from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("bert-base-cased")


def tokenize_function(examples):
    return tokenizer(examples["text"], padding="max_length", truncation=True)


tokenized_datasets = dataset.map(tokenize_function, batched=True)

你還可以使用完整數據集的一個子集來進行微調,這樣可以減少時間。

small_train_dataset = tokenized_datasets["train"].shuffle(seed=42).select(range(1000))
small_eval_dataset = tokenized_datasets["test"].shuffle(seed=42).select(range(1000))

用Trainer進行微調

Hugging Face Transformers提供了一個Trainer類用來優化模型的訓練,不用人工編寫自己的訓練循環就能開始訓練。Trainer AIP支持廣泛的訓練選項和特征,比如:日志、梯度積累、混合精度。

一開始要加載你的模型,並制定期望的標簽數目。從Yelp Review數據集卡片得知,總共有5個標簽:

from transformers import AutoModelForSequenceClassification

model = AutoModelForSequenceClassification.from_pretrained("bert-base-cased", num_labels=5)

你將看到一個“一些預訓練權重沒有被使用,並且一些權重被隨機初始化”的提醒。不用擔心,這非常正常!BERT模型的預訓練頭被丟棄了,取而代之的是一個隨機初始化的分類頭。你將會在你的序列分類任務上微調這個新模型頭,將預訓練模型的知識遷移過去。

訓練超參數

下一步,創建一個TrainingArguments類,這個類包含了你可以調整的所有超參數,以及激活不同訓練選項的標志。在本篇教程中,你可以從默認的訓練超參數開始,然后進一步可以盡情實驗以找到自己最佳的環境。

指定要把訓練產生的checkpoint存到哪個地址:

from transformers import TrainingArguments

training_args = TrainingArguments(output_dir="test_trainer")

評價指標

Trainer不能在訓練過程中自動評價模型的表現。你需要傳給Trainer一個函數來計算和報告指標。Datasets庫提供了一個簡單的accuracy函數,可以通過load_metric()加載。

import numpy as np
from datasets import load_metric

metric = load_metric("accuracy")

在metric上調用compute可以計算模型預測的准確率。在將你的預測值放入comput之前,你需要將預測值轉換為概率(記住所有的transformers模型都返回logits)。

def compute_metrics(eval_pred):
    logits, labels = eval_pred
    predictions = np.argmax(logits, axis=-1)
    return metric.compute(predictions=predictions, references=labels)

如果你希望在微調過程中監控你的評價指標,在訓練參數中指定evaluation_strategy參數,在每一回合最后報告評價指標

from transformers import TrainingArguments

training_args = TrainingArguments(output_dir="test_trainer", evaluation_strategy="epoch")

Trainer

使用你的模型、訓練參數、訓練和測試數據集以及評價函數,創建一個Trainer類。

from transformers import Trainer

trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=small_train_dataset,
    eval_dataset=small_eval_dataset,
    compute_metrics=compute_metrics,
)

然后通過調用train()微調你的模型:

trainer.train()

在原生Pytorch上進行微調

Trainer包含了訓練循環,並允許你使用一行代碼微調模型。對於喜歡使用自己訓練循環的用戶,你可以在原生Pytorch上微調模型。

手工后處理tokenized_dataset

  1. 將text列刪除,因為模型不能直接接收文本作為輸入
tokenized_datasets = tokenized_datasets.remove_columns(["text"])
  1. 將label列重命名為labels,因為模型期望的參數名是labels
tokenized_datasets = tokenized_datasets.rename_column("label", "labels")
  1. 設置數據集的格式,使得返回張量,而不是lists
tokenized_datasets.set_format("torch")

DataLoader

為你的訓練和測試數據集創建一個DataLoader,這樣你可以迭代批次的數據

from torch.utils.data import DataLoader

train_dataloader = DataLoader(small_train_dataset, shuffle=True, batch_size=8)
eval_dataloader = DataLoader(small_eval_dataset, batch_size=8)

優化器和學習率衰減

創建一個優化器和學習率規划器來微調模型。優化器使用AdamW

from torch.optim import AdamW

optimizer = AdamW(model.parameters(), lr=5e-5)

創建一個默認的學習率規划器

from transformers import get_scheduler

num_epochs = 3
num_training_steps = num_epochs * len(train_dataloader)
lr_scheduler = get_scheduler(
    name="linear", optimizer=optimizer, num_warmup_steps=0, num_training_steps=num_training_steps
)

最后,指定device使用GPU

import torch

device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")
model.to(device)

現在,你就可以訓練了。

訓練循環

為了跟蹤你的訓練過程,使用tqdm庫添加一個進度條

from tqdm.auto import tqdm

progress_bar = tqdm(range(num_training_steps))

model.train()
for epoch in range(num_epochs):
    for batch in train_dataloader:
        batch = {k: v.to(device) for k, v in batch.items()}
        outputs = model(**batch)
        loss = outputs.loss
        loss.backward()

        optimizer.step()
        lr_scheduler.step()
        optimizer.zero_grad()
        progress_bar.update(1)

評價指標

和Trainer一樣,在你寫自己的訓練循環時需要做相同的事情。但是這次,你需要將所有批次數據的數值累計起來,在最后計算指標。

metric = load_metric("accuracy")
model.eval()
for batch in eval_dataloader:
    batch = {k: v.to(device) for k, v in batch.items()}
    with torch.no_grad():
        outputs = model(**batch)

    logits = outputs.logits
    predictions = torch.argmax(logits, dim=-1)
    metric.add_batch(predictions=predictions, references=batch["labels"])

metric.compute()


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM