GPT2 pour la classification de texte à l'aide de transformateurs de visage étreignant

Nœud source: 809063

classification de texte

Ce bloc-notes est utilisé pour affiner le modèle GPT2 pour la classification de texte à l'aide de Étreindre le visage transformateurs bibliothèque sur un ensemble de données personnalisé.

Hugging Face est très agréable pour nous d'inclure toutes les fonctionnalités nécessaires à l'utilisation de GPT2 dans les tâches de classification. Merci Hugging Face!

Je n'ai pas pu trouver beaucoup d'informations sur la façon d'utiliser GPT2 pour la classification, j'ai donc décidé de faire ce tutoriel en utilisant une structure similaire avec d'autres modèles de transformateurs.

Si ce contenu éducatif approfondi vous est utile, abonnez-vous à notre liste de diffusion de recherche sur l'IA d'être alerté lorsque nous publierons du nouveau matériel. 

Idée principale: Puisque GPT2 est un transformateur de décodeur, le dernier jeton de la séquence d'entrée est utilisé pour faire des prédictions sur le prochain jeton qui devrait suivre l'entrée. Cela signifie que le dernier jeton de la séquence d'entrée contient toutes les informations nécessaires à la prédiction. Dans cet esprit, nous pouvons utiliser ces informations pour effectuer une prédiction dans une tâche de classification au lieu d'une tâche de génération.

En d'autres termes, au lieu d'utiliser la première incorporation de jetons pour faire des prédictions comme nous le faisons dans Bert, nous utiliserons la dernière incorporation de jetons pour faire des prédictions avec GPT2.

Comme nous ne nous soucions que du premier jeton de Bert, nous nous déplaçons vers la droite. Maintenant, dans GPT2, nous utilisons le dernier jeton pour la prédiction, nous devrons donc remplir à gauche. En raison d'une belle mise à niveau vers HuggingFace Transformers, nous sommes en mesure de configurer le Tokenizer GPT2 pour faire exactement cela.

Que dois-je savoir pour ce cahier?

Puisque j'utilise PyTorch pour affiner nos modèles de transformateurs, toutes les connaissances sur PyTorch sont très utiles.

Connaissant un peu le transformateurs la bibliothèque aide aussi.

Comment utiliser ce notebook?

Comme pour chaque projet, j'ai construit ce cahier en pensant à sa réutilisation.

Tous les changements se produiront dans la partie traitement des données où vous devez personnaliser le jeu de données PyTorch, le collecteur de données et le chargeur de données pour répondre à vos propres besoins en données.

Tous les paramètres qui peuvent être modifiés sont sous Importations section. Chaque paramètre est joliment commenté et structuré pour être le plus intuitif possible.

Ensemble de données

Ce cahier couvrira les transformateurs de pré-formation sur un ensemble de données personnalisé. J'utiliserai les critiques de films bien connues positives - négatives Grand ensemble de données d'examen de films.

La description fournie sur le site Web de Stanford:

Il s'agit d'un ensemble de données pour la classification des sentiments binaires contenant beaucoup plus de données que les ensembles de données de référence précédents. Nous proposons un ensemble de 25,000 25,000 critiques de films hautement polaires pour la formation et de XNUMX XNUMX pour les tests. Il existe également des données non étiquetées supplémentaires à utiliser. Des formats de texte brut et de sac de mots déjà traités sont fournis. Voir le fichier README contenu dans la version pour plus de détails.

Pourquoi cet ensemble de données? Je pense que c'est un ensemble de données facile à comprendre et à utiliser pour la classification. Je pense que les données de sentiment sont toujours amusantes à travailler.

Codage

Maintenant, faisons un peu de codage! Nous passerons en revue chaque cellule de codage du cahier et décrirons ce qu'elle fait, quel est le code et quand est pertinent - montrer la sortie.

J'ai rendu ce format facile à suivre si vous décidez d'exécuter chaque cellule de code dans votre propre bloc-notes python.

Quand j'apprends d'un tutoriel, j'essaie toujours de reproduire les résultats. Je pense que c'est facile à suivre si vous avez le code à côté des explications.

Télécharger

Télécharger  Grand ensemble de données d'examen de films et décompressez-le localement.

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

Installations

  • transformateurs La bibliothèque doit être installée pour utiliser tout le code génial de Hugging Face. Pour obtenir la dernière version, je vais l'installer directement à partir de GitHub.
  • ml_choses bibliothèque utilisée pour diverses tâches liées à l'apprentissage automatique. J'ai créé cette bibliothèque pour réduire la quantité de code que j'ai besoin d'écrire pour chaque projet d'apprentissage automatique.
# 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

Importations

Importez toutes les bibliothèques nécessaires pour ce notebook.Déclarez les paramètres utilisés pour ce notebook:

  • set_seed(123) - Toujours bon de définir une graine fixe pour la reproductibilité.
  • epochs - Nombre d'époques de formation (les auteurs recommandent entre 2 et 4).
  • batch_size - Nombre de lots - en fonction de la longueur maximale de la séquence et de la mémoire GPU. Pour une longueur de 512 séquences, un lot de 10 fonctionne habituellement sans problèmes de mémoire cuda. Pour une petite longueur de séquence, vous pouvez essayer un lot de 32 ou plus. max_length - Remplit ou tronque les séquences de texte à une longueur spécifique. Je vais le régler à 60 pour accélérer la formation.
  • device - Recherchez le GPU à utiliser. Utilisera le processeur par défaut si aucun GPU n'a été trouvé.
  • model_name_or_path - Nom du modèle de transformateurs - utilisera un modèle déjà pré-entraîné. Chemin du modèle de transformateur - chargera votre propre modèle à partir du disque local. Dans ce tutoriel, je vais utiliser gpt2 .
  • labels_ids - Dictionnaire des étiquettes et leur identifiant - il sera utilisé pour convertir les étiquettes de chaîne en nombres.
  • n_labels - Combien d'étiquettes utilisons-nous dans cet ensemble de données. Ceci est utilisé pour décider de la taille de la tête de classification.
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)

Fonctions d'assistance

J'aime conserver toutes les classes et fonctions qui seront utilisées dans ce bloc-notes dans cette section pour aider à maintenir un aspect propre du bloc-notes:

MovieReviewsDataset (ensemble de données)

Si vous avez déjà travaillé avec PyTorch, c'est assez standard. Nous avons besoin de cette classe pour lire notre jeu de données, l'analyser et renvoyer les textes avec leurs étiquettes associées.

Dans cette classe, je n'ai besoin que de lire le contenu de chaque fichier, d'utiliser fix_text pour résoudre les problèmes Unicode et de garder une trace des sentiments positifs et négatifs.

J'ajouterai tous les textes et étiquettes dans les listes.

Il existe trois parties principales de cette classe de jeu de données PyTorch:

  • init () où nous lisons dans l'ensemble de données et transformons le texte et les étiquettes en nombres.
  • len () où nous devons renvoyer le nombre d'exemples que nous lisons. Ceci est utilisé lors de l'appel de len (MovieReviewsDataset ()).
  • obtenir l'article() prend toujours comme entrée une valeur int qui représente l'exemple de nos exemples à renvoyer à partir de notre ensemble de données. Si une valeur de 3 est passée, nous retournerons l'exemple de notre ensemble de données à la position 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]}

Gpt2ClassificationColler

J'utilise cette classe pour créer le Data Collator. Cela sera utilisé dans le DataLoader pour créer les bains de données qui sont alimentés au modèle. J'utilise le tokenizer et l'encodeur d'étiquettes sur chaque séquence pour convertir des textes et des étiquettes en nombre.

Heureusement pour nous, Hugging Face a pensé à tout et a obligé le tokenizer à faire tout le gros du travail (diviser le texte en jetons, remplissage, tronquer, encoder le texte en nombres) et est très facile à utiliser!

Il existe deux parties principales de cette classe Data Collator:

  • init () où nous initialisons le tokenizer que nous prévoyons d'utiliser, comment encoder nos étiquettes et si nous devons définir la longueur de la séquence sur une valeur différente.
  • appel() utilisé comme collator de fonction qui prend en entrée un lot d'exemples de données. Il doit renvoyer un objet au format qui peut être introduit dans notre modèle. Heureusement, notre tokenizer fait cela pour nous et renvoie un dictionnaire de variables prêtes à être alimentées au modèle de cette manière: model(**inputs). Depuis que nous peaufinons le modèle, j'ai également inclus les étiquettes.
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 (chargeur de données, optimizer_, scheduler_, device_)

J'ai créé cette fonction pour effectuer un passage complet à travers l'objet DataLoader (l'objet DataLoader est créé à partir de notre objet de type Dataset * à l'aide de la classe ** MovieReviewsDataset). Il s'agit essentiellement d'un train d'époque à travers l'ensemble de données.

Le chargeur de données est créé à partir de PyTorch DataLoader qui prend l'objet créé à partir de la classe MovieReviewsDataset et met chaque exemple par lots. De cette façon, nous pouvons alimenter nos modèles de lots de données!

L'optimizer_ et le scheduler_ sont très courants dans PyTorch. Ils sont tenus de mettre à jour les paramètres de notre modèle et de mettre à jour notre taux d'apprentissage pendant la formation. Il y a beaucoup plus que cela, mais je n'entrerai pas dans les détails. Cela peut en fait être un énorme terrier de lapin car BEAUCOUP se passe derrière ces fonctions que nous n'avons pas à nous inquiéter. Merci PyTorch!

Dans le processus, nous suivons les étiquettes réelles et les étiquettes prévues ainsi que la perte.

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

validation (dataloader, device_)

J'ai implémenté cette fonction d'une manière très similaire à celle du train mais sans la mise à jour des paramètres, le passage en arrière et la partie décente de gradient. Nous n'avons pas besoin de faire toutes ces tâches TRÈS intensives en calcul car nous ne nous soucions que des prédictions de notre modèle.

J'utilise le DataLoader de la même manière qu'en train pour sortir des lots pour alimenter notre modèle.

Dans le processus, je garde une trace des étiquettes réelles et des étiquettes prévues ainsi que de la perte.

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

Charger le modèle et le tokenizer

Chargement des trois parties essentielles du transformateur GPT2 pré-entraîné: configuration, tokenizer et modèle.

Pour cet exemple, je vais utiliser gpt2 de transformateurs pré-entraînés HuggingFace. Vous pouvez utiliser toutes les variantes de GP2 que vous souhaitez.

En créant le model_config Je mentionnerai le nombre d'étiquettes dont j'ai besoin pour ma tâche de classification. Puisque je ne prédis que deux sentiments: positif et négatif, je n'aurai besoin que de deux étiquettes pour num_labels.

Création du tokenizer est assez standard lors de l'utilisation de la bibliothèque Transformers. Après avoir créé le tokenizer, il est essentiel que ce didacticiel définisse le remplissage à gauche tokenizer.padding_side = "left" et initialisez le jeton de remplissage à tokenizer.eos_token qui est le jeton de fin de séquence d'origine du GPT2. C'est la partie la plus essentielle de ce didacticiel car GPT2 utilise le dernier jeton pour la prédiction, nous devons donc nous déplacer vers la gauche.

HuggingFace a déjà fait l'essentiel du travail pour nous et a ajouté une couche de classification au modèle GPT2. En créant le modèle que j'ai utilisé GPT2ForSequenceClassification. Puisque nous avons un jeton de remplissage personnalisé, nous devons l'initialiser pour le modèle en utilisant model.config.pad_token_id. Enfin, nous devrons déplacer le modèle vers le périphérique que nous avons défini précédemment.

# 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`

Ensemble de données et assembleur

C'est là que je crée le jeu de données PyTorch et le chargeur de données avec des objets Data Collator qui seront utilisés pour alimenter des données dans notre modèle.

C'est là que j'utilise le FilmReviewsDataset classe pour créer le jeu de données PyTorch qui renverra des textes et des étiquettes.

Puisque nous devons entrer des nombres dans notre modèle, nous devons convertir les textes et les étiquettes en nombres. C'est le but d'un assembleur! Il prend les données générées par le jeu de données PyTorch et transmises via la fonction Data Collator pour générer la séquence de notre modèle.

Je garde le tokenizer loin du jeu de données PyTorch pour rendre le code plus propre et mieux structuré. Vous pouvez évidemment utiliser le tokenizer à l'intérieur du Dataset PyTorch et des séquences de sortie qui peuvent être utilisées directement dans le modèle sans utiliser de Data Collator.

Je recommande fortement d'utiliser un fichier texte de validation afin de déterminer combien de formation est nécessaire afin d'éviter le surajustement. Une fois que vous avez déterminé quels paramètres donnent les meilleurs résultats, le fichier de validation peut être incorporé dans le train et exécuter un train final avec l'ensemble de données.

Le collecteur de données est utilisé pour formater les sorties du jeu de données PyTorch afin qu'elles correspondent aux entrées nécessaires pour 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!

Train

J'ai créé l'utilisation de l'optimiseur et du planificateur par PyTorch en formation. J'ai utilisé les paramètres les plus courants utilisés par les modèles de transformateurs.

J'ai parcouru le nombre d'époques définies et j'appelle le train ainsi que  validation fonctions.

J'essaie de produire des informations similaires après chaque époque en tant que Keras: train_loss: - val_loss: - train_acc: - valid_acc.

Après la formation, tracez le train et la validation des courbes de perte et de précision pour vérifier le déroulement de la formation.

Remarque: Les graphiques d'entraînement peuvent sembler un peu bizarres: la précision de validation commence plus haut que la précision d'entraînement et la perte de validation commence plus bas que la perte d'entraînement. Normalement, ce sera le contraire. Je suppose que la division des données est simplement plus facile pour la partie validation ou trop difficile pour la partie formation ou les deux. Étant donné que ce tutoriel concerne l'utilisation de GPT2 pour la classification, je ne m'inquiéterai pas trop des résultats du modèle.

# 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
Perte de train et de validation.
Exactitude de la formation et de la validation.

Évaluer

Lorsqu'il s'agit de classification, il est utile d'examiner le rappel de précision et le score F1.

Une bonne jauge à avoir lors de l'évaluation d'un modèle est la matrice de confusion.

# 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 de confusion normalisée.

note finale

Si tu l'as fait jusqu'ici Félicitations! 🎊 et Merci! 🙏 pour votre intérêt pour mon tutoriel!

J'utilise ce code depuis un certain temps maintenant et je pense qu'il est arrivé à un point où il est bien documenté et facile à suivre.

Bien sûr, il m'est facile de suivre parce que je l'ai construit. C'est pourquoi tout commentaire est le bienvenu et cela m'aide à améliorer mes futurs tutoriels!

Si vous voyez quelque chose qui ne va pas, veuillez me le faire savoir en ouvrant un problème sur mon Dépôt GitHub ml_things!

De nombreux didacticiels sont pour la plupart ponctuels et ne sont pas maintenus. Je prévois de garder mes tutoriels à jour autant que possible.

Cet article a été publié initialement le Site Web personnel de George Mihaila  et republié sur TOPBOTS avec la permission de l'auteur.

Profitez de cet article? Inscrivez-vous pour plus de mises à jour de l'IA.

Nous vous informerons lorsque nous publierons plus de formation technique.

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

Horodatage:

Plus de TOPBOTS