GPT2 voor tekstclassificatie met behulp van omhelzende gezichtstransformatoren

Bronknooppunt: 809063

tekstclassificatie

Dit notebook wordt gebruikt om het GPT2-model voor tekstclassificatie te verfijnen Gezicht knuffelen transformers bibliotheek op een aangepaste gegevensset.

Het is erg aardig voor ons dat Hugging Face alle functionaliteit bevat die nodig is om GPT2 te gebruiken bij classificatietaken. Bedankt knuffelgezicht!

Ik kon niet veel informatie vinden over het gebruik van GPT2 voor classificatie, dus besloot ik deze tutorial te maken met een vergelijkbare structuur als andere transformatormodellen.

Als deze diepgaande educatieve inhoud nuttig voor u is, abonneer u op onze AI-research mailinglijst om gewaarschuwd te worden wanneer we nieuw materiaal uitbrengen. 

Hoofdidee: Omdat GPT2 een decodertransformator is, wordt het laatste token van de invoerreeks gebruikt om voorspellingen te doen over het volgende token dat op de invoer zou moeten volgen. Dit betekent dat het laatste token van de invoerreeks alle informatie bevat die nodig is voor de voorspelling. Met dit in gedachten kunnen we die informatie gebruiken om een ​​voorspelling te doen in een classificatietaak in plaats van in een generatietaak.

Met andere woorden, in plaats van de eerste token-inbedding te gebruiken om voorspellingen te doen, zoals we doen in Bert, zullen we de laatste token-inbedding gebruiken om voorspellingen te doen met GPT2.

Omdat het ons alleen om het eerste token in Bert ging, waren we naar rechts aan het opvullen. Nu gebruiken we in GPT2 het laatste token voor voorspellingen, dus we zullen aan de linkerkant moeten opvullen. Dankzij een mooie upgrade naar HuggingFace Transformers kunnen we de GPT2 Tokenizer precies daarvoor configureren.

Wat moet ik weten voor dit notitieboekje?

Omdat ik PyTorch gebruik om onze transformatormodellen te verfijnen, is alle kennis over PyTorch erg handig.

Een klein beetje weten over de transformers bibliotheek helpt ook.

Hoe gebruik je dit notitieboekje?

Zoals bij elk project heb ik bij het bouwen van deze notebook rekening gehouden met herbruikbaarheid.

Alle veranderingen zullen plaatsvinden in het gegevensverwerkingsgedeelte, waar u de PyTorch Dataset, Data Collator en DataLoader moet aanpassen aan uw eigen gegevensbehoeften.

Alle parameters die kunnen worden gewijzigd, staan ​​onder de Invoer sectie. Elke parameter is mooi becommentarieerd en gestructureerd om zo intuïtief mogelijk te zijn.

dataset

Deze notebook behandelt pretraining-transformatoren op een aangepaste dataset. Ik zal de bekende filmrecensies positief - negatief gelabeld gebruiken Dataset voor grote filmrecensies.

De beschrijving op de Stanford-website:

Dit is een dataset voor binaire sentimentclassificatie die aanzienlijk meer data bevat dan eerdere benchmarkdatasets. We bieden een set van 25,000 zeer polaire filmrecensies voor training en 25,000 voor testen. Er zijn ook aanvullende niet-gelabelde gegevens voor gebruik. Er worden onbewerkte tekst en reeds verwerkte tekstverpakkingen geleverd. Zie het README-bestand in de release voor meer details.

Waarom deze dataset? Ik denk dat het een gemakkelijk te begrijpen en te gebruiken dataset is voor classificatie. Ik denk dat sentimentgegevens altijd leuk zijn om mee te werken.

codering

Laten we nu wat coderen! We zullen elke coderingscel in het notitieboek doorlopen en beschrijven wat het doet, wat de code is en wanneer relevant - laat de uitvoer zien.

Ik heb dit formaat zo gemaakt dat het gemakkelijk te volgen is als je besluit om elke codecel in je eigen python-notebook uit te voeren.

Als ik leer van een tutorial, probeer ik altijd de resultaten te repliceren. Ik denk dat het gemakkelijk te volgen is als je de code naast de uitleg hebt staan.

Downloads

Download de Dataset voor grote filmrecensies en pak het lokaal uit.

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

Installeert

  • transformers bibliotheek moet worden geïnstalleerd om alle geweldige code van Hugging Face te gebruiken. Om de nieuwste versie te krijgen, zal ik deze rechtstreeks vanuit GitHub installeren.
  • ml_dingen bibliotheek die wordt gebruikt voor verschillende aan machine learning gerelateerde taken. Ik heb deze bibliotheek gemaakt om de hoeveelheid code die ik moet schrijven voor elk machine learning-project te verminderen.
# 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

Invoer

Importeer alle benodigde bibliotheken voor dit notebook. Declareer de parameters die voor dit notebook worden gebruikt:

  • set_seed(123) - Altijd goed om een ​​vast zaadje te zetten voor reproduceerbaarheid.
  • epochs - Aantal trainingstijdvakken (auteurs bevelen tussen 2 en 4 aan).
  • batch_size – Aantal batches – afhankelijk van de maximale sequentielengte en GPU-geheugen. Voor een reekslengte van 512 werkt een batch van 10 doorgaans zonder cuda-geheugenproblemen. Voor een kleine reekslengte kunt u een batch van 32 of hoger proberen. max_length – Tekstreeksen opvullen of afkappen tot een specifieke lengte. Ik zal het op 60 zetten om de training te versnellen.
  • device – Zoek naar gpu die u wilt gebruiken. Zal standaard cpu gebruiken als er geen gpu wordt gevonden.
  • model_name_or_path – Naam van het transformatormodel – zal een reeds voorgetraind model gebruiken. Pad van transformatormodel – laadt uw eigen model vanaf de lokale schijf. In deze tutorial zal ik gebruiken gpt2 model.
  • labels_ids - Woordenboek van labels en hun id - dit wordt gebruikt om stringlabels om te zetten in getallen.
  • n_labels - Hoeveel labels gebruiken we in deze dataset. Dit wordt gebruikt om de grootte van het classificatiehoofd te bepalen.
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)

Helper-functies

Ik wil graag alle Klassen en functies die in dit notitieboekje worden gebruikt onder deze sectie houden om het uiterlijk van het notitieboekje schoon te houden:

MovieReviewsDataset(Dataset)

Als je eerder met PyTorch hebt gewerkt, is dit vrij standaard. We hebben deze klasse nodig om onze dataset in te lezen, te parseren en teksten met de bijbehorende labels terug te geven.

In deze les hoef ik alleen maar de inhoud van elk bestand in te lezen, fix_text te gebruiken om eventuele Unicode-problemen op te lossen en positieve en negatieve gevoelens bij te houden.

Ik zal alle teksten en labels in lijsten toevoegen.

Er zijn drie hoofdonderdelen van deze PyTorch Dataset-klasse:

  • in het() waar we in de dataset lezen en tekst en labels omzetten in getallen.
  • len () waar we het aantal voorbeelden moeten retourneren dat we hebben ingelezen. Dit wordt gebruikt bij het aanroepen van len(MovieReviewsDataset()).
  • getitem() neemt altijd als invoer een int-waarde die aangeeft welk voorbeeld uit onze voorbeelden moet worden geretourneerd uit onze dataset. Als een waarde van 3 wordt doorgegeven, retourneren we het voorbeeld uit onze dataset op positie 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]}

Gpt2ClassificatieCollator

Ik gebruik deze klasse om de Data Collator te maken. Dit zal in de DataLoader worden gebruikt om de gegevensverzamelingen te creëren die aan het model worden toegevoegd. Ik gebruik de tokenizer en label-encoder op elke reeks om teksten en labels naar getallen te converteren.

Gelukkig voor ons heeft Hugging Face aan alles gedacht en de tokenizer al het zware werk laten doen (tekst in tokens splitsen, opvullen, afkappen, tekst in cijfers coderen) en het is heel gemakkelijk te gebruiken!

Er zijn twee hoofdonderdelen van deze Data Collator-klasse:

  • in het() waar we de tokenizer initialiseren die we willen gebruiken, hoe we onze labels moeten coderen en of we de reekslengte op een andere waarde moeten instellen.
  • bellen () gebruikt als functiecollator die een reeks gegevensvoorbeelden als invoer gebruikt. Het moet een object retourneren met het formaat dat aan ons model kan worden ingevoerd. Gelukkig doet onze tokenizer dat voor ons en retourneert een woordenboek met variabelen die op deze manier aan het model kunnen worden toegevoegd: model(**inputs). Omdat we het model aan het verfijnen zijn, heb ik er ook de labels bijgevoegd.
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

trein (dataloader, optimizer_, scheduler_, device_)

Ik heb deze functie gemaakt om een ​​volledige doorgang door het DataLoader-object uit te voeren (het DataLoader-object wordt gemaakt op basis van ons Dataset*-type object met behulp van de **MovieReviewsDataset-klasse). Dit is feitelijk één tijdperktrein door de gehele dataset.

De dataloader is gemaakt op basis van PyTorch DataLoader, die het object neemt dat is gemaakt met de MovieReviewsDataset-klasse en elk voorbeeld in batches plaatst. Op deze manier kunnen we onze modelbatches met gegevens voeden!

De optimizer_ en planner_ zijn heel gebruikelijk in PyTorch. Ze zijn verplicht om de parameters van ons model bij te werken en ons leerpercentage tijdens de training bij te werken. Er is nog veel meer dan dat, maar ik zal niet in details treden. Dit kan eigenlijk een enorm konijnenhol zijn, aangezien er VEEL achter deze functies gebeurt waar we ons geen zorgen over hoeven te maken. Bedankt PyTorch!

Tijdens het proces houden we de daadwerkelijke labels en de voorspelde labels bij, samen met het verlies.

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

validatie (dataloader, device_)

Ik heb deze functie op een vergelijkbare manier geïmplementeerd als trein, maar zonder de parameters-update, achterwaartse pass en gradiënt-fatsoenlijke deel. We hoeven niet al die ZEER rekenintensieve taken uit te voeren, omdat we alleen geïnteresseerd zijn in de voorspellingen van ons model.

Ik gebruik de DataLoader op dezelfde manier als in de trein om batches te verkrijgen die aan ons model kunnen worden toegevoegd.

Tijdens het proces houd ik de daadwerkelijke labels en de voorspelde labels bij, samen met het verlies.

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

Laad model en tokenizer

Het laden van de drie essentiële onderdelen van de voorgetrainde GPT2-transformator: configuratie, tokenizer en model.

Voor dit voorbeeld zal ik gebruiken gpt2 van voorgetrainde transformatoren van HuggingFace. Je kunt elke gewenste variant van GP2 gebruiken.

Bij het maken van het model_config Ik zal het aantal labels vermelden dat ik nodig heb voor mijn classificatietaak. Omdat ik slechts twee gevoelens voorspel: positief en negatief, heb ik er maar twee labels voor nodig num_labels.

Het maken van de tokenizer is vrij standaard bij gebruik van de Transformers-bibliotheek. Na het maken van de tokenizer is het voor deze tutorial van cruciaal belang om de opvulling naar links in te stellen tokenizer.padding_side = "left" en initialiseer het opvultoken naar tokenizer.eos_token dit is het oorspronkelijke einde van de reeks-token van de GPT2. Dit is het meest essentiële onderdeel van deze tutorial, aangezien GPT2 het laatste token gebruikt voor voorspellingen, dus we moeten naar links gaan.

HuggingFace heeft het meeste werk al voor ons gedaan en een classificatielaag aan het GPT2-model toegevoegd. Bij het maken van het model dat ik heb gebruikt GPT2ForSequenceClassification. Omdat we een aangepast opvultoken hebben, moeten we deze initialiseren voor het gebruikte model model.config.pad_token_id. Ten slotte zullen we het model moeten verplaatsen naar het apparaat dat we eerder hebben gedefinieerd.

# 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 en Collator

Hier maak ik de PyTorch Dataset en Data Loader met Data Collator-objecten die zullen worden gebruikt om gegevens in ons model in te voeren.

Dit is waar ik de FilmRecensiesDataset class om de PyTorch-gegevensset te maken die teksten en labels retourneert.

Omdat we getallen in ons model moeten invoeren, moeten we de teksten en labels naar getallen converteren. Dit is het doel van een collator! Er zijn gegevens nodig die door de PyTorch-gegevensset worden uitgevoerd en door de Data Collator-functie worden doorgegeven om de reeks voor ons model uit te voeren.

Ik houd de tokenizer uit de buurt van de PyTorch-dataset om de code schoner en beter gestructureerd te maken. U kunt uiteraard de tokenizer in de PyTorch-gegevensset gebruiken en reeksen uitvoeren die rechtstreeks in het model kunnen worden gebruikt zonder een gegevenscollator te gebruiken.

Ik raad ten zeerste aan om een ​​validatietekstbestand te gebruiken om te bepalen hoeveel training nodig is om overfitting te voorkomen. Nadat u erachter bent gekomen welke parameters de beste resultaten opleveren, kan het validatiebestand in de trein worden opgenomen en een laatste trein met de hele dataset laten draaien.

De gegevenscollator wordt gebruikt om de PyTorch Dataset-uitvoer te formatteren zodat deze overeenkomt met de invoer die nodig is voor 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!

Trainen

Ik heb tijdens de training optimalisatie- en plannergebruik door PyTorch gemaakt. Ik heb de meest voorkomende parameters gebruikt die worden gebruikt door transformatormodellen.

Ik doorliep het aantal gedefinieerde tijdperken en roep de trein en bevestiging functies.

Ik probeer na elk tijdperk soortgelijke informatie uit te voeren als Keras: train_loss: - val_loss: - train_acc: - valid_acc.

Na de training kunt u de curven voor trein- en validatieverlies en nauwkeurigheid plotten om te controleren hoe de training verliep.

Opmerking: De trainingsgrafieken zien er misschien een beetje raar uit: de validatienauwkeurigheid begint hoger dan de trainingsnauwkeurigheid en het validatieverlies begint lager dan het trainingsverlies. Normaal gesproken zal dit het tegenovergestelde zijn. Ik neem aan dat de gegevenssplitsing eenvoudiger is voor het validatiegedeelte of te moeilijk voor het trainingsgedeelte of beide. Omdat deze tutorial gaat over het gebruik van GPT2 voor classificatie, zal ik me niet al te veel zorgen maken over de resultaten van het model.

# 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
Trein- en validatieverlies.
Nauwkeurigheid van trainen en valideren.

Schatten

Bij het omgaan met classificatie is het nuttig om te kijken naar precisieherinnering en F1-score.

Een goede maatstaf bij het evalueren van een model is de verwarringsmatrix.

# 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
Verwarringsmatrix genormaliseerd.

Final Note

Als je zover bent gekomen Congrats! 🎊 en Dank je! 🙏 voor uw interesse in mijn tutorial!

Ik gebruik deze code nu al een tijdje en ik heb het gevoel dat het op een punt is gekomen dat het mooi gedocumenteerd en gemakkelijk te volgen is.

Het is voor mij natuurlijk gemakkelijk te volgen omdat ik het heb gebouwd. Daarom is alle feedback welkom en het helpt me mijn toekomstige tutorials te verbeteren!

Als u iets verkeerds ziet, laat het me dan weten door een probleem te openen op mijn ml_things GitHub-opslagplaats!

Veel tutorials die er zijn, zijn meestal eenmalig en worden niet onderhouden. Ik ben van plan mijn tutorials zo veel mogelijk up-to-date te houden.

Dit artikel is oorspronkelijk gepubliceerd op George Mihaila's persoonlijke website  en opnieuw gepubliceerd naar TOPBOTS met toestemming van de auteur.

Geniet van dit artikel? Meld u aan voor meer AI-updates.

We laten het je weten wanneer we meer technisch onderwijs vrijgeven.

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

Tijdstempel:

Meer van TOPBOTS