GPT2 til tekstklassificering ved hjælp af krammeansigtstransformere

Kildeknude: 809063

tekstklassificering

Denne notesbog bruges til at finjustere GPT2-modellen til tekstklassificering ved hjælp af Knusende ansigt transformers bibliotek på et brugerdefineret datasæt.

Hugging Face er meget rart for os at inkludere al den funktionalitet, der er nødvendig for, at GPT2 kan bruges i klassificeringsopgaver. Tak Knusende ansigt!

Jeg var ikke i stand til at finde meget information om, hvordan man bruger GPT2 til klassificering, så jeg besluttede at lave denne tutorial ved at bruge lignende struktur med andre transformatormodeller.

Hvis dette dybdegående undervisningsindhold er nyttigt for dig, abonner på vores AI-forskningsmailingliste for at blive advaret, når vi udgiver nyt materiale. 

Hoved ide: Da GPT2 er en dekodertransformator, bruges det sidste token af ​​inputsekvensen til at lave forudsigelser om det næste token, der skal følge inputtet. Det betyder, at det sidste token i inputsekvensen indeholder al den information, der er nødvendig i forudsigelsen. Med dette i tankerne kan vi bruge denne information til at lave en forudsigelse i en klassifikationsopgave i stedet for generationsopgave.

Med andre ord, i stedet for at bruge første token-indlejring til at lave forudsigelse, som vi gør i Bert, vil vi bruge den sidste token-indlejring til at lave forudsigelse med GPT2.

Da vi kun bekymrede os om det første token i Bert, polstrede vi til højre. Nu i GPT2 bruger vi det sidste token til forudsigelse, så vi bliver nødt til at pude til venstre. På grund af en god opgradering til HuggingFace Transformers er vi i stand til at konfigurere GPT2 Tokenizer til netop det.

Hvad skal jeg vide om denne notesbog?

Da jeg bruger PyTorch til at finjustere vores transformatormodeller, er enhver viden om PyTorch meget nyttig.

Ved lidt om transformers biblioteket hjælper også.

Hvordan bruger man denne notesbog?

Som med ethvert projekt byggede jeg denne notesbog med genbrugelighed i tankerne.

Alle ændringer vil ske i databehandlingsdelen, hvor du skal tilpasse PyTorch Dataset, Data Collator og DataLoader til at passe til dine egne databehov.

Alle parametre, der kan ændres, er under Import afsnit. Hver parameter er pænt kommenteret og struktureret for at være så intuitiv som muligt.

datasæt

Denne notesbog vil dække fortræning af transformere på et brugerdefineret datasæt. Jeg vil bruge de velkendte filmanmeldelser positive — negative mærket Stort filmanmeldelsesdatasæt.

Beskrivelsen på Stanfords hjemmeside:

Dette er et datasæt til binær sentimentklassificering, der indeholder væsentligt flere data end tidligere benchmarkdatasæt. Vi leverer et sæt på 25,000 meget polære filmanmeldelser til træning og 25,000 til test. Der er også yderligere umærkede data til brug. Rå tekst og allerede behandlede pose med ord-formater leveres. Se README-filen i udgivelsen for flere detaljer.

Hvorfor dette datasæt? Jeg tror, ​​det er et let at forstå og bruge datasæt til klassificering. Jeg synes, at sentimentdata altid er sjovt at arbejde med.

Kodning

Lad os nu lave noget kodning! Vi vil gennemgå hver kodningscelle i notesbogen og beskrive, hvad den gør, hvad koden er, og hvornår det er relevant - vis outputtet.

Jeg har lavet dette format, så det er nemt at følge, hvis du beslutter dig for at køre hver kodecelle i din egen python-notesbog.

Når jeg lærer fra en tutorial, prøver jeg altid at kopiere resultaterne. Jeg tror, ​​det er nemt at følge med, hvis du har koden ved siden af ​​forklaringerne.

Downloads

Download Stort filmanmeldelsesdatasæt og pak den ud lokalt.

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

installationer

  • transformers biblioteket skal installeres for at bruge al den fantastiske kode fra Hugging Face. For at få den seneste version installerer jeg den direkte fra GitHub.
  • ml_ting bibliotek brugt til forskellige maskinlæringsrelaterede opgaver. Jeg oprettede dette bibliotek for at reducere mængden af ​​kode, jeg skal skrive til hvert maskinlæringsprojekt.
# 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

Import

Importer alle nødvendige biblioteker til denne notesbog. Angiv parametre, der bruges til denne notesbog:

  • set_seed(123) – Altid godt at sætte et fast frø for reproducerbarhed.
  • epochs – Antal træningsepoker (forfattere anbefaler mellem 2 og 4).
  • batch_size – Antal batches – afhængig af den maksimale sekvenslængde og GPU-hukommelse. For en sekvenslængde på 512 fungerer en batch på 10 SAMMENLIGT uden problemer med cuda-hukommelse. For lille sekvenslængde kan prøve batch på 32 eller højere. max_length – Indtast eller afkort tekstsekvenser til en bestemt længde. Jeg vil sætte den til 60 for at fremskynde træningen.
  • device – Se efter gpu at bruge. Vil bruge cpu som standard, hvis ingen gpu findes.
  • model_name_or_path – Navn på transformatormodel – vil bruge allerede fortrænet model. Sti til transformermodel – indlæser din egen model fra lokal disk. I denne tutorial vil jeg bruge gpt2 model.
  • labels_ids – Ordbog over etiketter og deres id – dette vil blive brugt til at konvertere strengetiketter til tal.
  • n_labels – Hvor mange etiketter bruger vi i dette datasæt. Dette bruges til at bestemme størrelsen på klassifikationshovedet.
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)

Hjælpefunktioner

Jeg kan godt lide at beholde alle klasser og funktioner, der vil blive brugt i denne notesbog, under dette afsnit for at hjælpe med at bevare et rent udseende af notesbogen:

MovieReviewsDataset(Dataset)

Hvis du har arbejdet med PyTorch før, er dette ret standard. Vi har brug for denne klasse til at læse vores datasæt ind, analysere den og returnere tekster med tilhørende etiketter.

I denne klasse behøver jeg kun at læse indholdet af hver fil, bruge fix_text til at rette eventuelle Unicode-problemer og holde styr på positive og negative følelser.

Jeg vil tilføje alle tekster og etiketter i lister.

Der er tre hoveddele af denne PyTorch Dataset-klasse:

  • i det() hvor vi læser i datasættet og omdanner tekst og etiketter til tal.
  • len () hvor vi skal returnere antallet af eksempler vi læser ind. Dette bruges når man kalder len(MovieReviewsDataset()).
  • getitem() tager altid som input en int-værdi, der repræsenterer hvilket eksempel fra vores eksempler, der skal returneres fra vores datasæt. Hvis en værdi på 3 passeres, returnerer vi eksemplet fra vores datasæt på 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]}

Gpt2ClassificationCollator

Jeg bruger denne klasse til at oprette Data Collator. Dette vil blive brugt i DataLoader til at skabe de bade af data, der føres til modellen. Jeg bruger tokenizer og etiketkoder på hver sekvens til at konvertere tekster og etiketter til tal.

Heldigt for os tænkte Hugging Face på alt og fik tokenizeren til at gøre alt det tunge løft (opdelt tekst i tokens, polstring, trunkering, indkode tekst i tal) og er meget nem at bruge!

Der er to hoveddele af denne Data Collator-klasse:

  • i det() hvor vi initialiserer den tokenizer, vi planlægger at bruge, hvordan vi koder vores etiketter, og hvis vi skal indstille sekvenslængden til en anden værdi.
  • opkald() bruges som funktionssamler, der tager et parti af dataeksempler som input. Den skal returnere et objekt med det format, der kan føres til vores model. Heldigvis gør vores tokenizer det for os og returnerer en ordbog over variabler, der er klar til at blive feedet til modellen på denne måde: model(**inputs). Da vi finjusterer modellen, har jeg også inkluderet etiketterne.
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_)

Jeg oprettede denne funktion for at udføre en fuld gennemgang gennem DataLoader-objektet (DataLoader-objektet er oprettet ud fra vores Dataset*-objekt ved hjælp af klassen **MovieReviewsDataset). Dette er grundlæggende et epoketog gennem hele datasættet.

Dataindlæseren er oprettet fra PyTorch DataLoader, som tager objektet oprettet fra MovieReviewsDataset-klassen og sætter hvert eksempel i batches. På denne måde kan vi fodre vores modelbatches af data!

Optimizer_ og scheduler_ er meget almindelige i PyTorch. De er forpligtet til at opdatere parametrene for vores model og opdatere vores indlæringshastighed under træning. Der er meget mere end det, men jeg vil ikke gå i detaljer. Dette kan faktisk være et stort kaninhul, da der sker MEGET bag disse funktioner, som vi ikke behøver at bekymre os om. Tak PyTorch!

I processen holder vi styr på de faktiske etiketter og de forudsagte etiketter sammen med tabet.

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

validering (dataloader, enhed_)

Jeg implementerede denne funktion på en meget lignende måde som tog, men uden parametrene opdatering, baglæns pass og gradient anstændig del. Vi behøver ikke at udføre alle de MEGET beregningsintensive opgaver, fordi vi kun bekymrer os om vores models forudsigelser.

Jeg bruger DataLoader på samme måde som i tog for at få batcher ud til at fodre til vores model.

I processen holder jeg styr på de faktiske etiketter og de forudsagte etiketter sammen med tabet.

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

Indlæs model og tokenizer

Indlæsning af de tre væsentlige dele af den fortrænede GPT2-transformer: konfiguration, tokenizer og model.

Til dette eksempel vil jeg bruge gpt2 fra HuggingFace fortrænede transformere. Du kan bruge alle varianter af GP2, du ønsker.

Ved oprettelse af model_config Jeg vil nævne antallet af etiketter, jeg skal bruge til min klassificeringsopgave. Da jeg kun forudsiger to følelser: positiv og negativ, skal jeg kun bruge to etiketter til num_labels.

Oprettelse af tokenizer er ret standard, når du bruger Transformers-biblioteket. Efter at have oprettet tokenizeren er det afgørende for denne tutorial at indstille polstring til venstre tokenizer.padding_side = "left" og initialisere polstringstokenet til tokenizer.eos_token som er GPT2's originale ende af sekvens-token. Dette er den mest essentielle del af denne tutorial, da GPT2 bruger det sidste token til forudsigelse, så vi er nødt til at pude til venstre.

HuggingFace har allerede gjort det meste af arbejdet for os og tilføjet et klassifikationslag til GPT2-modellen. Ved at lave den model jeg brugte GPT2ForSequenceClassification. Da vi har et brugerdefineret polstringstoken, skal vi initialisere det til den model, der bruger model.config.pad_token_id. Til sidst bliver vi nødt til at flytte modellen til den enhed, vi definerede tidligere.

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

Datasæt og samler

Det er her, jeg opretter PyTorch-datasættet og dataindlæseren med Data Collator-objekter, der vil blive brugt til at føre data ind i vores model.

Det er her jeg bruger Filmanmeldelser Datasæt klasse for at oprette PyTorch-datasættet, der returnerer tekster og etiketter.

Da vi skal indtaste tal til vores model, skal vi konvertere tekster og etiketter til tal. Dette er formålet med en samler! Det kræver data, der udlæses af PyTorch-datasættet og sendes gennem Data Collator-funktionen for at udlæse sekvensen for vores model.

Jeg holder tokenizeren væk fra PyTorch-datasættet for at gøre koden renere og bedre struktureret. Du kan naturligvis bruge tokenizeren inde i PyTorch-datasættet og udlæse sekvenser, der kan bruges direkte ind i modellen uden at bruge en Data Collator.

Jeg anbefaler kraftigt at bruge en valideringstekstfil for at bestemme, hvor meget træning der skal til for at undgå overfitting. Når du har fundet ud af, hvilke parametre der giver de bedste resultater, kan valideringsfilen inkorporeres i tog og køre et sidste tog med hele datasættet.

Datasamleren bruges til at formatere PyTorch Dataset-output, så de matcher de input, der er nødvendige for 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!

Tog

Jeg oprettede optimizer og skemalægger brug af PyTorch under træning. Jeg brugte de mest almindelige parametre, der bruges af transformatormodeller.

Jeg gennemgik antallet af definerede epoker og kalder tog , validering funktioner.

Jeg forsøger at udlæse lignende oplysninger efter hver epoke som Keras: train_tab: — val_loss: — train_acc: — valid_acc.

Efter træning, plottræn og valideringstab og nøjagtighedskurver for at kontrollere, hvordan træningen gik.

Bemærk: Træningsplottene kan se lidt mærkelige ud: Valideringsnøjagtigheden starter højere end træningsnøjagtigheden, og valideringstabet starter lavere end træningstabet. Normalt vil dette være det modsatte. Jeg antager, at dataopdelingen tilfældigvis er nemmere for valideringsdelen eller for svær for træningsdelen eller begge dele. Da denne tutorial handler om at bruge GPT2 til klassificering, vil jeg ikke bekymre mig for meget om resultaterne af modellen.

# 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
Tog- og valideringstab.
Trænings- og valideringsnøjagtighed.

Evaluer

Når man beskæftiger sig med klassificering er det nyttigt at se på præcisionsgenkaldelse og F1-score.

En god målestok at have, når man skal evaluere en model, er forvirringsmatricen.

# 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
Forvirringsmatrix normaliseret.

Afsluttende Note

Hvis du nåede så langt Tillykke! 🎊 og Tak! 🙏 for din interesse for min tutorial!

Jeg har brugt denne kode i et stykke tid nu, og jeg føler, at den er nået til et punkt, hvor den er pænt dokumenteret og nem at følge.

Det er selvfølgelig nemt for mig at følge, fordi jeg byggede det. Derfor er enhver feedback velkommen, og den hjælper mig med at forbedre mine fremtidige tutorials!

Hvis du ser noget galt, så lad mig det vide ved at åbne et problem på min ml_things GitHub repository!

Mange tutorials derude er for det meste en engangs ting og bliver ikke vedligeholdt. Jeg planlægger at holde mine tutorials ajour så meget som muligt.

Denne artikel blev oprindeligt offentliggjort den George Mihailas personlige hjemmeside  og genudgivet til TOPBOTS med tilladelse fra forfatteren.

Nyder du denne artikel? Tilmeld dig for flere AI-opdateringer.

Vi giver dig besked, når vi frigiver mere teknisk uddannelse.

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

Tidsstempel:

Mere fra TOPBOTS