GPT2 para clasificación de texto usando transformadores faciales abrazados

Nodo de origen: 809063

clasificación de texto

Este cuaderno se utiliza para ajustar el modelo GPT2 para la clasificación de texto utilizando Abrazando la cara transformers biblioteca en un conjunto de datos personalizado.

Hugging Face es muy agradable para nosotros al incluir toda la funcionalidad necesaria para que GPT2 se use en tareas de clasificación. ¡Gracias Cara Abrazadora!

No pude encontrar mucha información sobre cómo usar GPT2 para la clasificación, así que decidí hacer este tutorial usando una estructura similar con otros modelos de transformadores.

Si este contenido educativo en profundidad es útil para usted, suscríbete a nuestra lista de correo de investigación de IA ser alertado cuando lancemos nuevo material. 

Idea principal: Dado que GPT2 es un transformador decodificador, el último token de la secuencia de entrada se utiliza para hacer predicciones sobre el siguiente token que debe seguir a la entrada. Esto significa que el último token de la secuencia de entrada contiene toda la información necesaria en la predicción. Con esto en mente, podemos usar esa información para hacer una predicción en una tarea de clasificación en lugar de una tarea de generación.

En otras palabras, en lugar de usar la incrustación del primer token para hacer predicciones como lo hacemos en Bert, usaremos la incrustación del último token para hacer predicciones con GPT2.

Como solo nos importaba la primera ficha de Bert, nos dirigíamos hacia la derecha. Ahora en GPT2 estamos usando el último token para la predicción, por lo que tendremos que rellenar a la izquierda. Gracias a una buena actualización de HuggingFace Transformers, podemos configurar el Tokenizer GPT2 para hacer precisamente eso.

¿Qué debo saber para este portátil?

Dado que estoy usando PyTorch para ajustar nuestros modelos de transformadores, cualquier conocimiento sobre PyTorch es muy útil.

Sabiendo un poco sobre el transformers la biblioteca también ayuda.

¿Cómo usar este cuaderno?

Como con todos los proyectos, construí este portátil pensando en la reutilización.

Todos los cambios se producirán en la parte de procesamiento de datos, donde debe personalizar el conjunto de datos de PyTorch, el recopilador de datos y el cargador de datos para que se adapten a sus propias necesidades de datos.

Todos los parámetros que se pueden cambiar se encuentran bajo la Importaciones sección. Cada parámetro está bien comentado y estructurado para que sea lo más intuitivo posible.

Conjunto de datos

Este cuaderno cubrirá la formación previa a los transformadores en un conjunto de datos personalizado. Usaré las reseñas de películas conocidas como positivas - negativas etiquetadas Gran conjunto de datos de revisión de películas.

La descripción proporcionada en el sitio web de Stanford:

Este es un conjunto de datos para la clasificación de sentimiento binario que contiene sustancialmente más datos que los conjuntos de datos de referencia anteriores. Ofrecemos un conjunto de 25,000 reseñas de películas muy polares para entrenamiento y 25,000 para pruebas. También hay datos adicionales sin etiquetar para su uso. Se proporcionan formatos de texto sin formato y bolsa de palabras ya procesada. Consulte el archivo README incluido en la versión para obtener más detalles.

¿Por qué este conjunto de datos? Creo que es un conjunto de datos fácil de entender y usar para la clasificación. Creo que siempre es divertido trabajar con los datos de opinión.

Codificación

¡Ahora hagamos un poco de codificación! Revisaremos cada celda de codificación en el cuaderno y describiremos lo que hace, cuál es el código y cuándo es relevante: mostrar el resultado.

Hice este formato para que sea fácil de seguir si decide ejecutar cada celda de código en su propio cuaderno de Python.

Cuando aprendo de un tutorial, siempre trato de replicar los resultados. Creo que es fácil de seguir si tiene el código junto a las explicaciones.

Descargas

Descargue nuestra Gran conjunto de datos de revisión de películas y descomprímalo localmente.

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

Se instala

  • transformers La biblioteca debe estar instalada para usar todo el increíble código de Hugging Face. Para obtener la última versión, la instalaré directamente desde GitHub.
  • ml_cosas biblioteca utilizada para diversas tareas relacionadas con el aprendizaje automático. Creé esta biblioteca para reducir la cantidad de código que necesito escribir para cada proyecto de aprendizaje automático.
# 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

Importaciones

Importe todas las bibliotecas necesarias para este cuaderno. Declare los parámetros utilizados para este cuaderno:

  • set_seed(123) - Siempre es bueno establecer una semilla fija para la reproducibilidad.
  • epochs - Número de épocas de entrenamiento (los autores recomiendan entre 2 y 4).
  • batch_size - Número de lotes: según la longitud máxima de secuencia y la memoria de la GPU. Para una longitud de secuencia de 512, un lote de 10 normalmente funciona sin problemas de memoria cuda. Para una secuencia pequeña, puede probar lotes de 32 o más. max_length: rellena o trunca secuencias de texto a una longitud específica. Lo pondré en 60 para acelerar el entrenamiento.
  • device - Busque gpu para usar. Utilizará cpu de forma predeterminada si no se encuentra ninguna gpu.
  • model_name_or_path - Nombre del modelo de transformadores: utilizará el modelo ya entrenado. Ruta del modelo de transformador: cargará su propio modelo desde el disco local. En este tutorial usaré gpt2 modelo.
  • labels_ids - Diccionario de etiquetas y su identificación: se utilizará para convertir etiquetas de cadena en números.
  • n_labels - Cuántas etiquetas estamos usando en este conjunto de datos. Esto se usa para decidir el tamaño del cabezal de clasificación.
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)

Funciones auxiliares

Me gusta mantener todas las clases y funciones que se utilizarán en este cuaderno en esta sección para ayudar a mantener un aspecto limpio del cuaderno:

MovieReviewsDataset (conjunto de datos)

Si trabajó con PyTorch antes, esto es bastante estándar. Necesitamos esta clase para leer en nuestro conjunto de datos, analizarlo y devolver textos con sus etiquetas asociadas.

En esta clase, solo necesito leer el contenido de cada archivo, usar fix_text para solucionar cualquier problema de Unicode y realizar un seguimiento de los sentimientos positivos y negativos.

Agregaré todos los textos y etiquetas en listas.

Hay tres partes principales de esta clase de conjunto de datos de PyTorch:

  • en eso() donde leemos en el conjunto de datos y transformamos el texto y las etiquetas en números.
  • len () donde necesitamos devolver el número de ejemplos que leemos. Esto se usa cuando se llama a len (MovieReviewsDataset ()).
  • obtiene el objeto() siempre toma como entrada un valor int que representa qué ejemplo de nuestros ejemplos devolver de nuestro conjunto de datos. Si se pasa un valor de 3, devolveremos el ejemplo de nuestro conjunto de datos en la posición 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]}

Gpt2ClasificaciónCollator

Utilizo esta clase para crear el Data Collator. Esto se utilizará en el DataLoader para crear los grupos de datos que se alimentan al modelo. Utilizo el tokenizador y el codificador de etiquetas en cada secuencia para convertir textos y etiquetas en números.

Por suerte para nosotros, Hugging Face pensó en todo e hizo que el tokenizador hiciera todo el trabajo pesado (dividir el texto en tokens, rellenar, truncar, codificar el texto en números) ¡y es muy fácil de usar!

Hay dos partes principales de esta clase Data Collator:

  • en eso() dónde inicializamos el tokenizador que planeamos usar, cómo codificar nuestras etiquetas y si necesitamos establecer la longitud de la secuencia en un valor diferente.
  • llamada() se utiliza como comparador de funciones que toma como entrada un lote de ejemplos de datos. Necesita devolver un objeto con el formato que se puede alimentar a nuestro modelo. Afortunadamente, nuestro tokenizador lo hace por nosotros y devuelve un diccionario de variables listo para ser alimentado al modelo de esta manera: model(**inputs). Como estamos afinando el modelo, también incluí las etiquetas.
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 (cargador de datos, optimizador_, planificador_, dispositivo_)

Creé esta función para realizar una pasada completa a través del objeto DataLoader (el objeto DataLoader se crea a partir de nuestro objeto de tipo Dataset * usando la clase ** MovieReviewsDataset). Este es básicamente un tren de época a través de todo el conjunto de datos.

El cargador de datos se crea a partir de PyTorch DataLoader, que toma el objeto creado a partir de la clase MovieReviewsDataset y coloca cada ejemplo en lotes. ¡De esta manera podemos alimentar nuestros lotes de datos de modelos!

El optimizador_ y el planificador_ son muy comunes en PyTorch. Son necesarios para actualizar los parámetros de nuestro modelo y actualizar nuestra tasa de aprendizaje durante el entrenamiento. Hay mucho más que eso, pero no entraré en detalles. En realidad, esto puede ser un gran agujero de conejo, ya que hay MUCHAS cosas detrás de estas funciones que no debemos preocuparnos. ¡Gracias PyTorch!

En el proceso, realizamos un seguimiento de las etiquetas reales y las etiquetas previstas junto con la pérdida.

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

validación (cargador de datos, dispositivo_)

Implementé esta función de una manera muy similar a la del tren, pero sin la actualización de los parámetros, el paso hacia atrás y la parte decente del gradiente. No necesitamos hacer todas esas tareas MUY intensivas desde el punto de vista computacional porque solo nos preocupan las predicciones de nuestro modelo.

Utilizo el DataLoader de manera similar a como en el tren para sacar lotes para alimentar a nuestro modelo.

En el proceso, hago un seguimiento de las etiquetas reales y las etiquetas previstas junto con la pérdida.

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

Modelo de carga y tokenizador

Carga de las tres partes esenciales del transformador GPT2 preentrenado: configuración, tokenizador y modelo.

Para este ejemplo usaré gpt2 de transformadores pre-entrenados HuggingFace. Puede utilizar cualquier variación de GP2 que desee.

Al crear el model_config Mencionaré la cantidad de etiquetas que necesito para mi tarea de clasificación. Como solo predigo dos sentimientos: positivo y negativo, solo necesitaré dos etiquetas para num_labels.

Creando el tokenizer es bastante estándar cuando se usa la biblioteca Transformers. Después de crear el tokenizador, es fundamental que este tutorial establezca el relleno a la izquierda tokenizer.padding_side = "left" e inicializar el token de relleno para tokenizer.eos_token que es el token de fin de secuencia original de GPT2. Esta es la parte más esencial de este tutorial, ya que GPT2 usa el último token para la predicción, por lo que debemos desplazarnos hacia la izquierda.

HuggingFace ya hizo la mayor parte del trabajo por nosotros y agregó una capa de clasificación al modelo GPT2. Al crear el modelo que utilicé GPT2ForSequenceClassification. Dado que tenemos un token de relleno personalizado, debemos inicializarlo para el modelo usando model.config.pad_token_id. Finalmente, necesitaremos mover el modelo al dispositivo que definimos anteriormente.

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

Conjunto de datos y clasificador

Aquí es donde creo los objetos PyTorch Dataset y Data Loader con Data Collator que se utilizarán para introducir datos en nuestro modelo.

Aquí es donde uso el PelículaComentariosConjunto de datos class para crear el conjunto de datos PyTorch que devolverá textos y etiquetas.

Dado que necesitamos ingresar números en nuestro modelo, necesitamos convertir los textos y las etiquetas en números. ¡Este es el propósito de una compaginadora! Toma datos generados por PyTorch Dataset y pasados ​​a través de la función Data Collator para generar la secuencia para nuestro modelo.

Mantengo el tokenizador alejado del conjunto de datos de PyTorch para que el código sea más limpio y esté mejor estructurado. Obviamente, puede usar el tokenizador dentro del conjunto de datos de PyTorch y las secuencias de salida que se pueden usar directamente en el modelo sin usar un clasificador de datos.

Recomiendo encarecidamente utilizar un archivo de texto de validación para determinar cuánta formación se necesita para evitar el sobreajuste. Después de averiguar qué parámetros producen los mejores resultados, el archivo de validación se puede incorporar en el tren y ejecutar un tren final con todo el conjunto de datos.

El clasificador de datos se utiliza para formatear las salidas del conjunto de datos de PyTorch para que coincidan con las entradas necesarias para 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!

Entrenar

Creé el uso de optimizador y programador de PyTorch en el entrenamiento. Usé los parámetros más comunes utilizados por los modelos de transformadores.

Recorrí el número de épocas definidas y llamé al Presión en y validación funciones.

Estoy tratando de generar información similar después de cada época como Keras: train_loss: - val_loss: - train_acc: - valid_acc.

Después del entrenamiento, trace las curvas de pérdida y precisión del tren y de validación para verificar cómo fue el entrenamiento.

Nota:  Los gráficos de entrenamiento pueden parecer un poco extraños: la precisión de la validación comienza por encima de la precisión del entrenamiento y la pérdida de validación comienza por debajo de la pérdida de entrenamiento. Normalmente esto será lo contrario. Supongo que la división de datos es más fácil para la parte de validación o demasiado difícil para la parte de entrenamiento o ambas. Dado que este tutorial trata sobre el uso de GPT2 para la clasificación, no me preocuparé demasiado por los resultados del modelo.

# 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
Pérdida de entrenamiento y validación.
Precisión de entrenamiento y validación.

Evaluar

Cuando se trata de clasificación, es útil observar la recuperación de precisión y la puntuación F1.

Un buen indicador para evaluar un modelo es la matriz de confusión.

# 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
Matriz de confusión normalizada.

Nota final

Si llegaste tan lejos Congrats! 🎊 y Gracias! 🙏 ¡por tu interés en mi tutorial!

He estado usando este código por un tiempo y siento que llegó a un punto en el que está bien documentado y es fácil de seguir.

Por supuesto, es fácil de seguir para mí porque lo construí. ¡Es por eso que cualquier comentario es bienvenido y me ayuda a mejorar mis futuros tutoriales!

Si ve algo mal, avíseme abriendo un problema en mi ml_things repositorio de GitHub!

Muchos de los tutoriales que existen son en su mayoría algo que se realiza una sola vez y no se mantienen. Planeo mantener mis tutoriales actualizados tanto como pueda.

Este artículo se publicó originalmente el Sitio web personal de George Mihaila  y re-publicado a TOPBOTS con permiso del autor.

¿Disfrutas este artículo? Regístrese para recibir más actualizaciones de IA.

Te avisaremos cuando publiquemos más educación técnica.

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

Sello de tiempo:

Mas de TOPBOTS