GPT2 για ταξινόμηση κειμένου χρησιμοποιώντας αγκάλιασμα μετασχηματιστών προσώπου

Κόμβος πηγής: 809063

ταξινόμηση κειμένου

Αυτός ο φορητός υπολογιστής χρησιμοποιείται για τη βελτιστοποίηση του μοντέλου GPT2 για ταξινόμηση κειμένου Αγκαλιάζοντας το πρόσωπο μετασχηματιστές βιβλιοθήκη σε ένα προσαρμοσμένο σύνολο δεδομένων.

Το Hugging Face είναι πολύ ωραίο για εμάς να συμπεριλάβουμε όλες τις λειτουργίες που απαιτούνται για τη χρήση του GPT2 σε εργασίες ταξινόμησης. Ευχαριστώ Hugging Face!

Δεν μπόρεσα να βρω πολλές πληροφορίες σχετικά με τον τρόπο χρήσης του GPT2 για ταξινόμηση, γι' αυτό αποφάσισα να κάνω αυτό το σεμινάριο χρησιμοποιώντας παρόμοια δομή με άλλα μοντέλα μετασχηματιστών.

Εάν αυτό το σε βάθος εκπαιδευτικό περιεχόμενο είναι χρήσιμο για εσάς, εγγραφείτε στη λίστα αλληλογραφίας της AI μας να ειδοποιούμε όταν κυκλοφορούμε νέο υλικό. 

Κύρια ιδέα: Δεδομένου ότι το GPT2 είναι ένας μετασχηματιστής αποκωδικοποιητή, το τελευταίο διακριτικό της ακολουθίας εισόδου χρησιμοποιείται για να γίνουν προβλέψεις σχετικά με το επόμενο διακριτικό που πρέπει να ακολουθήσει την είσοδο. Αυτό σημαίνει ότι το τελευταίο διακριτικό της ακολουθίας εισόδου περιέχει όλες τις πληροφορίες που χρειάζονται για την πρόβλεψη. Έχοντας αυτό κατά νου, μπορούμε να χρησιμοποιήσουμε αυτές τις πληροφορίες για να κάνουμε μια πρόβλεψη σε μια εργασία ταξινόμησης αντί για εργασία δημιουργίας.

Με άλλα λόγια, αντί να χρησιμοποιήσουμε την πρώτη ενσωμάτωση διακριτικού για να κάνουμε πρόβλεψη όπως κάνουμε στον Bert, θα χρησιμοποιήσουμε την τελευταία ενσωμάτωση διακριτικού για να κάνουμε πρόβλεψη με το GPT2.

Δεδομένου ότι μας ένοιαζε μόνο το πρώτο κουπόνι στο Μπερτ, γεμίζαμε προς τα δεξιά. Τώρα στο GPT2 χρησιμοποιούμε το τελευταίο διακριτικό για πρόβλεψη, οπότε θα χρειαστεί να βάλουμε pad στα αριστερά. Λόγω μιας ωραίας αναβάθμισης στο HuggingFace Transformers, είμαστε σε θέση να διαμορφώσουμε το GPT2 Tokenizer για να κάνει ακριβώς αυτό.

Τι πρέπει να γνωρίζω για αυτό το σημειωματάριο;

Εφόσον χρησιμοποιώ το PyTorch για να βελτιώσω τα μοντέλα των μετασχηματιστών μας, κάθε γνώση σχετικά με το PyTorch είναι πολύ χρήσιμη.

Γνωρίζοντας λίγο για το μετασχηματιστές βοηθάει επίσης η βιβλιοθήκη.

Πώς να χρησιμοποιήσετε αυτό το σημειωματάριο;

Όπως με κάθε έργο, έφτιαξα αυτό το σημειωματάριο έχοντας κατά νου την επαναχρησιμοποίηση.

Όλες οι αλλαγές θα συμβούν στο τμήμα επεξεργασίας δεδομένων όπου πρέπει να προσαρμόσετε το σύνολο δεδομένων PyTorch, το Data Collator και το DataLoader για να ταιριάζουν στις δικές σας ανάγκες δεδομένων.

Όλες οι παράμετροι που μπορούν να αλλάξουν βρίσκονται κάτω από το Εισαγωγές Ενότητα. Κάθε παράμετρος σχολιάζεται όμορφα και είναι δομημένη ώστε να είναι όσο πιο διαισθητική γίνεται.

Σύνολο δεδομένων

Αυτό το σημειωματάριο θα καλύψει μετασχηματιστές προκαταρκτικής κατάρτισης σε ένα προσαρμοσμένο σύνολο δεδομένων. Θα χρησιμοποιήσω τις γνωστές κριτικές ταινιών θετικές - αρνητικές Μεγάλο σύνολο κριτικών ταινιών.

Η περιγραφή παρέχεται στον ιστότοπο του Στάνφορντ:

Αυτό είναι ένα σύνολο δεδομένων για την ταξινόμηση δυαδικών συναισθημάτων που περιέχει ουσιαστικά περισσότερα δεδομένα από τα προηγούμενα σύνολα δεδομένων αναφοράς. Παρέχουμε ένα σύνολο από 25,000 κριτικές για πολικές ταινίες για εκπαίδευση και 25,000 για δοκιμές. Υπάρχουν επιπλέον δεδομένα χωρίς ετικέτα για χρήση επίσης. Παρέχονται ακατέργαστο κείμενο και ήδη επεξεργασμένες μορφές σάκων λέξεων. Ανατρέξτε στο αρχείο README που περιέχεται στην έκδοση για περισσότερες λεπτομέρειες.

Γιατί αυτό το σύνολο δεδομένων; Πιστεύω ότι είναι ένα εύκολο στην κατανόηση και χρήση του συνόλου δεδομένων για την ταξινόμηση. Νομίζω ότι τα δεδομένα συναισθημάτων είναι πάντα διασκεδαστικά να δουλεύουμε.

Κωδικοποίηση

Τώρα ας κάνουμε κάποια κωδικοποίηση! Θα εξετάσουμε κάθε κελί κωδικοποίησης στο σημειωματάριο και θα περιγράψουμε τι κάνει, ποιος είναι ο κωδικός και πότε είναι σχετικός - θα δείξουμε την έξοδο.

Έκανα αυτή τη μορφή να είναι εύκολο να ακολουθηθεί εάν αποφασίσετε να εκτελέσετε κάθε κελί κώδικα στο δικό σας φορητό υπολογιστή python.

Όταν μαθαίνω από ένα σεμινάριο προσπαθώ πάντα να επαναλαμβάνω τα αποτελέσματα. Πιστεύω ότι είναι εύκολο να ακολουθήσετε αν έχετε τον κωδικό δίπλα στις εξηγήσεις.

Λήψεις

Κατεβάστε το Μεγάλο σύνολο κριτικών ταινιών και αποσυμπιέστε το τοπικά.

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

Εγκαθιστά

  • μετασχηματιστές Η βιβλιοθήκη πρέπει να εγκατασταθεί για να χρησιμοποιήσει όλο τον καταπληκτικό κώδικα από το Hugging Face. Για να λάβω την τελευταία έκδοση θα την εγκαταστήσω απευθείας από το GitHub.
  • ml_πράγματα βιβλιοθήκη που χρησιμοποιείται για διάφορες εργασίες σχετικά με τη μηχανική μάθηση. Δημιούργησα αυτήν τη βιβλιοθήκη για να μειώσω τον αριθμό του κώδικα που πρέπει να γράψω για κάθε έργο μηχανικής εκμάθησης.
# 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

Εισαγωγές

Εισαγάγετε όλες τις απαραίτητες βιβλιοθήκες για αυτό το σημειωματάριο. Δηλώστε τις παραμέτρους που χρησιμοποιούνται για αυτό το σημειωματάριο:

  • set_seed(123) - Πάντα καλό να ρυθμίζετε έναν σταθερό σπόρο για αναπαραγωγιμότητα.
  • epochs - Αριθμός εποχών εκπαίδευσης (οι συγγραφείς προτείνουν μεταξύ 2 και 4).
  • batch_size – Αριθμός παρτίδων – ανάλογα με το μέγιστο μήκος ακολουθίας και τη μνήμη GPU. Για μήκος ακολουθίας 512, μια παρτίδα των 10 ΣΥΝΗΘΩΣ λειτουργεί χωρίς προβλήματα μνήμης. Για μικρό μήκος ακολουθίας, μπορείτε να δοκιμάσετε παρτίδα 32 ή υψηλότερη. max_length – Επιλογή ή περικοπή ακολουθιών κειμένου σε συγκεκριμένο μήκος. Θα το βάλω στο 60 για να επιταχύνω την προπόνηση.
  • device – Αναζητήστε gpu για χρήση. Θα χρησιμοποιεί cpu από προεπιλογή εάν δεν βρεθεί gpu.
  • model_name_or_path – Όνομα μοντέλου μετασχηματιστών – θα χρησιμοποιεί ήδη προεκπαιδευμένο μοντέλο. Path of transformer model – θα φορτώσει το δικό σας μοντέλο από τον τοπικό δίσκο. Σε αυτό το σεμινάριο θα χρησιμοποιήσω gpt2 μοντέλο.
  • labels_ids - Λεξικό ετικετών και το αναγνωριστικό τους - αυτό θα χρησιμοποιηθεί για τη μετατροπή ετικετών συμβολοσειρών σε αριθμούς.
  • n_labels - Πόσες ετικέτες χρησιμοποιούμε σε αυτό το σύνολο δεδομένων. Αυτό χρησιμοποιείται για να αποφασιστεί το μέγεθος της κεφαλής ταξινόμησης.
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)

Βοηθητικές λειτουργίες

Μου αρέσει να διατηρώ όλες τις τάξεις και τις λειτουργίες που θα χρησιμοποιηθούν σε αυτό το σημειωματάριο σε αυτήν την ενότητα για να διατηρήσω μια καθαρή εμφάνιση του φορητού υπολογιστή:

MovieReviewsDataset (Σύνολο δεδομένων)

Εάν έχετε εργαστεί με το PyTorch πριν, αυτό είναι αρκετά τυπικό. Χρειαζόμαστε αυτήν την κλάση για να διαβάσει στο σύνολο δεδομένων μας, να την αναλύσει και να επιστρέψει κείμενα με τις συσχετισμένες ετικέτες τους.

Σε αυτήν την τάξη χρειάζεται μόνο να διαβάσω το περιεχόμενο κάθε αρχείου, να χρησιμοποιήσω το fix_text για να διορθώσω τυχόν προβλήματα Unicode και να παρακολουθώ θετικά και αρνητικά συναισθήματα.

Θα προσθέσω όλα τα κείμενα και τις ετικέτες σε λίστες.

Υπάρχουν τρία κύρια μέρη αυτής της κλάσης συνόλου δεδομένων PyTorch:

  • μέσα σε αυτό() όπου διαβάζουμε στο σύνολο δεδομένων και μετατρέπουμε κείμενο και ετικέτες σε αριθμούς.
  • Λέν () όπου πρέπει να επιστρέψουμε τον αριθμό των παραδειγμάτων που διαβάσαμε. Αυτό χρησιμοποιείται όταν καλούμε το len(MovieReviewsDataset()).
  • getitem() λαμβάνει πάντα ως είσοδο μια τιμή int που αντιπροσωπεύει ποιο παράδειγμα από τα παραδείγματά μας να επιστρέψει από το σύνολο δεδομένων μας. Εάν περάσει μια τιμή 3, θα επιστρέψουμε το παράδειγμα από το σύνολο δεδομένων μας στη θέση 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

Χρησιμοποιώ αυτήν την κλάση για να δημιουργήσω το Data Collator. Αυτό θα χρησιμοποιηθεί στο DataLoader για να δημιουργήσει τα λουτρά των δεδομένων που τροφοδοτούνται στο μοντέλο. Χρησιμοποιώ το tokenizer και τον κωδικοποιητή ετικετών σε κάθε ακολουθία για να μετατρέψω κείμενα και ετικέτες σε αριθμούς.

Ευτυχώς για εμάς, το Hugging Face σκέφτηκε τα πάντα και έκανε το tokenizer να κάνει όλη τη βαριά ανύψωση (διαχωρισμός κειμένου σε μάρκες, συμπλήρωση, περικοπή, κωδικοποίηση κειμένου σε αριθμούς) και είναι πολύ εύκολο στη χρήση!

Υπάρχουν δύο κύρια μέρη αυτής της κατηγορίας Συλλογής δεδομένων:

  • μέσα σε αυτό() πού αρχικοποιούμε το tokenizer που σκοπεύουμε να χρησιμοποιήσουμε, πώς να κωδικοποιήσουμε τις ετικέτες μας και εάν χρειάζεται να ορίσουμε το μήκος της ακολουθίας σε διαφορετική τιμή.
  • κλήση() χρησιμοποιείται ως συλλέκτης συναρτήσεων που λαμβάνει ως είσοδο μια παρτίδα παραδειγμάτων δεδομένων. Πρέπει να επιστρέψει ένα αντικείμενο με τη μορφή που μπορεί να τροφοδοτηθεί στο μοντέλο μας. Ευτυχώς το tokenizer μας το κάνει αυτό για εμάς και επιστρέφει ένα λεξικό μεταβλητών έτοιμο να τροφοδοτηθεί στο μοντέλο με αυτόν τον τρόπο: model(**inputs). Δεδομένου ότι τελειοποιούμε το μοντέλο, συμπεριέλαβα και τις ετικέτες.
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

τρένο (dataloader, optimizer_, scheduler_, device_)

Δημιούργησα αυτήν τη συνάρτηση για να εκτελέσω ένα πλήρες πέρασμα μέσω του αντικειμένου DataLoader (το αντικείμενο DataLoader δημιουργείται από το αντικείμενο τύπου Dataset* χρησιμοποιώντας την κλάση **MovieReviewsDataset). Αυτό είναι βασικά ένα τρένο εποχής σε ολόκληρο το σύνολο δεδομένων.

Το πρόγραμμα φόρτωσης δεδομένων δημιουργείται από το PyTorch DataLoader που παίρνει το αντικείμενο που δημιουργήθηκε από την κλάση MovieReviewsDataset και τοποθετεί κάθε παράδειγμα σε παρτίδες. Με αυτόν τον τρόπο μπορούμε να τροφοδοτήσουμε παρτίδες δεδομένων του μοντέλου μας!

Το optimizer_ και το scheduler_ είναι πολύ κοινά στο PyTorch. Απαιτείται να ενημερώσουν τις παραμέτρους του μοντέλου μας και να ενημερώσουν το ρυθμό εκμάθησής μας κατά τη διάρκεια της εκπαίδευσης. Υπάρχουν πολλά περισσότερα από αυτό, αλλά δεν θα μπω σε λεπτομέρειες. Αυτό μπορεί στην πραγματικότητα να είναι μια τεράστια τρύπα κουνελιού, καθώς συμβαίνουν ΠΟΛΛΑ πίσω από αυτές τις λειτουργίες που δεν χρειάζεται να ανησυχούμε. Ευχαριστώ PyTorch!

Στη διαδικασία παρακολουθούμε τις πραγματικές ετικέτες και τις προβλεπόμενες ετικέτες μαζί με την απώλεια.

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

επικύρωση (dataloader, device_)

Εφάρμοσα αυτή τη λειτουργία με παρόμοιο τρόπο με το τρένο, αλλά χωρίς την ενημέρωση παραμέτρων, το πέρασμα προς τα πίσω και το ντεγκραντέ αξιοπρεπές τμήμα. Δεν χρειάζεται να κάνουμε όλες αυτές τις ΠΟΛΥ υπολογιστικά εντατικές εργασίες γιατί μας ενδιαφέρουν μόνο οι προβλέψεις του μοντέλου μας.

Χρησιμοποιώ το DataLoader με παρόμοιο τρόπο όπως στο τρένο για να βγάζω παρτίδες για να τροφοδοτήσω το μοντέλο μας.

Στη διαδικασία παρακολουθώ τις πραγματικές ετικέτες και τις προβλεπόμενες ετικέτες μαζί με την απώλεια.

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

Φόρτωση μοντέλου και Tokenizer

Φόρτωση των τριών βασικών μερών του προεκπαιδευμένου μετασχηματιστή GPT2: διαμόρφωση, tokenizer και μοντέλο.

Για αυτό το παράδειγμα θα χρησιμοποιήσω gpt2 από προεκπαιδευμένους μετασχηματιστές HuggingFace. Μπορείτε να χρησιμοποιήσετε όποιες παραλλαγές του GP2 θέλετε.

Κατά τη δημιουργία του model_config Θα αναφέρω τον αριθμό των ετικετών που χρειάζομαι για την εργασία μου κατάταξης. Εφόσον προβλέπω μόνο δύο συναισθήματα: θετικό και αρνητικό, θα χρειαστώ μόνο δύο ετικέτες num_labels.

Δημιουργία του tokenizer είναι αρκετά τυπικό όταν χρησιμοποιείτε τη βιβλιοθήκη Transformers. Μετά τη δημιουργία του tokenizer, είναι σημαντικό για αυτό το σεμινάριο να ρυθμίσετε το padding προς τα αριστερά tokenizer.padding_side = "left" και αρχικοποιήστε το διακριτικό συμπλήρωσης σε tokenizer.eos_token που είναι το αρχικό διακριτικό τέλους ακολουθίας του GPT2. Αυτό είναι το πιο ουσιαστικό μέρος αυτού του σεμιναρίου, καθώς το GPT2 χρησιμοποιεί το τελευταίο διακριτικό για πρόβλεψη, επομένως πρέπει να βάλουμε pad προς τα αριστερά.

Το HuggingFace έκανε ήδη το μεγαλύτερο μέρος της δουλειάς για εμάς και πρόσθεσε ένα επίπεδο ταξινόμησης στο μοντέλο GPT2. Στη δημιουργία του μοντέλου που χρησιμοποίησα GPT2ForSequenceClassification. Εφόσον έχουμε ένα προσαρμοσμένο διακριτικό συμπλήρωσης, πρέπει να το αρχικοποιήσουμε για το μοντέλο που χρησιμοποιεί model.config.pad_token_id. Τέλος θα χρειαστεί να μετακινήσουμε το μοντέλο στη συσκευή που ορίσαμε νωρίτερα.

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

Σύνολο δεδομένων και Collator

Εδώ δημιουργώ τα αντικείμενα PyTorch Dataset και Data Loader με Data Collator που θα χρησιμοποιηθούν για την τροφοδοσία δεδομένων στο μοντέλο μας.

Εδώ χρησιμοποιώ το Σύνολο δεδομένων MovieReviews τάξη για να δημιουργήσετε το σύνολο δεδομένων PyTorch που θα επιστρέφει κείμενα και ετικέτες.

Εφόσον πρέπει να εισάγουμε αριθμούς στο μοντέλο μας, πρέπει να μετατρέψουμε τα κείμενα και τις ετικέτες σε αριθμούς. Αυτός είναι ο σκοπός ενός συλλέκτη! Παίρνει δεδομένα που εξάγονται από το σύνολο δεδομένων PyTorch και περνούν από τη συνάρτηση Συλλογής δεδομένων για να εξάγει την ακολουθία για το μοντέλο μας.

Κρατώ το tokenizer μακριά από το σύνολο δεδομένων PyTorch για να κάνω τον κώδικα πιο καθαρό και καλύτερα δομημένο. Μπορείτε προφανώς να χρησιμοποιήσετε το tokenizer μέσα στο PyTorch Dataset και ακολουθίες εξόδου που μπορούν να χρησιμοποιηθούν κατευθείαν στο μοντέλο χωρίς τη χρήση συλλέκτη δεδομένων.

Συνιστώ ανεπιφύλακτα να χρησιμοποιήσετε ένα αρχείο κειμένου επικύρωσης για να προσδιορίσετε πόση εκπαίδευση απαιτείται για να αποφύγετε την υπερβολική εφαρμογή. Αφού καταλάβετε ποιες παράμετροι αποδίδουν τα καλύτερα αποτελέσματα, το αρχείο επικύρωσης μπορεί να ενσωματωθεί στο τρένο και να εκτελέσετε ένα τελικό τρένο με ολόκληρο το σύνολο δεδομένων.

Ο συλλέκτης δεδομένων χρησιμοποιείται για τη μορφοποίηση των εξόδων του συνόλου δεδομένων PyTorch ώστε να ταιριάζουν με τις εισόδους που απαιτούνται για το 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!

Τρένο

Δημιούργησα τη χρήση βελτιστοποιητή και προγραμματιστή από την PyTorch στην εκπαίδευση. Χρησιμοποίησα τις πιο κοινές παραμέτρους που χρησιμοποιούνται από μοντέλα μετασχηματιστών.

Έκανα βρόχο μέσω του αριθμού των καθορισμένων εποχών και καλώ το τρένο και  επικύρωση λειτουργίες.

Προσπαθώ να βγάζω παρόμοιες πληροφορίες μετά από κάθε εποχή όπως το Keras: train_loss: - val_loss: - train_acc: - valid_acc.

Μετά την εκπαίδευση, σχεδιάστε το τρένο και τις καμπύλες απώλειας και ακρίβειας επικύρωσης για να ελέγξετε πώς πήγε η εκπαίδευση.

Σημείωση: Τα σχέδια εκπαίδευσης μπορεί να φαίνονται λίγο περίεργα: Η ακρίβεια επικύρωσης ξεκινά υψηλότερη από την ακρίβεια εκπαίδευσης και η απώλεια επικύρωσης ξεκινά χαμηλότερη από την απώλεια εκπαίδευσης. Κανονικά αυτό θα είναι το αντίθετο. Υποθέτω ότι ο διαχωρισμός των δεδομένων τυχαίνει να είναι ευκολότερος για το μέρος επικύρωσης ή πολύ δύσκολος για το τμήμα εκπαίδευσης ή και τα δύο. Επειδή αυτό το σεμινάριο αφορά τη χρήση του GPT2 για ταξινόμηση, δεν θα ανησυχώ πολύ για τα αποτελέσματα του μοντέλου.

# 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
Απώλεια αμαξοστοιχίας και επικύρωσης.
Ακρίβεια εκπαίδευσης και επικύρωσης.

Αξιολογώ

Όταν ασχολούμαστε με την ταξινόμηση, είναι χρήσιμο να εξετάσουμε την ανάκληση ακριβείας και τη βαθμολογία F1.

Ένας καλός μετρητής που πρέπει να έχετε κατά την αξιολόγηση ενός μοντέλου είναι ο πίνακας σύγχυσης.

# 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
Ομαλοποιήθηκε ο πίνακας σύγχυσης.

τελική σημείωση

Αν το έχετε φτάσει μέχρι τώρα Συγχαρητήρια! 🎊 και Ευχαριστώ! 🙏 για το ενδιαφέρον σας για το σεμινάριό μου!

Χρησιμοποιώ αυτόν τον κώδικα εδώ και αρκετό καιρό και πιστεύω ότι έφτασε σε ένα σημείο όπου είναι όμορφα τεκμηριωμένο και εύκολο στην παρακολούθηση.

Φυσικά είναι εύκολο να το ακολουθήσω γιατί το έφτιαξα. Γι 'αυτό τα σχόλια είναι ευπρόσδεκτα και με βοηθούν να βελτιώσω τα μελλοντικά μου μαθήματα!

Αν δείτε κάτι λάθος, ενημερώστε με ανοίγοντας ένα ζήτημα στο δικό μου ml_things GitHub αποθετήριο!

Πολλά μαθήματα εκεί έξω είναι ως επί το πλείστον ένα πράγμα και δεν συντηρούνται. Σκοπεύω να ενημερώνω τα μαθήματά μου όσο περισσότερο μπορώ.

Αυτό το άρθρο δημοσιεύθηκε αρχικά στις Ο προσωπικός ιστότοπος του George Mihaila  και εκδόθηκε εκ νέου στο TOPBOTS με την άδεια του συντάκτη.

Σας αρέσει αυτό το άρθρο; Εγγραφείτε για περισσότερες ενημερώσεις AI.

Θα σας ενημερώσουμε όταν κυκλοφορούμε περισσότερη τεχνική εκπαίδευση.

Πηγή: https://www.topbots.com/gpt2-text-classification-using-hugging-face-transformers/

Σφραγίδα ώρας:

Περισσότερα από ΚΟΡΥΦΑΙΑ