LLM Course documentation
Ajustarea unui model folosind Trainer API
Ajustarea unui model folosind Trainer API
🤗 Transformers oferă o clasă Trainer
pentru a vă ajuta să reglați mai bine oricare dintre modelele preinstruite pe care le oferă pe setul dvs. de date. După ce ați făcut toată munca de preprocesare a datelor din ultima secțiune, vă mai rămân doar câțiva pași pentru a defini clasa Trainer
. Cea mai dificilă parte va fi probabil pregătirea mediului pentru a rula Trainer.train()
, deoarece acesta va rula foarte lent pe un CPU. Dacă nu aveți un GPU configurat, puteți obține acces gratuit la GPU-uri sau TPU-uri pe [Google Colab] (https://colab.research.google.com/).
Exemplele de cod de mai jos presupun că ați executat deja exemplele din secțiunea anterioară. Iată un scurt rezumat care recapitulează ceea ce aveți nevoie:
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)
Antrenarea
Primul pas înainte de a ne defini modelul Trainer
este să definim o clasă TrainingArguments
care va conține toți hiperparametrii pe care Trainer
îi va utiliza pentru formare și evaluare. Singurul argument pe care trebuie să îl furnizați este un folder în care va fi salvat modelul antrenat, precum și punctele de control de pe parcurs. Pentru tot restul, puteți lăsa valorile implicite, care ar trebui să funcționeze destul de bine pentru o ajustare de bază.
from transformers import TrainingArguments
training_args = TrainingArguments("test-trainer")
💡 Dacă doriți să încărcați automat modelul în Hub în timpul instruirii, treceți push_to_hub=True
în TrainingArguments
. Vom afla mai multe despre acest lucru în Capitolul 4.
Al doilea pas este să ne definim modelul. Ca și în capitolul anterior, vom folosi clasa AutoModelForSequenceClassification
, cu două etichete:
from transformers import AutoModelForSequenceClassification
model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2)
Veți observa că, spre deosebire de Capitolul 2, veți primi un avertisment după instanțierea acestui model preinstruit. Acest lucru se datorează faptului că BERT nu a fost instruit în prealabil cu privire la clasificarea perechilor de propoziții, astfel încât head-ul modelului instruit în prealabil a fost eliminat și a fost adăugat în schimb un nou head adecvat pentru clasificarea secvențelor. Avertizările indică faptul că unele ponderi nu au fost utilizate (cele corespunzătoare head-ului de preformare eliminat) și că altele au fost inițializate aleatoriu (cele pentru noul head). În încheiere, vă încurajează să antrenați modelul, ceea ce vom face acum.
Odată ce avem modelul nostru, putem defini un Trainer
transmițându-i toate obiectele construite până acum - modelul
, training_args
, seturile de date de formare și validare, data_collator
și 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,
)
Rețineți că atunci când treceți tokenizer
așa cum am făcut aici, data_collator
implicit folosit de Trainer
va fi un DataCollatorWithPadding
așa cum a fost definit anterior, deci puteți sări peste linia data_collator=data_collator
în acest apel. Era totuși important să vă arăt această parte a procesării în secțiunea 2!
Pentru a regla cu precizie modelul pe setul nostru de date, trebuie doar să apelăm metoda train()
a Trainer
:
trainer.train()
Acest lucru va începe reglarea fină (care ar trebui să dureze câteva minute pe un GPU) și va raporta valoarea pierderii de formare la fiecare 500 de pași. Cu toate acestea, nu vă va spune cât de bine (sau rău) funcționează modelul dumneavoastră. Acest lucru se datorează faptului că:
- Nu am precizat că
Trainer
trebuie să evalueze în timpul antrenamentului prin setareaevaluation_strategy
la„steps”
(evaluare la fiecareeval_steps
) sau„epoch”
(evaluare la sfârșitul fiecărei epoch). - Nu am furnizat pentru
Trainer
o funcțiecompute_metrics()
pentru a calcula o valoare metrică în timpul evaluării (altfel evaluarea ar fi afișat doar pierderea, care nu este un număr foarte intuitiv).
Evaluarea
Să vedem cum putem construi o funcție utilă compute_metrics()
și să o folosim data viitoare când ne antrenăm. Funcția trebuie să preia un obiect EvalPrediction
(care este un tuple numit cu un câmp predictions
și un câmp label_ids
) și va returna un dicționar care mapează șiruri de caractere în valori float. Pentru a obține unele predicții de la modelul nostru, putem utiliza comanda Trainer.predict()
:
predictions = trainer.predict(tokenized_datasets["validation"])
print(predictions.predictions.shape, predictions.label_ids.shape)
(408, 2) (408,)
Rezultatul metodei predict()
este un alt tuple numit cu trei câmpuri: predictions
, label_ids
și metrics
. Câmpul metrics
va conține doar pierderea pe setul de date transmis, precum și unele valori metrice de timp (cât timp a durat predicția, în total și în medie). După ce vom finaliza funcția compute_metrics()
și o vom transmite către Trainer
, acest câmp va conține și metrica returnată de compute_metrics()
.
După cum puteți vedea, predictions
este un array bidimensional cu forma 408 x 2 (408 fiind numărul de elemente din setul de date pe care l-am folosit). Acestea sunt logits pentru fiecare element al setului de date pe care l-am transmis la predict()
(după cum ați văzut în capitolul anterior, toate modelele Transformer returnează logits). Pentru a le transforma în predicții pe care le putem compara cu etichetele noastre, trebuie să luăm indicele cu valoarea maximă pe a doua axă:
import numpy as np
preds = np.argmax(predictions.predictions, axis=-1)
Acum putem compara preds
cu etichetele. Pentru a construi funcția noastră compute_metric()
, ne vom baza pe valorile metrice din biblioteca 🤗 Evaluate. Putem încărca valorile metrice asociate cu setul de date MRPC la fel de ușor cum am încărcat setul de date, de data aceasta cu funcția evaluate.load()
. Obiectul returnat are o metodă compute()
pe care o putem utiliza pentru a efectua calculul metric:
import evaluate
metric = evaluate.load("glue", "mrpc")
metric.compute(predictions=preds, references=predictions.label_ids)
{'accuracy': 0.8578431372549019, 'f1': 0.8996539792387542}
Rezultatele exacte pe care le obțineți pot varia, deoarece inițializarea aleatorie a head-ului modelului poate schimba parametrii obținuți. Aici, putem vedea că modelul nostru are o precizie de 85,78% pe setul de validare și un scor F1 de 89,97. Acestea sunt cele două valori metrice utilizate pentru a evalua rezultatele pe setul de date MRPC pentru criteriul de referință GLUE. Tabelul din [lucrarea BERT] (https://arxiv.org/pdf/1810.04805.pdf) a raportat un scor F1 de 88,9 pentru modelul de bază. Acesta a fost modelul „fără casare”, în timp ce noi folosim în prezent modelul „cu casare”, ceea ce explică rezultatul mai bun.
Adunând totul, obținem funcția noastră 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)
Și pentru a vedea cum se utilizează în practică pentru a raporta datele metrice la sfârșitul fiecărei perioade, iată cum definim un nou Trainer
cu această funcție compute_metrics()
:
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,
)
Rețineți că creăm un nou TrainingArguments
cu evaluation_strategy
setat la „epoch”
și un nou model - în caz contrar, am continua doar instruirea modelului pe care l-am instruit deja. Pentru a lansa o nouă rulare de formare, executăm:
trainer.train()
De data aceasta, acesta va raporta pierderea de validare și metrica la sfârșitul fiecărei perioade, pe lângă valoarea pierderii de formare. Din nou, scorul exact de acuratețe/F1 pe care îl veți obține ar putea fi puțin diferit de ceea ce am găsit noi, din cauza inițializării aleatorii a modelului, dar ar trebui să fie în aceeași zonă.
Modelul Trainer
va funcționa din start pe mai multe GPU sau TPU și oferă o mulțime de opțiuni, cum ar fi formarea cu precizie mixtă (utilizați fp16 = True
în argumentele de formare). Vom trece în revistă toate funcțiile pe care le suportă în capitolul 10.
Aceasta încheie introducerea la reglarea fină cu ajutorul API-ului Trainer
. În Capitolul 7 va fi prezentat un exemplu de efectuare a acestei operații pentru cele mai comune sarcini NLP, dar pentru moment să analizăm cum se poate face același lucru în PyTorch pur.
✏️ Încercați! Ajustați un model pe setul de date GLUE SST-2, folosind procesarea datelor efectuată în secțiunea 2.