Pytorch
TensorFlow

#
Ajustarea unui model cu Keras

După ce ați efectuat toate lucrările de preprocesare a datelor din ultima secțiune, mai aveți doar câțiva pași de făcut pentru a antrena modelul. Rețineți, totuși, că comanda `model.fit()` va rula foarte lent pe un CPU. Dacă nu aveți un GPU configurat, puteți obține acces gratuit la GPU sau TPU pe Google Colab.

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
    import numpy as np

    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, return_tensors="tf")

    tf_train_dataset = tokenized_datasets["train"].to_tf_dataset(
        columns=["attention_mask", "input_ids", "token_type_ids"],
        label_cols=["labels"],
        shuffle=True,
        collate_fn=data_collator,
        batch_size=8,
    )

    tf_validation_dataset = tokenized_datasets["validation"].to_tf_dataset(
        columns=["attention_mask", "input_ids", "token_type_ids"],
        label_cols=["labels"],
        shuffle=False,
        collate_fn=data_collator,
        batch_size=8,
    )

###
Antrenarea

Modelele TensorFlow importate din 🤗 Transformers sunt deja modele Keras. În cele ce urmează găsiți o scurtă introducere în Keras.

Aceasta înseamnă că, odată ce avem datele noastre, este nevoie de foarte puțină muncă pentru a începe antrenarea pe baza acestora.

Ca și în capitolul anterior, vom folosi clasa `TFAutoModelForSequenceClassification`, cu două etichete:

    from transformers import TFAutoModelForSequenceClassification

    model = TFAutoModelForSequenceClassification.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 preinstruit pentru clasificarea perechilor de propoziții, astfel încât head-ul modelului preinstruit a fost eliminat și a fost introdus î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.

Pentru a realiza fine-tuning-ul modelului pe setul nostru de date, trebuie doar să `compilăm()` modelul nostru și apoi să transmitem datele noastre metodei `fit()`. Aceasta va începe procesul de `fine-tuning` (care ar trebui să dureze câteva minute pe un GPU) și va raporta pierderea de formare pe parcurs, plus pierderea de validare la sfârșitul fiecărei epoci.

Rețineți că modelele 🤗 Transformers au o abilitate specială pe care majoritatea modelelor Keras nu o au - ele pot utiliza automat o valoare adecvată a pierderii pe care o calculează intern. Ele vor utiliza această valoare în mod implicit dacă nu setați un argument de pierdere în `compile()`. Rețineți că pentru a utiliza valoarea internă a pierderii va trebui să transmiteți etichetele ca parte a datelor de intrare, nu ca etichetă separată, care este modul normal de utilizare a etichetelor cu modelele Keras. Veți vedea exemple în acest sens în partea 2 a cursului, unde definirea funcției de pierdere corecte poate fi complicată. Cu toate acestea, pentru clasificarea secvențelor, o funcție de pierdere Keras standard funcționează bine, așa că aceasta este cea pe care o vom utiliza aici.

    from tensorflow.keras.losses import SparseCategoricalCrossentropy

    model.compile(
        optimizer="adam",
        loss=SparseCategoricalCrossentropy(from_logits=True),
        metrics=["accuracy"],
    )
    model.fit(
        tf_train_dataset,
        validation_data=tf_validation_dataset,
    )

Remarcați o problemă foarte des întâlnită aici - puteți doar să transmiteți numele pierderii ca șir de caractere către Keras, dar în mod implicit Keras va presupune că ați aplicat deja un softmax rezultatelor dvs. Cu toate acestea, multe modele produc valorile chiar înainte de aplicarea softmax, care sunt cunoscute și sub numele de logits. Trebuie să spunem funcției de pierdere că asta face modelul nostru, iar singura modalitate de a face acest lucru este să o apelăm direct, mai degrabă decât prin nume cu un șir.

###
Îmbunătățirea performanțelor de instruire

Dacă încercați codul de mai sus, acesta rulează cu siguranță, dar veți constata că valoarea pierderii scade doar lent sau sporadic. Cauza principală este rata de învățare. Ca și în cazul pierderii, atunci când îi transmitem lui Keras numele unui optimizator ca șir de caractere, Keras inițializează optimizatorul respectiv cu valori implicite pentru toți parametrii, inclusiv rata de învățare. Totuși, din experiența îndelungată, știm că modelele transformatoare beneficiază de o rată de învățare mult mai mică decât cea implicită pentru Adam, care este 1e-3, scrisă și ca 10 la puterea -3, sau 0,001. 5e-5 (0,00005), care este de aproximativ douăzeci de ori mai mică, este un punct de plecare mult mai bun.

În plus față de scăderea ratei de învățare, avem un al doilea as în mânecă: putem reduce încet rata de învățare pe parcursul instruirii. În literatura de specialitate, veți vedea uneori că acest lucru este denumit decădere sau analizare a ratei de învățare. În Keras, cel mai bun mod de a face acest lucru este de a utiliza un programator al ratei de învățare. Un program bun de utilizat este `PolynomialDecay` - în ciuda numelui, cu setările implicite, acesta pur și simplu scade liniar rata de învățare de la valoarea inițială până la valoarea finală pe parcursul instruirii, ceea ce este exact ceea ce ne dorim. Pentru a utiliza corect un programator, totuși, trebuie să îi spunem cât va dura antrenamentul. Calculăm acest lucru ca `num_train_steps` mai jos.

    from tensorflow.keras.optimizers.schedules import PolynomialDecay

    batch_size = 8
    num_epochs = 3
    # Numărul etapelor de formare este numărul de eșantioane din setul de date, împărțit la dimensiunea batch-ului, apoi înmulțit
    # cu numărul total de epoci. Rețineți că setul de date tf_train_dataset de aici este un set de date tf.data.Dataset în batch-uri,
    num_train_steps = len(tf_train_dataset) * num_epochs
    lr_scheduler = PolynomialDecay(
        initial_learning_rate=5e-5, end_learning_rate=0.0, decay_steps=num_train_steps
    )
    from tensorflow.keras.optimizers import Adam

    opt = Adam(learning_rate=lr_scheduler)

Biblioteca Transformers 🤗 are, de asemenea, o funcție `create_optimizer()` care va crea un optimizator `AdamW` cu rata de învățare în scădere. Aceasta este o scurtătură convenabilă pe care o veți vedea în detaliu în secțiunile viitoare ale cursului.

Acum avem optimizatorul nostru complet nou și putem încerca să ne antrenăm cu el. În primul rând, să reîncărcăm modelul, pentru a reseta modificările aduse ponderilor în urma instruirii pe care tocmai am efectuat-o, iar apoi îl putem compila cu noul optimizator:

    import tensorflow as tf

    model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2)
    loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
    model.compile(optimizer=opt, loss=loss, metrics=["accuracy"])

Acum, ne potrivim din nou:

    model.fit(tf_train_dataset, validation_data=tf_validation_dataset, epochs=3)

💡 Dacă doriți să încărcați automat modelul dvs. în Hub în timpul instruirii, puteți trece un `PushToHubCallback` în metoda `model.fit()`. Vom afla mai multe despre acest lucru în Capitolul 4

###
Predicțiile modelului

Este foarte interesant să ne antrenăm și să vedem cum scade valoarea pierderii, dar ce se întâmplă dacă dorim să obținem rezultate de la modelul antrenat, fie pentru a calcula anumiți parametri, fie pentru a utiliza modelul în producție? Pentru a face acest lucru, putem folosi metoda `predict()`. Aceasta va returna logit-urile din rezultatele modelului, unul pentru fiecare clasă.

    preds = model.predict(tf_validation_dataset)["logits"]

Putem converti aceste logiți în predicții de clasă ale modelului folosind `argmax` pentru a găsi cel mai mare logit, care corespunde celei mai probabile clase:

    class_preds = np.argmax(preds, axis=1)
    print(preds.shape, class_preds.shape)

    (408, 2) (408,)

Acum, să folosim `preds` pentru a calcula niște indicatori! Putem încărca indicatorii de măsurare asociați 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 folosi pentru a face calculul metric:

    import evaluate

    metric = evaluate.load("glue", "mrpc")
    metric.compute(predictions=class_preds, references=raw_datasets["validation"]["label"])

    {'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ă metrici 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 `uncased`, în timp ce noi folosim în prezent modelul `cased`, ceea ce explică rezultatul mai bun.

Aceasta încheie introducerea la ajustarea fină utilizând API-ul Keras. În Capitolul 7 va fi prezentat un exemplu de efectuare a acestui lucru pentru cele mai comune sarcini NLP. Dacă doriți să vă perfecționați abilitățile cu API-ul Keras, încercați să reglați un model pe setul de date GLUE SST-2, utilizând prelucrarea datelor pe care ați făcut-o în secțiunea 2.

< > Update on GitHub