GPT2 per la classificazione del testo utilizzando trasformatori di volti abbraccianti

Nodo di origine: 809063

classificazione del testo

Questo notebook viene utilizzato per mettere a punto il modello GPT2 per la classificazione del testo utilizzando Abbracciare il viso trasformatori libreria su un set di dati personalizzato.

Hugging Face è molto carino per noi includere tutte le funzionalità necessarie per GPT2 da utilizzare nelle attività di classificazione. Grazie Hugging Face!

Non sono riuscito a trovare molte informazioni su come utilizzare GPT2 per la classificazione, quindi ho deciso di realizzare questo tutorial utilizzando una struttura simile con altri modelli di trasformatori.

Se questo contenuto educativo approfondito è utile per te, iscriviti alla nostra mailing list di ricerca sull'IA per essere avvisato quando rilasciamo nuovo materiale. 

Idea principale: Poiché GPT2 è un trasformatore di decodifica, l'ultimo token della sequenza di input viene utilizzato per fare previsioni sul token successivo che dovrebbe seguire l'input. Ciò significa che l'ultimo token della sequenza di input contiene tutte le informazioni necessarie nella previsione. Tenendo presente questo, possiamo usare queste informazioni per fare una previsione in un'attività di classificazione invece che in un'attività di generazione.

In altre parole, invece di utilizzare il primo incorporamento di token per fare previsioni come facciamo in Bert, useremo l'ultimo incorporamento di token per fare previsioni con GPT2.

Dato che ci interessava solo il primo token in Bert, stavamo andando verso destra. Ora in GPT2 stiamo usando l'ultimo token per la previsione, quindi dovremo pad a sinistra. Grazie a un bell'aggiornamento a HuggingFace Transformers siamo in grado di configurare GPT2 Tokenizer per fare proprio questo.

Cosa dovrei sapere per questo taccuino?

Dato che sto usando PyTorch per mettere a punto i nostri modelli di trasformatori, qualsiasi conoscenza su PyTorch è molto utile.

Conoscere un po 'di trasformatori anche la biblioteca aiuta.

Come usare questo taccuino?

Come con ogni progetto, ho costruito questo taccuino pensando alla riusabilità.

Tutte le modifiche avverranno nella parte dell'elaborazione dei dati in cui è necessario personalizzare PyTorch Dataset, Data Collator e DataLoader per soddisfare le proprie esigenze di dati.

Tutti i parametri che possono essere modificati si trovano sotto il file Importazioni sezione. Ogni parametro è ben commentato e strutturato per essere il più intuitivo possibile.

dataset

Questo notebook coprirà i trasformatori di pre-addestramento su un set di dati personalizzato. Userò le ben note recensioni di film con etichette positive - negative Set di dati di recensioni di film di grandi dimensioni.

La descrizione fornita sul sito web di Stanford:

Si tratta di un set di dati per la classificazione del sentiment binario contenente sostanzialmente più dati rispetto ai precedenti set di dati di benchmark. Forniamo una serie di 25,000 recensioni di film altamente polari per la formazione e 25,000 per i test. Sono disponibili anche dati aggiuntivi senza etichetta da utilizzare. Vengono forniti testo grezzo e formati di bag of words già elaborati. Vedere il file README contenuto nel rilascio per maggiori dettagli.

Perché questo set di dati? Credo che sia un set di dati di facile comprensione e utilizzo per la classificazione. Penso che lavorare con i dati sul sentiment sia sempre divertente.

codifica

Ora facciamo un po 'di programmazione! Esamineremo ogni cella di codifica nel notebook e descriveremo cosa fa, qual è il codice e quando è rilevante - mostra l'output.

Ho reso questo formato facile da seguire se decidi di eseguire ogni cella di codice nel tuo notebook Python.

Quando imparo da un tutorial cerco sempre di replicare i risultati. Credo che sia facile da seguire se hai il codice accanto alle spiegazioni.

Scarica

Scarica la Set di dati di recensioni di film di grandi dimensioni e decomprimilo localmente.

Download the dataset.
!wget -q -nc http://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz
Unzip the dataset.
!tar -zxf /content/aclImdb_v1.tar.gz

Installazioni

  • trasformatori la libreria deve essere installata per utilizzare tutto il fantastico codice di Hugging Face. Per ottenere l'ultima versione la installerò direttamente da GitHub.
  • ml_cose libreria utilizzata per varie attività correlate all'apprendimento automatico. Ho creato questa libreria per ridurre la quantità di codice che devo scrivere per ogni progetto di machine learning.
# Install transformers library.
!pip install -q git+https://github.com/huggingface/transformers.git
# Install helper functions.
!pip install -q git+https://github.com/gmihaila/ml_things.git
Installing build dependencies ... done Getting requirements to build wheel ... done Preparing wheel metadata ... done |████████████████████████████████| 2.9MB 6.7MB/s |████████████████████████████████| 890kB 48.9MB/s |████████████████████████████████| 1.1MB 49.0MB/s Building wheelfor transformers (PEP 517) ... done Building wheel for sacremoses (setup.py) ... done |████████████████████████████████| 71kB 5.2MB/s Building wheel for ml-things (setup.py) ... done Building wheel for ftfy (setup.py) ... done

Importazioni

Importa tutte le librerie necessarie per questo notebook.Dichiarare i parametri utilizzati per questo notebook:

  • set_seed(123) - Sempre bene impostare un seme fisso per la riproducibilità.
  • epochs - Numero di periodi di formazione (gli autori consigliano tra 2 e 4).
  • batch_size - Numero di batch, a seconda della lunghezza massima della sequenza e della memoria della GPU. Per la lunghezza di 512 sequenze, un lotto di 10 di solito funziona senza problemi di memoria cuda. Per piccole sequenze di lunghezza puoi provare un lotto di 32 o superiore. max_length - Riempie o tronca le sequenze di testo a una lunghezza specifica. Lo imposterò a 60 per accelerare l'allenamento.
  • device - Cerca la GPU da usare. Utilizzerà la CPU per impostazione predefinita se non viene trovata alcuna GPU.
  • model_name_or_path - Nome del modello dei trasformatori - utilizzerà il modello già pre-addestrato. Percorso del modello del trasformatore: caricherà il tuo modello dal disco locale. In questo tutorial userò gpt2 modello.
  • labels_ids - Dizionario delle etichette e il loro ID: questo verrà utilizzato per convertire le etichette delle stringhe in numeri.
  • n_labels - Quante etichette stiamo usando in questo set di dati. Viene utilizzato per decidere la dimensione della testa di classificazione.
import io
import os
import torch
from tqdm.notebook import tqdm
from torch.utils.data import Dataset, DataLoader
from ml_things import plot_dict, plot_confusion_matrix, fix_text
from sklearn.metrics import classification_report, accuracy_score
from transformers import (set_seed, TrainingArguments, Trainer, GPT2Config, GPT2Tokenizer, AdamW, get_linear_schedule_with_warmup, GPT2ForSequenceClassification) # Set seed for reproducibility.
set_seed(123) # Number of training epochs (authors on fine-tuning Bert recommend between 2 and 4).
epochs = 4 # Number of batches - depending on the max sequence length and GPU memory.
# For 512 sequence length batch of 10 works without cuda memory issues.
# For small sequence length can try batch of 32 or higher.
batch_size = 32 # Pad or truncate text sequences to a specific length
# if `None` it will use maximum sequence of word piece tokens allowed by model.
max_length = 60 # Look for gpu to use. Will use `cpu` by default if no gpu found.
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # Name of transformers model - will use already pretrained model.
# Path of transformer model - will load your own model from local disk.
model_name_or_path = 'gpt2' # Dictionary of labels and their id - this will be used to convert.
# String labels to number ids.
labels_ids = {'neg': 0, 'pos': 1} # How many labels are we using in training.
# This is used to decide size of classification head.
n_labels = len(labels_ids)

Funzioni di supporto

Mi piace mantenere tutte le classi e le funzioni che verranno utilizzate in questo taccuino in questa sezione per aiutare a mantenere un aspetto pulito del taccuino:

MovieReciewsDataset (Dataset)

Se hai già lavorato con PyTorch, questo è abbastanza standard. Abbiamo bisogno di questa classe per leggere nel nostro set di dati, analizzarlo e restituire testi con le etichette associate.

In questa classe ho solo bisogno di leggere il contenuto di ogni file, usare fix_text per risolvere eventuali problemi Unicode e tenere traccia dei sentimenti positivi e negativi.

Aggiungerò tutti i testi e le etichette negli elenchi.

Ci sono tre parti principali di questa classe PyTorch Dataset:

  • dentro() dove leggiamo nel set di dati e trasformiamo testo ed etichette in numeri.
  • len () dove dobbiamo restituire il numero di esempi che abbiamo letto. Viene usato quando si chiama len (MovieReviewsDataset ()).
  • getitem () prende sempre come input un valore int che rappresenta quale esempio dai nostri esempi restituire dal nostro set di dati. Se viene passato un valore di 3, restituiremo l'esempio dal nostro set di dati alla posizione 3.
class MovieReviewsDataset(Dataset): r"""PyTorch Dataset class for loading data. This is where the data parsing happens. This class is built with reusability in mind: it can be used as is as. Arguments: path (:obj:`str`): Path to the data partition. """ def __init__(self, path, use_tokenizer): # Check if path exists. if not os.path.isdir(path): # Raise error if path is invalid. raise ValueError('Invalid `path` variable! Needs to be a directory') self.texts = [] self.labels = [] # Since the labels are defined by folders with data we loop # through each label. for label in ['pos', 'neg']: sentiment_path = os.path.join(path, label) # Get all files from path. files_names = os.listdir(sentiment_path)#[:10] # Sample for debugging. # Go through each file and read its content. for file_name in tqdm(files_names, desc=f'{label} files'): file_path = os.path.join(sentiment_path, file_name) # Read content. content = io.open(file_path, mode='r', encoding='utf-8').read() # Fix any unicode issues. content = fix_text(content) # Save content. self.texts.append(content) # Save encode labels. self.labels.append(label) # Number of exmaples. self.n_examples = len(self.labels) return def __len__(self): r"""When used `len` return the number of examples. """ return self.n_examples def __getitem__(self, item): r"""Given an index return an example from the position. Arguments: item (:obj:`int`): Index position to pick an example to return. Returns: :obj:`Dict[str, str]`: Dictionary of inputs that contain text and asociated labels. """ return {'text':self.texts[item], 'label':self.labels[item]}

Gpt2ClassificationCollator

Uso questa classe per creare il Data Collator. Questo verrà utilizzato nel DataLoader per creare i bagni di dati che vengono forniti al modello. Uso il tokenizer e il codificatore di etichette su ogni sequenza per convertire testi ed etichette in numeri.

Fortunatamente per noi, Hugging Face ha pensato a tutto e ha fatto fare al tokenizer tutto il lavoro pesante (dividere il testo in token, riempire, troncare, codificare il testo in numeri) ed è molto facile da usare!

Esistono due parti principali di questa classe Data Collator:

  • dentro() dove inizializziamo il tokenizer che intendiamo utilizzare, come codificare le nostre etichette e se dobbiamo impostare la lunghezza della sequenza su un valore diverso.
  • chiamata() usato come funzione collator che prende come input un batch di esempi di dati. Deve restituire un oggetto con il formato che può essere fornito al nostro modello. Fortunatamente il nostro tokenizer lo fa per noi e restituisce un dizionario di variabili pronte per essere fornite al modello in questo modo: model(**inputs). Dato che stiamo mettendo a punto il modello, ho incluso anche le etichette.
class Gpt2ClassificationCollator(object): r""" Data Collator used for GPT2 in a classificaiton rask. It uses a given tokenizer and label encoder to convert any text and labels to numbers that can go straight into a GPT2 model. This class is built with reusability in mind: it can be used as is as long as the `dataloader` outputs a batch in dictionary format that can be passed straight into the model - `model(**batch)`. Arguments: use_tokenizer (:obj:`transformers.tokenization_?`): Transformer type tokenizer used to process raw text into numbers. labels_ids (:obj:`dict`): Dictionary to encode any labels names into numbers. Keys map to labels names and Values map to number associated to those labels. max_sequence_len (:obj:`int`, `optional`) Value to indicate the maximum desired sequence to truncate or pad text sequences. If no value is passed it will used maximum sequence size supported by the tokenizer and model. """ def __init__(self, use_tokenizer, labels_encoder, max_sequence_len=None): # Tokenizer to be used inside the class. self.use_tokenizer = use_tokenizer # Check max sequence length. self.max_sequence_len = use_tokenizer.model_max_length if max_sequence_len is None else max_sequence_len # Label encoder used inside the class. self.labels_encoder = labels_encoder return def __call__(self, sequences): r""" This function allowes the class objesct to be used as a function call. Sine the PyTorch DataLoader needs a collator function, I can use this class as a function. Arguments: item (:obj:`list`): List of texts and labels. Returns: :obj:`Dict[str, object]`: Dictionary of inputs that feed into the model. It holddes the statement `model(**Returned Dictionary)`. """ # Get all texts from sequences list. texts = [sequence['text'] for sequence in sequences] # Get all labels from sequences list. labels = [sequence['label'] for sequence in sequences] # Encode all labels using label encoder. labels = [self.labels_encoder[label] for label in labels] # Call tokenizer on all texts to convert into tensors of numbers with # appropriate padding. inputs = self.use_tokenizer(text=texts, return_tensors="pt", padding=True, truncation=True, max_length=self.max_sequence_len) # Update the inputs with the associated encoded labels as tensor. inputs.update({'labels':torch.tensor(labels)}) return inputs

train (dataloader, optimizer_, scheduler_, device_)

Ho creato questa funzione per eseguire un passaggio completo attraverso l'oggetto DataLoader (l'oggetto DataLoader viene creato dal nostro oggetto di tipo Dataset * utilizzando la classe ** MovieReviewsDataset). Questo è fondamentalmente un treno d'epoca attraverso l'intero set di dati.

Il dataloader viene creato da PyTorch DataLoader che prende l'oggetto creato dalla classe MovieReviewsDataset e mette ogni esempio in batch. In questo modo possiamo alimentare i nostri batch di modelli di dati!

Optimizer_ e scheduler_ sono molto comuni in PyTorch. Sono necessari per aggiornare i parametri del nostro modello e aggiornare la nostra velocità di apprendimento durante la formazione. C'è molto di più ma non entrerò nei dettagli. Questo può effettivamente essere un'enorme tana di coniglio poiché MOLTO accade dietro queste funzioni di cui non dobbiamo preoccuparci. Grazie PyTorch!

Nel processo teniamo traccia delle etichette effettive e previste insieme alla perdita.

def train(dataloader, optimizer_, scheduler_, device_): r""" Train pytorch model on a single pass through the data loader. It will use the global variable `model` which is the transformer model loaded on `_device` that we want to train on. This function is built with reusability in mind: it can be used as is as long as the `dataloader` outputs a batch in dictionary format that can be passed straight into the model - `model(**batch)`. Arguments: dataloader (:obj:`torch.utils.data.dataloader.DataLoader`): Parsed data into batches of tensors. optimizer_ (:obj:`transformers.optimization.AdamW`): Optimizer used for training. scheduler_ (:obj:`torch.optim.lr_scheduler.LambdaLR`): PyTorch scheduler. device_ (:obj:`torch.device`): Device used to load tensors before feeding to model. Returns: :obj:`List[List[int], List[int], float]`: List of [True Labels, Predicted Labels, Train Average Loss]. """ # Use global variable for model. global model # Tracking variables. predictions_labels = [] true_labels = [] # Total loss for this epoch. total_loss = 0 # Put the model into training mode. model.train() # For each batch of training data... for batch in tqdm(dataloader, total=len(dataloader)): # Add original labels - use later for evaluation. true_labels += batch['labels'].numpy().flatten().tolist() # move batch to device batch = {k:v.type(torch.long).to(device_) for k,v in batch.items()} # Always clear any previously calculated gradients before performing a # backward pass. model.zero_grad() # Perform a forward pass (evaluate the model on this training batch). # This will return the loss (rather than the model output) because we # have provided the `labels`. # The documentation for this a bert model function is here: # https://huggingface.co/transformers/v2.2.0/model_doc/bert.html#transformers.BertForSequenceClassification outputs = model(**batch) # The call to `model` always returns a tuple, so we need to pull the # loss value out of the tuple along with the logits. We will use logits # later to calculate training accuracy. loss, logits = outputs[:2] # Accumulate the training loss over all of the batches so that we can # calculate the average loss at the end. `loss` is a Tensor containing a # single value; the `.item()` function just returns the Python value # from the tensor. total_loss += loss.item() # Perform a backward pass to calculate the gradients. loss.backward() # Clip the norm of the gradients to 1.0. # This is to help prevent the "exploding gradients" problem. torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0) # Update parameters and take a step using the computed gradient. # The optimizer dictates the "update rule"--how the parameters are # modified based on their gradients, the learning rate, etc. optimizer.step() # Update the learning rate. scheduler.step() # Move logits and labels to CPU logits = logits.detach().cpu().numpy() # Convert these logits to list of predicted labels values. predictions_labels += logits.argmax(axis=-1).flatten().tolist() # Calculate the average loss over the training data. avg_epoch_loss = total_loss / len(dataloader) # Return all true labels and prediction for future evaluations. return true_labels, predictions_labels, avg_epoch_loss

validazione (dataloader, device_)

Ho implementato questa funzione in modo molto simile al treno ma senza l'aggiornamento dei parametri, il passaggio all'indietro e la parte decente del gradiente. Non abbiamo bisogno di fare tutte quelle attività MOLTO computazionalmente intensive perché ci preoccupiamo solo delle previsioni del nostro modello.

Uso il DataLoader in modo simile al treno per ottenere batch da alimentare al nostro modello.

Nel processo tengo traccia delle etichette effettive e delle etichette previste insieme alla perdita.

def validation(dataloader, device_): r"""Validation function to evaluate model performance on a separate set of data. This function will return the true and predicted labels so we can use later to evaluate the model's performance. This function is built with reusability in mind: it can be used as is as long as the `dataloader` outputs a batch in dictionary format that can be passed straight into the model - `model(**batch)`. Arguments: dataloader (:obj:`torch.utils.data.dataloader.DataLoader`): Parsed data into batches of tensors. device_ (:obj:`torch.device`): Device used to load tensors before feeding to model. Returns: :obj:`List[List[int], List[int], float]`: List of [True Labels, Predicted Labels, Train Average Loss] """ # Use global variable for model. global model # Tracking variables predictions_labels = [] true_labels = [] #total loss for this epoch. total_loss = 0 # Put the model in evaluation mode--the dropout layers behave differently # during evaluation. model.eval() # Evaluate data for one epoch for batch in tqdm(dataloader, total=len(dataloader)): # add original labels true_labels += batch['labels'].numpy().flatten().tolist() # move batch to device batch = {k:v.type(torch.long).to(device_) for k,v in batch.items()} # Telling the model not to compute or store gradients, saving memory and # speeding up validation with torch.no_grad(): # Forward pass, calculate logit predictions. # This will return the logits rather than the loss because we have # not provided labels. # token_type_ids is the same as the "segment ids", which # differentiates sentence 1 and 2 in 2-sentence tasks. # The documentation for this `model` function is here: # https://huggingface.co/transformers/v2.2.0/model_doc/bert.html#transformers.BertForSequenceClassification outputs = model(**batch) # The call to `model` always returns a tuple, so we need to pull the # loss value out of the tuple along with the logits. We will use logits # later to to calculate training accuracy. loss, logits = outputs[:2] # Move logits and labels to CPU logits = logits.detach().cpu().numpy() # Accumulate the training loss over all of the batches so that we can # calculate the average loss at the end. `loss` is a Tensor containing a # single value; the `.item()` function just returns the Python value # from the tensor. total_loss += loss.item() # get predicitons to list predict_content = logits.argmax(axis=-1).flatten().tolist() # update list predictions_labels += predict_content # Calculate the average loss over the training data. avg_epoch_loss = total_loss / len(dataloader) # Return all true labels and prediciton for future evaluations. return true_labels, predictions_labels, avg_epoch_loss

Carica modello e tokenizzatore

Caricamento delle tre parti essenziali del trasformatore GPT2 pre-addestrato: configurazione, tokenizer e modello.

Per questo esempio userò gpt2 da trasformatori pre-addestrati HuggingFace. Puoi utilizzare tutte le variazioni di GP2 che desideri.

Nella creazione del file model_config Menzionerò il numero di etichette di cui ho bisogno per la mia attività di classificazione. Dato che prevedo solo due sentimenti: positivo e negativo, avrò bisogno solo di due etichette num_labels.

Creare il tokenizer è piuttosto standard quando si utilizza la libreria Transformers. Dopo aver creato il tokenizer, è fondamentale per questo tutorial impostare il riempimento a sinistra tokenizer.padding_side = "left" e inizializza il token di riempimento su tokenizer.eos_token che è il token di fine sequenza originale di GPT2. Questa è la parte più essenziale di questo tutorial poiché GPT2 utilizza l'ultimo token per la previsione, quindi dobbiamo spostarci a sinistra.

HuggingFace ha già svolto la maggior parte del lavoro per noi e ha aggiunto un livello di classificazione al modello GPT2. Nella creazione del modello che ho usato GPT2ForSequenceClassification. Poiché abbiamo un token di riempimento personalizzato, dobbiamo inizializzarlo per il modello che utilizza model.config.pad_token_id. Infine dovremo spostare il modello sul dispositivo che abbiamo definito in precedenza.

# Get model configuration.
print('Loading configuraiton...')
model_config = GPT2Config.from_pretrained(pretrained_model_name_or_path=model_name_or_path, num_labels=n_labels) # Get model's tokenizer.
print('Loading tokenizer...')
tokenizer = GPT2Tokenizer.from_pretrained(pretrained_model_name_or_path=model_name_or_path)
# default to left padding
tokenizer.padding_side = "left"
# Define PAD Token = EOS Token = 50256
tokenizer.pad_token = tokenizer.eos_token # Get the actual model.
print('Loading model...')
model = GPT2ForSequenceClassification.from_pretrained(pretrained_model_name_or_path=model_name_or_path, config=model_config) # resize model embedding to match new tokenizer
model.resize_token_embeddings(len(tokenizer)) # fix model padding token id
model.config.pad_token_id = model.config.eos_token_id # Load model to defined device.
model.to(device)
print('Model loaded to `%s`'%device)
Loading configuraiton... Loading tokenizer... Loading model... Some weights of GPT2ForSequenceClassification were not initialized from the model checkpoint at gpt2 and are newly initialized: ['score.weight'] You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference. Model loaded to `cuda`

Dataset e Collator

Qui è dove creo il set di dati PyTorch e il caricatore di dati con oggetti Data Collator che verranno utilizzati per inserire i dati nel nostro modello.

Qui è dove uso il file MovieReviewsSet di dati class per creare il set di dati PyTorch che restituirà testi ed etichette.

Poiché abbiamo bisogno di inserire numeri nel nostro modello, dobbiamo convertire i testi e le etichette in numeri. Questo è lo scopo di un raccoglitore! Prende i dati emessi dal set di dati PyTorch e passati attraverso la funzione Data Collator per produrre la sequenza per il nostro modello.

Tengo il tokenizer lontano dal set di dati PyTorch per rendere il codice più pulito e meglio strutturato. È ovviamente possibile utilizzare il tokenizer all'interno del set di dati PyTorch e le sequenze di output che possono essere utilizzate direttamente nel modello senza utilizzare un Data Collator.

Consiglio vivamente di utilizzare un file di testo di convalida per determinare la quantità di formazione necessaria per evitare l'overfitting. Dopo aver individuato quali parametri producono i risultati migliori, il file di convalida può essere incorporato in train ed eseguire un train finale con l'intero set di dati.

L'agente di raccolta dati viene utilizzato per formattare gli output del set di dati PyTorch in modo che corrispondano agli input necessari per GPT2.

# Create data collator to encode text and labels into numbers.
gpt2_classificaiton_collator = Gpt2ClassificationCollator(use_tokenizer=tokenizer, labels_encoder=labels_ids, max_sequence_len=max_length) print('Dealing with Train...')
# Create pytorch dataset.
train_dataset = MovieReviewsDataset(path='/content/aclImdb/train', use_tokenizer=tokenizer)
print('Created `train_dataset` with %d examples!'%len(train_dataset)) # Move pytorch dataset into dataloader.
train_dataloader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True, collate_fn=gpt2_classificaiton_collator)
print('Created `train_dataloader` with %d batches!'%len(train_dataloader)) print() print('Dealing with Validation...')
# Create pytorch dataset.
valid_dataset = MovieReviewsDataset(path='/content/aclImdb/test', use_tokenizer=tokenizer)
print('Created `valid_dataset` with %d examples!'%len(valid_dataset)) # Move pytorch dataset into dataloader.
valid_dataloader = DataLoader(valid_dataset, batch_size=batch_size, shuffle=False, collate_fn=gpt2_classificaiton_collator)
print('Created `eval_dataloader` with %d batches!'%len(valid_dataloader))
Dealing with Train... pos files: 100%|████████████████████████████████|12500/12500 [01:17<00:00, 161.19it/s] neg files: 100%|████████████████████████████████|12500/12500 [01:05<00:00, 190.72it/s] Created `train_dataset` with 25000 examples! Created `train_dataloader` with 782 batches! Reading pos files... pos files: 100%|████████████████████████████████|12500/12500 [00:54<00:00, 230.93it/s] neg files: 100%|████████████████████████████████|12500/12500 [00:42<00:00, 291.07it/s] Created `valid_dataset` with 25000 examples! Created `eval_dataloader` with 782 batches!

Treni

Ho creato l'ottimizzatore e lo scheduler da usare da PyTorch in allenamento. Ho utilizzato i parametri più comuni utilizzati dai modelli di trasformatori.

Ho passato in rassegna il numero di epoche definite e ho chiamato il file provare ed convalida funzioni.

Sto cercando di produrre informazioni simili dopo ogni epoca come Keras: train_loss: - val_loss: - train_acc: - valid_acc.

Dopo l'allenamento, tracciare l'addestramento e la perdita di convalida e le curve di precisione per verificare come è andato l'allenamento.

Nota: I grafici di addestramento potrebbero sembrare un po 'strani: l'accuratezza della convalida inizia più in alto dell'accuratezza dell'addestramento e la perdita di convalida inizia più in basso rispetto alla perdita dell'addestramento. Normalmente questo sarà l'opposto. Presumo che la divisione dei dati sia più facile per la parte di convalida o troppo difficile per la parte di addestramento o per entrambi. Poiché questo tutorial riguarda l'utilizzo di GPT2 per la classificazione, non mi preoccuperò troppo dei risultati del modello.

# Note: AdamW is a class from the huggingface library (as opposed to pytorch) # I believe the 'W' stands for 'Weight Decay fix"
optimizer = AdamW(model.parameters(), lr = 2e-5, # default is 5e-5, our notebook had 2e-5 eps = 1e-8 # default is 1e-8. ) # Total number of training steps is number of batches * number of epochs.
# `train_dataloader` contains batched data so `len(train_dataloader)` gives # us the number of batches.
total_steps = len(train_dataloader) * epochs # Create the learning rate scheduler.
scheduler = get_linear_schedule_with_warmup(optimizer, num_warmup_steps = 0, # Default value in run_glue.py num_training_steps = total_steps) # Store the average loss after each epoch so we can plot them.
all_loss = {'train_loss':[], 'val_loss':[]}
all_acc = {'train_acc':[], 'val_acc':[]} # Loop through each epoch.
print('Epoch')
for epoch in tqdm(range(epochs)): print() print('Training on batches...') # Perform one full pass over the training set. train_labels, train_predict, train_loss = train(train_dataloader, optimizer, scheduler, device) train_acc = accuracy_score(train_labels, train_predict) # Get prediction form model on validation data. print('Validation on batches...') valid_labels, valid_predict, val_loss = validation(valid_dataloader, device) val_acc = accuracy_score(valid_labels, valid_predict) # Print loss and accuracy values to see how training evolves. print(" train_loss: %.5f - val_loss: %.5f - train_acc: %.5f - valid_acc: %.5f"%(train_loss, val_loss, train_acc, val_acc)) print() # Store the loss value for plotting the learning curve. all_loss['train_loss'].append(train_loss) all_loss['val_loss'].append(val_loss) all_acc['train_acc'].append(train_acc) all_acc['val_acc'].append(val_acc) # Plot loss curves.
plot_dict(all_loss, use_xlabel='Epochs', use_ylabel='Value', use_linestyles=['-', '--']) # Plot accuracy curves.
plot_dict(all_acc, use_xlabel='Epochs', use_ylabel='Value', use_linestyles=['-', '--'])
Epoch 100%|████████████████████████████████|4/4 [15:11<00:00, 227.96s/it] Training on batches... 100%|████████████████████████████████|782/782 [02:42<00:00, 4.82it/s] Validation on batches... 100%|████████████████████████████████|782/782 [02:07<00:00, 6.13it/s] train_loss: 0.54128 - val_loss: 0.38758 - train_acc: 0.75288 - valid_acc: 0.81904 Training on batches... 100%|████████████████████████████████|782/782 [02:36<00:00, 5.00it/s] Validation on batches... 100%|████████████████████████████████|782/782 [01:41<00:00, 7.68it/s] train_loss: 0.36716 - val_loss: 0.37620 - train_acc: 0.83288 -valid_acc: 0.82912 Training on batches... 100%|████████████████████████████████|782/782 [02:36<00:00, 5.00it/s] Validation on batches... 100%|████████████████████████████████|782/782 [01:24<00:00, 9.24it/s] train_loss: 0.31409 - val_loss: 0.39384 - train_acc: 0.86304 - valid_acc: 0.83044 Training on batches... 100%|████████████████████████████████|782/782 [02:36<00:00, 4.99it/s] Validation on batches... 100%|████████████████████████████████|782/782 [01:09<00:00, 11.29it/s] train_loss: 0.27358 - val_loss: 0.39798 - train_acc: 0.88432 - valid_acc: 0.83292
Perdita di addestramento e convalida.
Accuratezza del training e della convalida.

Valutare

Quando si ha a che fare con la classificazione è utile guardare al richiamo di precisione e al punteggio F1.

Un buon indicatore da avere quando si valuta un modello è la matrice di confusione.

# Get prediction form model on validation data. This is where you should use
# your test data.
true_labels, predictions_labels, avg_epoch_loss = validation(valid_dataloader, device) # Create the evaluation report.
evaluation_report = classification_report(true_labels, predictions_labels, labels=list(labels_ids.values()), target_names=list(labels_ids.keys()))
# Show the evaluation report.
print(evaluation_report) # Plot confusion matrix.
plot_confusion_matrix(y_true=true_labels, y_pred=predictions_labels, classes=list(labels_ids.keys()), normalize=True, magnify=0.1, );
Training on batches... 100%|████████████████████████████████|782/782 [01:09<00:00, 11.24it/s] precision recall f1-score support neg 0.84 0.83 0.83 12500 pos 0.83 0.84 0.83 12500 accuracy 0.83 25000 macro avg 0.83 0.83 0.83 25000 weighted avg 0.83 0.83 0.83 25000
Matrice di confusione normalizzata.

Nota finale

Se sei arrivato così lontano Complimenti! 🎊 e . 🙏 per il tuo interesse per il mio tutorial!

Sto usando questo codice da un po 'di tempo e sento che è arrivato a un punto in cui è ben documentato e facile da seguire.

Ovviamente è facile per me seguirlo perché l'ho costruito. Ecco perché qualsiasi feedback è il benvenuto e mi aiuta a migliorare i miei futuri tutorial!

Se vedi qualcosa che non va, fammelo sapere aprendo un problema sul mio repository GitHub ml_things!

Molti tutorial là fuori sono per lo più una cosa unica e non vengono mantenuti. Ho intenzione di mantenere i miei tutorial aggiornati il ​​più possibile.

Questo articolo è stato pubblicato in origine Il sito personale di George Mihaila  e ripubblicato su TOPBOTS con il permesso dell'autore.

Ti piace questo articolo? Iscriviti per ulteriori aggiornamenti AI.

Ti faremo sapere quando rilasceremo più istruzione tecnica.

Fonte: https://www.topbots.com/gpt2-text-classification-using-hugging-face-transformers/

Timestamp:

Di più da TOPBOT