Costruzione di modelli linguistici Una guida passo-passo all’implementazione di BERT

'Guida passo-passo per l'implementazione di BERT costruzione di modelli linguistici'

Introduzione

Nei ultimi anni ci sono stati progressi rapidi nei modelli di machine learning che elaborano il linguaggio. Questi progressi hanno lasciato il laboratorio di ricerca ed iniziano a alimentare alcuni dei principali prodotti digitali. Un ottimo esempio è l’annuncio che i modelli BERT sono ora una forza significativa dietro la ricerca di Google. Google ritiene che questo passo (avanzamenti nella comprensione del linguaggio naturale applicata alla ricerca) rappresenti “il più grande salto degli ultimi cinque anni e uno dei più grandi nella storia della ricerca”. Capiamo cosa è BERT?

BERT significa Bidirectional Encoder Representations from Transformers. Il suo design prevede la pre-formazione di rappresentazioni bidirezionali profonde dal testo non etichettato, basandosi sia sul contesto a sinistra che su quello a destra. Possiamo migliorare il modello BERT pre-arricchito per diverse attività di elaborazione del linguaggio naturale aggiungendo solo uno strato di output aggiuntivo.

Obiettivi di apprendimento

  • Comprendere l’architettura e i componenti di BERT.
  • Imparare le fasi di pre-elaborazione richieste per l’input di BERT e come gestire lunghezze di sequenza di input variabili.
  • Acquisire conoscenze pratiche per implementare BERT utilizzando popolari framework di machine learning come TensorFlow o PyTorch.
  • Imparare come adattare BERT per specifiche attività secondarie, come la classificazione del testo o il riconoscimento delle entità nominate.

Adesso un’altra domanda che sorge è perché ne abbiamo bisogno? Lasciatemi spiegare.

Questo articolo è stato pubblicato come parte del Data Science Blogathon.

Perché abbiamo bisogno di BERT?

Rappresentazione adeguata del linguaggio è la capacità delle macchine di comprendere il linguaggio generale. I modelli senza contesto come word2Vec o Glove generano una singola rappresentazione di incorporamento delle parole per ogni parola nel vocabolario. Ad esempio, il termine “gru” avrebbe la stessa rappresentazione in “gru nel cielo” e in “gru per sollevare oggetti pesanti”. I modelli contestuali rappresentano ogni parola in base alle altre parole nella frase. Quindi BERT è un modello contestuale che cattura queste relazioni in modo bidirezionale.

BERT si basa su lavori recenti e idee intelligenti nella pre-formazione di rappresentazioni contestuali, tra cui Semi-supervised Sequence Learning, Generative Pre-Training, ELMo, il transformer di OpenAI, ULMFit e il transformer. Anche se questi modelli sono tutti unidirezionali o debolmente bidirezionali, BERT è completamente bidirezionale.

Possiamo addestrare i modelli BERT sui nostri dati per uno scopo specifico, come l’analisi dei sentimenti o la risposta alle domande, per fornire previsioni avanzate, o possiamo usarli per estrarre funzionalità linguistiche di alta qualità dai nostri dati testuali. La domanda successiva che sorge è: “Cosa succede dietro tutto questo?” Andiamo avanti per capire meglio.

Qual è l’idea principale dietro tutto questo?

Per capire le idee prima di tutto, dobbiamo conoscere alcune cose come:

  • Cos’è il modellamento del linguaggio?
  • Quale problema stanno cercando di risolvere i modelli di linguaggio?

Prendiamo un esempio: Completa la frase in base al contesto per capire meglio.

Un modello di linguaggio (approccio unidirezionale) completerà questa frase dicendo che le parole sono:

  • carrello
  • coppia

La maggior parte dei partecipanti (80%) sceglierà “coppia”, mentre il 20% selezionerà “carrello”. Entrambe sono legittime, ma quale dovrei considerare? Seleziona la parola appropriata per completare la frase utilizzando diverse tecniche.

Ora entra in gioco BERT, un modello di linguaggio addestrato in modo bidirezionale. Ciò significa che abbiamo una comprensione più profonda del contesto del linguaggio rispetto ai modelli di linguaggio a direzione singola.

Inoltre, BERT si basa sull’architettura del modello Transformer anziché sugli LSTM.

Architettura di BERT

BERT (Bidirectional Encoder Representations from Transformers) è un’architettura di modelli di linguaggio basata su Transformer. È composto da più livelli di auto-attenzione e reti neurali feed-forward. BERT utilizza un approccio bidirezionale per catturare informazioni contestuali dalle parole precedenti e successive in una frase. Ci sono quattro tipi di versioni pre-addestrate di BERT a seconda della scala dell’architettura del modello:

1) BERT-Base (Cased / Un-Cased): 12 livelli, 768 nodi nascosti, 12 attenzione, 110 milioni di parametri

2) BERT-Large (Cased / Un-Cased): 24 strati, 1024 nodi nascosti, 16 teste di attenzione, 340 milioni di parametri

In base alle tue esigenze, puoi selezionare i pesi pre-allenati di BERT. Ad esempio, se non abbiamo accesso a Google TPU, procederemo con i modelli di base. Inoltre, la scelta tra “cased” e “uncased” dipende dal fatto che la maiuscola delle lettere sia utile per il compito in questione. Approfondiamo.

Come funziona?

BERT funziona sfruttando il potere del pre-training non supervisionato seguito da un fine-tuning supervisionato. Questa sezione convertirà due aree: la pre-elaborazione del testo e i compiti di pre-training.

Pre-elaborazione del testo

Un Transformer fondamentale consiste in un encoder per leggere l’input di testo e un decoder per produrre una predizione del compito. Per BERT è necessario solo l’elemento encoder in quanto il suo obiettivo è creare un modello di rappresentazione del linguaggio. L’input dell’encoder BERT è uno stream di token convertiti prima in vettori. Successivamente, la rete neurale li elabora.

Per iniziare, ogni embedding di input combina i seguenti tre embedding:

Gli embedding del token, della segmentazione e della posizione vengono sommati insieme per formare la rappresentazione di input per BERT.

  • Embedding del Token: All’inizio della prima frase viene aggiunto un token [CLS] ai token delle parole di input e dopo ogni frase viene aggiunto un token [SEP].
  • Embedding delle Segmentazioni: Ogni token riceve una marcatura che indica se appartiene alla frase A o alla frase B. Grazie a questo, l’encoder può distinguere quali frasi sono quali.
  • Embedding Posizionali: Ogni token riceve un embedding posizionale per mostrare dove si trova nella frase.

Compiti di Pre-Training

BERT ha già completato due compiti di NLP:

1. Modellazione del Linguaggio Mascherato

La modellazione del linguaggio consiste nel prevedere la parola successiva in una stringa di parole. Nel caso della modellazione del linguaggio mascherato, alcuni token di input vengono casualmente mascherati e solo quei token mascherati vengono predetti anziché il token che segue.

  • Token [MASK]: Questo token indica che un altro token è mancante.
  • Il token mascherato [MASK] non viene sempre utilizzato per sostituire le parole mascherate perché, in tal caso, i token mascherati non sarebbero mai mostrati prima del fine-tuning. Pertanto, viene effettuata una selezione casuale per il 15% dei token. Inoltre, dei token scelti per la mascheratura del 15%:

2. Predizione della Frase Successiva

Il compito di predizione della frase successiva valuta se la seconda frase di una coppia segue effettivamente la prima frase. Si tratta di un problema di classificazione binaria.

Costruire questo lavoro da qualsiasi corpus monolingue è facile. Riconoscere la connessione tra due frasi è utile in quanto è necessario per vari compiti successivi come domanda e risposta e inferenza del linguaggio naturale.

Implementazione di BERT

L’implementazione di BERT (Bidirectional Encoder Representations from Transformers) prevede l’utilizzo di modelli BERT pre-allenati e il fine-tuning su un compito specifico. Questo include la tokenizzazione dei dati di testo, la codifica delle sequenze, la definizione dell’architettura del modello, l’addestramento del modello e la valutazione delle sue prestazioni. L’implementazione di BERT offre potenti capacità di modellazione del linguaggio, consentendo compiti influenti di elaborazione del linguaggio naturale come la classificazione del testo e l’analisi del sentiment. Ecco una lista di passaggi per l’implementazione di BERT:

  • Importa le librerie richieste e il dataset
  • Suddividi il dataset in train/test
  • Importa BERT – base-uncased
  • Tokenizza e codifica le sequenze
  • Lista di Tensori
  • Data Loader
  • Architettura del modello
  • Fine-tuning
  • Esegui le previsioni

Iniziamo con l’enunciato del problema.

Enunciato del problema

L’obiettivo è creare un sistema che possa classificare i messaggi SMS come spam o non spam. Questo sistema mira a migliorare l’esperienza dell’utente e prevenire potenziali minacce alla sicurezza identificando e filtrando accuratamente i messaggi di spam. Il compito consiste nello sviluppare un modello che distingua tra testi di spam e testi legittimi, consentendo una rapida individuazione e azione contro i messaggi indesiderati.

Abbiamo diversi messaggi SMS, che è il problema. La maggior parte di questi messaggi sono autentici. Tuttavia, alcuni di essi sono spam. Il nostro obiettivo è creare un sistema che possa determinare istantaneamente se un testo è spam o meno. Link dataset: ()

Importa le librerie e il dataset necessari

Importa le librerie e il dataset necessari per il compito in questione. Prepara l’ambiente caricando le dipendenze necessarie e rende il dataset disponibile per ulteriori elaborazioni e analisi.

import numpy as np
import pandas as pd
import torch
import torch.nn as nn
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
import transformers
from transformers import AutoModel, BertTokenizerFast

# specifica la GPU
device = torch.device("cuda")

df = pd.read_csv("../input/spamdatatest/spamdata_v2.csv")
df.head()

Il dataset è composto da due colonne: “label” e “text”. La colonna “text” contiene il corpo del messaggio e “label” è una variabile binaria in cui 1 indica spam e 0 rappresenta un messaggio non spam.

# verifica la distribuzione delle classi
df['label'].value_counts(normalize = True)

Dividi il dataset in Train/Test

Divide il dataset in set di train, validation e test.

Dividiamo il dataset in tre parti in base ai parametri forniti utilizzando una libreria come la funzione train_test_split di scikit-learn.

I set risultanti, ovvero train_text, val_text e test_text, sono accompagnati dalle rispettive etichette: train_labels, val_labels e test_labels. Questi set possono essere utilizzati per addestrare, convalidare e testare il modello di machine learning.

Valutare le prestazioni del modello su dati ipotetici consente di valutare i modelli e evitare l’overfitting in modo appropriato.

# divide il dataset di train in set di train, validation e test
train_text, temp_text, train_labels, temp_labels = train_test_split(df['text'], df['label'], 
                                                                    random_state=2018, 
                                                                    test_size=0.3, 
                                                                    stratify=df['label'])


val_text, test_text, val_labels, test_labels = train_test_split(temp_text, temp_labels, 
                                                                random_state=2018, 
                                                                test_size=0.5, 
                                                                stratify=temp_labels)

Importa BERT-Base-Uncased

Il modello pre-addestrato BERT-base viene importato utilizzando la funzione AutoModel.from_pretrained() della libreria Hugging Face Transformers. Ciò consente agli utenti di accedere all’architettura BERT e ai suoi pesi pre-addestrati per potenti compiti di elaborazione del linguaggio.

Viene anche caricato il tokenizzatore BERT utilizzando la funzione BertTokenizerFast.from_pretrained(). Il tokenizzatore è responsabile della conversione del testo di input in token che BERT comprende. Il tokenizzatore “Bert-base-uncased” è specificamente progettato per gestire il testo in minuscolo ed è allineato con il modello pre-addestrato “Bert-base-uncased”.

# importa il modello preaddestrato BERT-base
bert = AutoModel.from_pretrained('bert-base-uncased')

# Carica il tokenizzatore BERT
tokenizer = BertTokenizerFast.from_pretrained('bert-base-uncased')

# ottieni la lunghezza di tutti i messaggi nel set di train
seq_len = [len(i.split()) for i in train_text]

pd.Series(seq_len).hist(bins = 30)

Tokenizza e codifica le sequenze

Come implementa BERT la tokenizzazione?

Per la tokenizzazione, BERT utilizza WordPiece.

Inizializziamo il vocabolario con tutti i singoli caratteri della lingua e poi lo aggiorniamo iterativamente con le combinazioni più frequenti/probabili delle parole esistenti.

Per mantenere la coerenza, la lunghezza della sequenza di input è limitata a 512 caratteri.

Utilizziamo il tokenizer di BERT per tokenizzare e codificare le sequenze nei set di addestramento, validazione e test. Utilizzando la funzione tokenizer.batch_encode_plus(), le sequenze di testo vengono trasformate in token numerici.

Per uniformità nella lunghezza della sequenza, viene stabilita una lunghezza massima di 25 per ogni set. Quando il parametro pad_to_max_length=True è impostato, le sequenze vengono riempite o troncate di conseguenza. Le sequenze più lunghe della lunghezza massima specificata vengono troncate quando il parametro truncation=True è abilitato.

# tokenizzare e codificare le sequenze nel set di addestramento
tokens_train = tokenizer.batch_encode_plus(
    train_text.tolist(),
    max_length = 25,
    pad_to_max_length=True,
    truncation=True
)

# tokenizzare e codificare le sequenze nel set di validazione
tokens_val = tokenizer.batch_encode_plus(
    val_text.tolist(),
    max_length = 25,
    pad_to_max_length=True,
    truncation=True
)

# tokenizzare e codificare le sequenze nel set di test
tokens_test = tokenizer.batch_encode_plus(
    test_text.tolist(),
    max_length = 25,
    pad_to_max_length=True,
    truncation=True
)

Da lista a tensori

Per convertire le sequenze tokenizzate e le etichette corrispondenti in tensori utilizzando PyTorch. La funzione “torch.tensor()” crea tensori dalle sequenze tokenizzate e dalle etichette.

Per ogni set (addestramento, validazione e test), le sequenze di input tokenizzate vengono convertite in tensori utilizzando “torch.tensor(tokens_train[‘input_ids’])”. Allo stesso modo, le maschere di attenzione vengono convertite in tensori utilizzando “torch.tensor(tokens_train[‘attention_mask’])”. Le etichette vengono convertite in tensori utilizzando “torch.tensor(train_labels.tolist())”.

La conversione dei dati in tensori consente un calcolo efficiente e la compatibilità con i modelli PyTorch, consentendo ulteriori elaborazioni e addestramenti utilizzando BERT o altri modelli nell’ecosistema PyTorch.

Convertire le liste in tensori

train_seq = torch.tensor(tokens_train[‘input_ids’]) train_mask = torch.tensor(tokens_train[‘attention_mask’]) train_y = torch.tensor(train_labels.tolist())

val_seq = torch.tensor(tokens_val[‘input_ids’]) val_mask = torch.tensor(tokens_val[‘attention_mask’]) val_y = torch.tensor(val_labels.tolist())

test_seq = torch.tensor(tokens_test[‘input_ids’]) test_mask = torch.tensor(tokens_test[‘attention_mask’]) test_y = torch.tensor(test_labels.tolist())

Data Loader

La creazione di data loader utilizzando le classi TensorDataset, DataLoader, RandomSampler e SequentialSampler di PyTorch. La classe TensorDataset avvolge le sequenze di input, le maschere di attenzione e le etichette in un singolo oggetto dataset.

Utilizziamo RandomSampler per campionare casualmente il set di addestramento, garantendo una rappresentazione diversificata dei dati durante l’addestramento. Al contrario, utilizziamo SequentialSampler per il set di validazione per testare i dati in modo sequenziale.

Per facilitare l’iterazione efficiente e la suddivisione dei dati durante l’addestramento e la validazione, utilizziamo DataLoader. Questo strumento permette la creazione di iteratori sui dataset con una dimensione del batch designata, semplificando il processo.

from torch.utils.data import TensorDataset, DataLoader, RandomSampler, SequentialSampler

#definire una dimensione del batch
batch_size = 32

# avvolgere i tensori
train_data = TensorDataset(train_seq, train_mask, train_y)

# campionatore per campionare i dati durante l'addestramento
train_sampler = RandomSampler(train_data)

# DataLoader per il set di addestramento
train_dataloader = DataLoader(train_data, sampler=train_sampler, batch_size=batch_size)

# avvolgere i tensori
val_data = TensorDataset(val_seq, val_mask, val_y)

# campionatore per campionare i dati durante l'addestramento
val_sampler = SequentialSampler(val_data)

# DataLoader per il set di validazione
val_dataloader = DataLoader(val_data, sampler = val_sampler, batch_size=batch_size)

Architettura del modello

La classe BERT_Arch estende la classe nn.Module e inizializza il modello BERT come parametro. Impostando i parametri del modello BERT in modo che non richiedano gradienti (param.requires_grad = False), ci assicuriamo che solo i parametri dei livelli aggiunti siano addestrati durante il processo di addestramento. Questa tecnica ci consente di sfruttare il modello BERT pre-addestrato per il trasferimento di apprendimento e adattarlo a un compito specifico.

# congelare tutti i parametri
for param in bert.parameters():
    param.requires_grad = False

L’architettura consiste in un livello di dropout, una funzione di attivazione ReLU, due livelli densi (con rispettivamente 768 e 512 unità) e una funzione di attivazione softmax. Il metodo forward prende gli ID delle frasi e le maschere come input, li passa attraverso il modello BERT per ottenere l’output dal token di classificazione (cls_hs) e applica quindi i livelli e le attivazioni definite per produrre le probabilità finali di classificazione.

class BERT_Arch(nn.Module):

    def __init__(self, bert):
        super(BERT_Arch, self).__init__()
        
        self.bert = bert 
        
        # livello di dropout
        self.dropout = nn.Dropout(0.1)
      
        # funzione di attivazione ReLU
        self.relu =  nn.ReLU()

        # primo livello denso
        self.fc1 = nn.Linear(768,512)
      
        # secondo livello denso (livello di output)
        self.fc2 = nn.Linear(512,2)

        # funzione di attivazione softmax
        self.softmax = nn.LogSoftmax(dim=1)

    #definire il passaggio in avanti
    def forward(self, sent_id, mask):
        
        #passare gli input al modello  
        _, cls_hs = self.bert(sent_id, attention_mask=mask, return_dict=False)
      
        x = self.fc1(cls_hs)

        x = self.relu(x)

        x = self.dropout(x)

        # livello di output
        x = self.fc2(x)
      
        # applicare la funzione di attivazione softmax
        x = self.softmax(x)

        return x

Per inizializzare un’istanza della classe BERT_Arch con il modello BERT come argomento, passiamo il modello BERT pre-addestrato all’architettura definita, BERT_Arch. In questo modo, il modello BERT viene utilizzato come base dell’architettura personalizzata.

Accelerazione GPU

Il modello viene spostato sulla GPU chiamando il metodo to() e specificando il dispositivo desiderato (device) per sfruttare l’accelerazione GPU. Ciò consente di eseguire calcoli più veloci durante l’addestramento e l’inferenza utilizzando le capacità di elaborazione parallela della GPU.

# passare il modello BERT pre-addestrato alla nostra architettura definita
model = BERT_Arch(bert)

# spingere il modello sulla GPU
model = model.to(device)

L’ottimizzatore AdamW dalla libreria Transformers di Hugging Face viene importato per effettuare l’ottimizzazione dei pesi. AdamW è una variante dell’ottimizzatore Adam che include una regolarizzazione del peso.

L’ottimizzatore viene quindi definito passando i parametri del modello (model.parameters()) e il tasso di apprendimento (lr) di 1e-5 al costruttore dell’ottimizzatore AdamW. Questo ottimizzatore aggiornerà i parametri del modello durante l’addestramento, ottimizzando le prestazioni del modello per il compito in questione.

# ottimizzatore da hugging face transformers
from transformers import AdamW

# definire l’ottimizzatore
optimizer = AdamW(model.parameters(),lr = 1e-5)

La funzione compute_class_weight dal modulo sklearn.utils.class_weight viene utilizzata per calcolare i pesi delle classi con più parametri per le etichette di addestramento.

from sklearn.utils.class_weight import compute_class_weight

# calcolare i pesi delle classi
class_weights = compute_class_weight(‘balanced’, np.unique(train_labels), train_labels)

print(“Class Weights:”,class_weights)

Per convertire i pesi delle classi in un tensore, spostarli sulla GPU e definire la funzione di perdita con pesi di classe ponderati. Il numero di epoche di addestramento è impostato su 10.

# convertire la lista dei pesi delle classi in un tensore
weights= torch.tensor(class_weights,dtype=torch.float)

# spingere sulla GPU
weights = weights.to(device)

# definire la funzione di perdita
cross_entropy  = nn.NLLLoss(weight=weights) 

# numero di epoche di addestramento
epochs = 10

Fine-Tune

Una funzione di addestramento che itera su batch di dati esegue passaggi in avanti e all’indietro, aggiorna i parametri del modello e calcola la perdita di addestramento. La funzione memorizza anche le previsioni del modello e restituisce la perdita media e le previsioni.

# funzione per addestrare il modello
def train():
    
    model.train()
    total_loss, total_accuracy = 0, 0
  
    # lista vuota per salvare le previsioni del modello
    total_preds=[]
  
    # iterare sui batch
    for step,batch in enumerate(train_dataloader):
        
        # aggiornamento progressivo dopo ogni 50 batch.
        if step % 50 == 0 and not step == 0:
            print('  Batch {:>5,}  di  {:>5,}.'.format(step, len(train_dataloader)))
        
        # spingere il batch sulla GPU
        batch = [r.to(device) for r in batch]
 
        sent_id, mask, labels = batch
        
        # cancellare i gradienti calcolati in precedenza 
        model.zero_grad()        

        # ottenere le previsioni del modello per il batch corrente
        preds = model(sent_id, mask)

        # calcolare la perdita tra i valori effettivi e previsti
        loss = cross_entropy(preds, labels)

        # aggiungere la perdita totale
        total_loss = total_loss + loss.item()

        # passaggio all'indietro per calcolare i gradienti
        loss.backward()

        # limitare i gradienti a 1.0. Ciò aiuta a prevenire il problema del gradiente esplosivo
        torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)

        # aggiornare i parametri
        optimizer.step()

        # le previsioni del modello sono memorizzate sulla GPU. Quindi spingerle sulla CPU
        preds=preds.detach().cpu().numpy()

    # aggiungere le previsioni del modello
    total_preds.append(preds)

    # calcolare la perdita di addestramento dell'epoca
    avg_loss = total_loss / len(train_dataloader)
  
      # le previsioni sono nella forma (numero di batch, dimensione del batch, numero di classi).
      # ridimensionare le previsioni nella forma (numero di campioni, numero di classi)
    total_preds  = np.concatenate(total_preds, axis=0)

    # restituire la perdita e le previsioni
    return avg_loss, total_preds

Una funzione di valutazione che valuta il modello sui dati di validazione. Calcola la perdita di validazione, memorizza le previsioni del modello e restituisce la perdita media e le previsioni. La funzione disattiva i dropout layer e esegue passaggi in avanti senza calcolare il gradiente utilizzando torch.no_grad().

# funzione per valutare il modello
def valuta():
    
    print("\nValutazione...")
  
    # disattiva i dropout layer
    model.eval()

    total_loss, total_accuracy = 0, 0
    
    # lista vuota per salvare le previsioni del modello
    total_preds = []

    # itera sui batch
    for step,batch in enumerate(val_dataloader):
        
        # Aggiornamento progressivo ogni 50 batch.
        if step % 50 == 0 and not step == 0:
            
            # Calcola il tempo trascorso in minuti.
            elapsed = format_time(time.time() - t0)
            
            # Segnala il progresso.
            print('  Batch {:>5,}  di  {:>5,}.'.format(step, len(val_dataloader)))

        # sposta il batch sulla gpu
        batch = [t.to(device) for t in batch]

        sent_id, mask, labels = batch

        # disattiva autograd
        with torch.no_grad():
            
            # previsioni del modello
            preds = model(sent_id, mask)

            # calcola la perdita di validazione tra i valori attuali e previsti
            loss = cross_entropy(preds,labels)

            total_loss = total_loss + loss.item()

            preds = preds.detach().cpu().numpy()

            total_preds.append(preds)

    # calcola la perdita di validazione dell'epoca
    avg_loss = total_loss / len(val_dataloader) 

    # ridimensiona le previsioni nella forma (numero di campioni, numero di classi)
    total_preds  = np.concatenate(total_preds, axis=0)

    return avg_loss, total_preds

Allenare il Modello

Per allenare il modello per il numero specificato di epoche. Traccia la migliore perdita di validazione, salva i pesi del modello se la perdita di validazione corrente è migliore e aggiunge le perdite di allenamento e validazione alle rispettive liste. Le perdite di allenamento e validazione vengono stampate per ogni epoca.

# impostare la perdita iniziale a infinito
best_valid_loss = float('inf')

# definizione delle epoche
epochs = 1

# liste vuote per memorizzare la perdita di allenamento e validazione di ogni epoca
train_losses=[]
valid_losses=[]

# per ogni epoca
for epoch in range(epochs):
     
    print('\n Epoca {:} / {:}'.format(epoch + 1, epochs))
    
    # allenare il modello
    train_loss, _ = train()
    
    # valutare il modello
    valid_loss, _ = valuta()
    
    # salvare il miglior modello
    if valid_loss < best_valid_loss:
        best_valid_loss = valid_loss
        torch.save(model.state_dict(), 'saved_weights.pt')
    
    # aggiungere la perdita di allenamento e validazione
    train_losses.append(train_loss)
    valid_losses.append(valid_loss)
    
    print(f'\n Perdita di Allenamento: {train_loss:.3f}')
    print(f' Perdita di Validazione: {valid_loss:.3f}')

Per caricare i migliori pesi del modello dal file salvato ‘saved_weights.pt’ utilizzando torch.load() e impostarli nel modello utilizzando model.load_state_dict().

#carica i pesi del miglior modello path = ‘saved_weights.pt’ model.load_state_dict(torch.load(path))

Effettuare Previsioni

Per effettuare previsioni sui dati di test utilizzando il modello addestrato e convertire le previsioni in array NumPy. Calcoliamo le metriche di classificazione, inclusa la precisione, il richiamo e l’F1-score, per valutare le prestazioni del modello utilizzando la funzione classification_report del modulo metrics di scikit-learn.

# ottieni le previsioni per i dati di test
with torch.no_grad():
    preds = model(test_seq.to(device), test_mask.to(device))
    preds = preds.detach().cpu().numpy()

# prestazioni del modello
preds = np.argmax(preds, axis = 1)
print(classification_report(test_y, preds))

Conclusion

In conclusione, BERT è senza dubbio una svolta nell’utilizzo dell’Apprendimento Automatico per l’Elaborazione del Linguaggio Naturale. Il fatto che sia accessibile e consenta un rapido fine-tuning probabilmente permetterà una vasta gamma di applicazioni pratiche in futuro. Questo tutorial di implementazione passo-passo di BERT permette agli utenti di costruire potenti modelli di linguaggio in grado di comprendere e generare correttamente il linguaggio naturale.

Ecco alcuni punti critici su BERT:

  • Il successo di BERT: BERT ha rivoluzionato il campo dell’elaborazione del linguaggio naturale con la sua capacità di catturare rappresentazioni contestualizzate profonde, portando a notevoli miglioramenti delle prestazioni in varie attività di NLP.
  • Accessibilità per tutti: Questo tutorial mira a rendere l’implementazione di BERT accessibile a una vasta gamma di utenti, indipendentemente dal loro livello di competenza. Seguendo la guida passo-passo, chiunque può sfruttare il potere di BERT e costruire modelli di linguaggio sofisticati.
  • Applicazioni nel mondo reale: La versatilità di BERT permette la sua applicazione a problemi reali in diversi settori, compresi l’analisi del sentiment dei clienti, i chatbot, i sistemi di raccomandazione e altro ancora. La sua implementazione può fornire vantaggi e conoscenze tangibili per le aziende e i ricercatori.

Domande frequenti

I media mostrati in questo articolo non sono di proprietà di Analytics Vidhya e sono utilizzati a discrezione dell’autore.