GPT2 Pentru clasificarea textului utilizând transformatoare de față îmbrățișate

Nodul sursă: 809063

clasificarea textului

Acest notebook este folosit pentru a regla fin modelul GPT2 pentru clasificarea textului folosind Fata îmbrățișată transformatoare bibliotecă pe un set de date personalizat.

Hugging Face este foarte plăcut pentru noi să includem toate funcționalitățile necesare pentru ca GPT2 să fie utilizat în sarcinile de clasificare. Mulțumesc Îmbrățișând fața!

Nu am putut găsi multe informații despre cum să folosesc GPT2 pentru clasificare, așa că am decis să fac acest tutorial folosind o structură similară cu alte modele de transformatoare.

Dacă acest conținut educațional aprofundat vă este util, abonați-vă la lista noastră de corespondență pentru cercetare AI pentru a fi avertizați atunci când lansăm material nou. 

Ideea principală: Deoarece GPT2 este un transformator de decodor, ultimul simbol al secvenței de intrare este utilizat pentru a face predicții despre următorul simbol care ar trebui să urmeze intrarea. Aceasta înseamnă că ultimul simbol al secvenței de intrare conține toate informațiile necesare în predicție. Având în vedere acest lucru, putem folosi acele informații pentru a face o predicție într-o sarcină de clasificare în loc de sarcină de generare.

Cu alte cuvinte, în loc să folosim încorporarea primelor simboluri pentru a face predicții așa cum facem în Bert, vom folosi ultima încorporare a simbolurilor pentru a face predicții cu GPT2.

Din moment ce ne-a păsat doar de primul jeton din Bert, umpleam în dreapta. Acum, în GPT2, folosim ultimul simbol pentru predicție, așa că va trebui să tamponăm în stânga. Datorită unui upgrade frumos la HuggingFace Transformers, putem configura Tokenizer GPT2 pentru a face exact acest lucru.

Ce ar trebui să știu pentru acest caiet?

Întrucât folosesc PyTorch pentru a regla fin modelele noastre de transformatoare, orice cunoștință despre PyTorch este foarte utilă.

Știind puțin despre transformatoare biblioteca ajută și ea.

Cum se folosește acest notebook?

Ca în cazul fiecărui proiect, am construit acest notebook având în vedere reutilizarea.

Toate modificările vor avea loc în partea de procesare a datelor, unde trebuie să personalizați setul de date PyTorch, Data Collator și DataLoader pentru a se potrivi propriilor dvs. nevoi de date.

Toți parametrii care pot fi modificați se află sub Importurile secțiune. Fiecare parametru este frumos comentat și structurat pentru a fi cât mai intuitiv posibil.

Setul de date

Acest notebook va acoperi transformatoarele de pre-antrenare pe un set de date personalizat. Voi folosi binecunoscutele recenzii de filme pozitive - negative etichetate Set de date pentru recenzii de filme mari.

Descrierea oferită pe site-ul Stanford:

Acesta este un set de date pentru clasificarea sentimentelor binare care conține substanțial mai multe date decât seturile de date de referință anterioare. Oferim un set de 25,000 de recenzii de film extrem de polare pentru antrenament și 25,000 pentru testare. Există și date suplimentare fără etichetă pentru utilizare. Sunt furnizate texte brute și formate de sac deja procesate. Consultați fișierul README conținut în versiune pentru mai multe detalii.

De ce acest set de date? Cred că este un set de date ușor de înțeles și de utilizat pentru clasificare. Cred că datele despre sentiment sunt întotdeauna distractive pentru a lucra.

Codificare

Acum hai să facem niște codări! Vom trece prin fiecare celulă de codare din caiet și vom descrie ce face, care este codul și când este relevant - vom arăta rezultatul.

Am făcut acest format să fie ușor de urmărit dacă decideți să rulați fiecare celulă de cod în propriul blocnotes python.

Când învăț dintr-un tutorial, încerc mereu să reproduc rezultatele. Cred că este ușor de urmărit dacă aveți codul lângă explicații.

Download

Descărcați Set de date pentru recenzii de filme mari și dezarhivați-l local.

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

instalări

  • transformatoare biblioteca trebuie instalată pentru a utiliza tot codul minunat de la Hugging Face. Pentru a obține cea mai recentă versiune, o voi instala direct de pe GitHub.
  • ml_lucruri bibliotecă utilizată pentru diverse sarcini legate de învățarea automată. Am creat această bibliotecă pentru a reduce cantitatea de cod pe care trebuie să o scriu pentru fiecare proiect de învățare automată.
# 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

Importurile

Importați toate bibliotecile necesare pentru acest notebook. Declarați parametrii utilizați pentru acest notebook:

  • set_seed(123) - Întotdeauna bine să setați o sămânță fixă ​​pentru reproductibilitate.
  • epochs - Numărul de epoci de instruire (autorii recomandă între 2 și 4).
  • batch_size - Numărul de loturi - în funcție de lungimea maximă a secvenței și de memoria GPU. Pentru lungimea de 512 secvențe, un lot de 10 de obicei funcționează fără probleme de memorie cuda. Pentru lungimea secvenței mici, puteți încerca lotul de 32 sau mai mare. max_length - Tastați sau tăiați secvențele de text la o lungime specifică. Îl voi seta la 60 pentru a accelera antrenamentul.
  • device - Căutați gpu de utilizat. Va folosi cpu în mod implicit dacă nu a fost găsit niciun gpu.
  • model_name_or_path - Denumirea modelului transformatoarelor - va folosi modelul deja predeterminat. Calea modelului transformatorului - vă va încărca propriul model de pe discul local. În acest tutorial voi folosi gpt2 model.
  • labels_ids - Dicționar de etichete și id-ul acestora - acesta va fi folosit pentru a converti etichetele șirului în numere.
  • n_labels - Câte etichete folosim în acest set de date. Aceasta este utilizată pentru a decide mărimea capului de clasificare.
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)

Funcții de ajutor

Îmi place să păstrez toate clasele și funcțiile care vor fi utilizate în acest notebook în această secțiune pentru a ajuta la menținerea unui aspect curat al notebook-ului:

MovieReviewsDataset (Dataset)

Dacă ați mai lucrat cu PyTorch, acest lucru este destul de standard. Avem nevoie ca această clasă să citească în setul nostru de date, să o analizeze și să returneze texte cu etichetele asociate.

În această clasă trebuie să citesc doar conținutul fiecărui fișier, să folosesc fix_text pentru a remedia orice problemă Unicode și să urmăresc sentimentele pozitive și negative.

Voi adăuga toate textele și etichetele din liste.

Există trei părți principale ale acestei clase PyTorch Dataset:

  • init () unde citim în setul de date și transformăm textul și etichetele în numere.
  • len () unde trebuie să returnăm numărul de exemple pe care le-am citit. Acesta este utilizat atunci când apelăm len (MovieReviewsDataset ()).
  • getitem () ia întotdeauna ca intrare o valoare int care reprezintă exemplul din exemplele noastre pentru a reveni din setul nostru de date. Dacă se trece o valoare 3, vom returna exemplul din setul nostru de date în poziția 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

Folosesc această clasă pentru a crea Data Collator. Acest lucru va fi utilizat în DataLoader pentru a crea grupurile de date care sunt alimentate cu modelul. Folosesc tokenizer și codificatorul de etichete pe fiecare secvență pentru a converti textele și etichetele în număr.

Norocos pentru noi, Hugging Face s-a gândit la toate și l-a făcut pe tokenizer să facă tot greul (împărțirea textului în jetoane, umplutură, trunchiere, codificarea textului în numere) și este foarte ușor de utilizat!

Există două părți principale ale acestei clase Data Collator:

  • init () unde inițializăm tokenizatorul pe care intenționăm să îl folosim, cum să codificăm etichetele noastre și dacă trebuie să setăm lungimea secvenței la o valoare diferită.
  • apel() folosit ca colector de funcții care ia ca intrare un lot de exemple de date. Trebuie să returneze un obiect cu formatul care poate fi alimentat modelului nostru. Din fericire tokenizer-ul nostru face asta pentru noi și returnează un dicționar de variabile gata să fie introduse în model în acest fel: model(**inputs). Deoarece ajustăm modelul, am inclus și etichete.
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

tren (dataloader, optimizer_, scheduler_, device_)

Am creat această funcție pentru a efectua o trecere completă prin obiectul DataLoader (obiectul DataLoader este creat din obiectul nostru de tip Dataset * utilizând clasa ** MovieReviewsDataset). Acesta este practic un tren de epocă prin întregul set de date.

Dataloader-ul este creat din PyTorch DataLoader, care preia obiectul creat din clasa MovieReviewsDataset și pune fiecare exemplu în loturi. În acest fel, putem hrăni modelele noastre de loturi de date!

Optimizatorul_ și programatorul_ sunt foarte frecvente în PyTorch. Li se cere să actualizeze parametrii modelului nostru și să actualizeze rata de învățare în timpul antrenamentului. Există mult mai mult decât atât, dar nu voi intra în detalii. Aceasta poate fi de fapt o gaură uriașă de iepure, deoarece MULTE se întâmplă în spatele acestor funcții pe care nu trebuie să le îngrijorăm. Mulțumesc PyTorch!

În acest proces, ținem evidența etichetelor reale și a etichetelor prevăzute, împreună cu pierderea.

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

validare (încărcător de date, dispozitiv_)

Am implementat această funcție într-un mod foarte asemănător cu trenul, dar fără actualizarea parametrilor, trecerea înapoi și partea decentă a gradientului. Nu trebuie să facem toate acele sarcini FOARTE intensive din punct de vedere al calculului, deoarece ne pasă doar de predicțiile modelului nostru.

Folosesc DataLoader într-un mod similar ca în tren pentru a obține loturi pentru a alimenta modelul nostru.

În acest proces, urmăresc etichetele reale și etichetele prezise, ​​împreună cu pierderea.

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

Încărcați modelul și Tokenizer

Încărcarea celor trei părți esențiale ale transformatorului GPT2 pretensionat: configurație, tokenizer și model.

Pentru acest exemplu voi folosi gpt2 de la HuggingFace transformatoare pretrainate. Puteți folosi orice variante de GP2 doriți.

În crearea model_config Voi menționa numărul de etichete de care am nevoie pentru sarcina mea de clasificare. Deoarece prezic doar două sentimente: pozitiv și negativ, voi avea nevoie doar de două etichete pentru num_labels.

Crearea tokenizer este destul de standard atunci când se utilizează biblioteca Transformers. După crearea tokenizer-ului, este esențial ca acest tutorial să seteze umplerea la stânga tokenizer.padding_side = "left" și inițializați jetonul de umplere la tokenizer.eos_token care este simbolul original de sfârșit de secvență al GPT2. Aceasta este cea mai esențială parte a acestui tutorial, deoarece GPT2 folosește ultimul simbol pentru predicție, așa că trebuie să tamponăm în stânga.

HuggingFace a făcut deja cea mai mare parte a muncii pentru noi și a adăugat un strat de clasificare la modelul GPT2. La crearea modelului pe care l-am folosit GPT2ForSequenceClassification. Deoarece avem un token de umplere personalizat, trebuie să-l inițializăm pentru modelul utilizat model.config.pad_token_id. În cele din urmă va trebui să mutăm modelul pe dispozitivul pe care l-am definit mai devreme.

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

Set de date și colector

Aici creez PyTorch Dataset și Data Loader cu obiecte Data Collator care vor fi folosite pentru a introduce date în modelul nostru.

Aici folosesc FilmReviewsDataset clasă pentru a crea setul de date PyTorch care va returna texte și etichete.

Deoarece trebuie să introducem numere în modelul nostru, trebuie să convertim textele și etichetele în numere. Acesta este scopul unui colector! Este nevoie de date transmise de setul de date PyTorch și trecute prin funcția Data Collator pentru a genera secvența pentru modelul nostru.

Țin tokenizerul departe de setul de date PyTorch pentru a face codul mai curat și mai bine structurat. Puteți utiliza în mod evident tokenizer-ul din setul de date PyTorch și secvențele de ieșire care pot fi utilizate direct în model fără a utiliza un Data Collator.

Vă recomandăm cu tărie să utilizați un fișier text de validare pentru a determina cât de mult este nevoie de instruire pentru a evita supradaptarea. După ce aflați ce parametri dau cele mai bune rezultate, fișierul de validare poate fi încorporat în tren și poate rula un tren final cu întregul set de date.

Colectorul de date este utilizat pentru a formata ieșirile PyTorch Dataset pentru a se potrivi cu intrările necesare pentru 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!

Tren

Am creat utilizarea programului de optimizare și programare de către PyTorch în antrenament. Am folosit parametrii cei mai comuni folosiți de modelele de transformatoare.

Am cercetat numărul de epoci definite și am apelat la tren și validare funcții.

Încerc să produc informații similare după fiecare epocă ca Keras: train_loss: - val_loss: - train_acc: - valid_acc.

După antrenament, parcelați trenul și curbele de pierdere și precizie ale validării pentru a verifica cum a decurs antrenamentul.

Notă: Parcela de antrenament ar putea părea puțin ciudată: precizia de validare începe mai mare decât acuratețea antrenamentului, iar pierderea de validare începe mai mică decât pierderea de antrenament. În mod normal, acesta va fi opusul. Presupun că divizarea datelor este mai ușoară pentru partea de validare sau prea dificilă pentru partea de instruire sau ambele. Deoarece acest tutorial este despre utilizarea GPT2 pentru clasificare, nu mă voi îngrijora prea mult de rezultatele modelului.

# 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
Pierderea trenului și validării.
Exactitatea trenului și validării.

Evalua

Când vă ocupați de clasificare este util să vă uitați la rechemarea de precizie și la scorul F1.

Un indicator adecvat pentru evaluarea unui model este matricea de confuzie.

# 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
Matricea de confuzie s-a normalizat.

Nota finală

Dacă ai ajuns până aici Felicitări! 🎊 și Mulțumesc! 🙏 pentru interesul dvs. față de tutorialul meu!

Folosesc acest cod de ceva vreme și simt că a ajuns la un punct în care este bine documentat și ușor de urmat.

Desigur, este ușor să urmez pentru că l-am construit. De aceea, orice feedback este binevenit și mă ajută să-mi îmbunătățesc viitoarele tutoriale!

Dacă vedeți ceva în neregulă, vă rugăm să ne anunțați deschizând o problemă pe adresa mea ml_things Depozit GitHub!

O mulțime de tutoriale sunt în mare parte un lucru unic și nu sunt întreținute. Plănuiesc să-mi mențin tutorialele la zi cât de mult pot.

Acest articol a fost publicat inițial Site-ul personal al lui George Mihaila  și re-publicat în TOPBOTS cu permisiunea autorului.

Vă place acest articol? Înscrieți-vă pentru mai multe actualizări AI.

Vă vom anunța când vom elibera mai multe studii tehnice.

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

Timestamp-ul:

Mai mult de la TOPBOTS