GPT2 para classificação de texto usando transformadores de rosto abraços

Nó Fonte: 809063

classificação de texto

Este notebook é usado para ajustar o modelo GPT2 para classificação de texto usando Abraçando o rosto transformadores biblioteca em um conjunto de dados personalizado.

Hugging Face é muito bom para nós incluir todas as funcionalidades necessárias para que o GPT2 seja usado em tarefas de classificação. Obrigado cara de abraço!

Não consegui encontrar muitas informações sobre como usar o GPT2 para classificação, então decidi fazer este tutorial usando uma estrutura semelhante com outros modelos de transformadores.

Se este conteúdo educacional aprofundado for útil para você, assine nossa lista de discussão sobre pesquisa em IA para ser alertado quando lançarmos novo material. 

Ideia principal: Como o GPT2 é um transformador decodificador, o último token da sequência de entrada é usado para fazer previsões sobre o próximo token que deve seguir a entrada. Isso significa que o último token da sequência de entrada contém todas as informações necessárias na previsão. Com isso em mente, podemos usar essa informação para fazer uma previsão em uma tarefa de classificação em vez de uma tarefa de geração.

Em outras palavras, em vez de usar o primeiro token embedding para fazer previsões como fazemos em Bert, usaremos o último token embedding para fazer previsões com GPT2.

Como só nos importamos com o primeiro token em Bert, estávamos indo para a direita. Agora, no GPT2, estamos usando o último token para predição, portanto, precisaremos preencher à esquerda. Por causa de uma boa atualização para os transformadores HuggingFace, podemos configurar o Tokenizer GPT2 para fazer exatamente isso.

O que devo saber sobre este notebook?

Como estou usando o PyTorch para ajustar nossos modelos de transformadores, qualquer conhecimento sobre o PyTorch é muito útil.

Conhecendo um pouco sobre o transformadores a biblioteca também ajuda.

Como usar este notebook?

Como em todo projeto, construí este notebook pensando na reutilização.

Todas as mudanças acontecerão na parte de processamento de dados, onde você precisa personalizar o PyTorch Dataset, Data Collator e DataLoader para atender às suas próprias necessidades de dados.

Todos os parâmetros que podem ser alterados estão sob o Importações seção. Cada parâmetro é bem comentado e estruturado para ser o mais intuitivo possível.

Conjunto de dados

Este bloco de notas cobrirá transformadores de pré-treinamento em um conjunto de dados personalizado. Vou usar as críticas de filmes bem conhecidas positivas - negativas rotuladas Conjunto de dados de revisão de filme grande.

A descrição fornecida no site de Stanford:

Este é um conjunto de dados para classificação de sentimento binário contendo substancialmente mais dados do que os conjuntos de dados de referência anteriores. Oferecemos um conjunto de 25,000 críticas de filmes altamente polares para treinamento e 25,000 para testes. Existem dados adicionais não rotulados para uso também. São fornecidos formatos de texto bruto e saco de palavras já processado. Consulte o arquivo README contido no release para obter mais detalhes.

Por que este conjunto de dados? Acredito que seja um conjunto de dados fácil de entender e usar para classificação. Acho que é sempre divertido trabalhar com dados de sentimento.

Codificação

Agora vamos programar! Iremos examinar cada célula de codificação no notebook e descrever o que ela faz, qual é o código e quando é relevante - mostrar a saída.

Fiz esse formato para ser fácil de seguir se você decidir executar cada célula de código em seu próprio bloco de notas Python.

Quando aprendo com um tutorial, sempre tento replicar os resultados. Acredito que seja fácil acompanhar se você tiver o código ao lado das explicações.

Downloads

Faça o download do Conjunto de dados de revisão de filme grande e descompacte-o 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

Instalação

  • transformadores A biblioteca precisa ser instalada para usar todo o código incrível do Hugging Face. Para obter a versão mais recente, irei instalá-la diretamente do GitHub.
  • ml_coisas biblioteca usada para várias tarefas relacionadas ao aprendizado de máquina. Criei essa biblioteca para reduzir a quantidade de código que preciso escrever para cada projeto de aprendizado de máquina.
# 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

Importações

Importe todas as bibliotecas necessárias para este bloco de notas. Parâmetros de declaração usados ​​para este bloco de notas:

  • set_seed(123) - É sempre bom definir uma semente fixa para reprodutibilidade.
  • epochs - Número de épocas de treinamento (os autores recomendam entre 2 e 4).
  • batch_size - Número de lotes - dependendo do comprimento máximo da sequência e da memória da GPU. Para 512 sequências de comprimento, um lote de 10 normalmente funciona sem problemas de memória cuda. Para sequências pequenas, tente lote de 32 ou superior. max_length - Preencher ou truncar sequências de texto para um comprimento específico. Vou definir para 60 para acelerar o treinamento.
  • device - Procure gpu para usar. Usará cpu por padrão se nenhuma GPU for encontrada.
  • model_name_or_path - Nome do modelo dos transformadores - utilizará o modelo pré-treinado. Caminho do modelo do transformador - carregará seu próprio modelo do disco local. Neste tutorial vou usar gpt2 modelo.
  • labels_ids - Dicionário de rótulos e seus id - isso será usado para converter rótulos de string em números.
  • n_labels - Quantos rótulos estamos usando neste conjunto de dados. Isso é usado para decidir o tamanho da cabeça de classificação.
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)

Funções auxiliares

Eu gosto de manter todas as classes e funções que serão usadas neste notebook nesta seção para ajudar a manter uma aparência limpa do notebook:

MovieReviewsDataset (conjunto de dados)

Se você já trabalhou com o PyTorch antes, isso é bastante normal. Precisamos dessa classe para ler nosso conjunto de dados, analisá-lo e retornar textos com seus rótulos associados.

Nesta aula, eu só preciso ler o conteúdo de cada arquivo, usar fix_text para corrigir quaisquer problemas de Unicode e acompanhar os sentimentos positivos e negativos.

Vou anexar todos os textos e rótulos nas listas.

Existem três partes principais desta classe PyTorch Dataset:

  • iniciar() onde lemos o conjunto de dados e transformamos o texto e os rótulos em números.
  • len () onde precisamos retornar o número de exemplos lidos. Isso é usado ao chamar len (MovieReviewsDataset ()).
  • getitem () sempre toma como entrada um valor int que representa qual exemplo de nossos exemplos retornar de nosso conjunto de dados. Se um valor de 3 for passado, retornaremos o exemplo de nosso conjunto de dados na posição 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

Eu uso essa classe para criar o Data Collator. Isso será usado no DataLoader para criar os banhos de dados que são alimentados para o modelo. Eu uso o tokenizer e o codificador de rótulo em cada sequência para converter textos e rótulos em número.

Para nossa sorte, o Hugging Face pensou em tudo e fez com que o tokenizer fizesse todo o trabalho pesado (dividir o texto em tokens, preencher, truncar, codificar o texto em números) e é muito fácil de usar!

Existem duas partes principais desta classe Data Collator:

  • iniciar() onde inicializamos o tokenizer que planejamos usar, como codificar nossos rótulos e se precisamos definir o comprimento da sequência com um valor diferente.
  • ligar() usado como intercalador de função que recebe como entrada um lote de exemplos de dados. Ele precisa retornar um objeto com o formato que pode ser alimentado para nosso modelo. Felizmente, nosso tokenizer faz isso para nós e retorna um dicionário de variáveis ​​prontas para serem alimentadas ao modelo desta maneira: model(**inputs). Como estamos ajustando o modelo, também incluí os rótulos.
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

treinar (dataloader, otimizador_, planejador_, dispositivo_)

Criei essa função para realizar uma passagem completa pelo objeto DataLoader (o objeto DataLoader é criado a partir de nosso objeto do tipo Dataset * usando a classe ** MovieReviewsDataset). Este é basicamente um trem de época através de todo o conjunto de dados.

O dataloader é criado a partir do PyTorch DataLoader, que pega o objeto criado na classe MovieReviewsDataset e coloca cada exemplo em lotes. Desta forma, podemos alimentar nossos lotes de dados do modelo!

O optimizer_ e o scheduler_ são muito comuns no PyTorch. Eles são necessários para atualizar os parâmetros de nosso modelo e atualizar nossa taxa de aprendizagem durante o treinamento. Há muito mais do que isso, mas não vou entrar em detalhes. Isso pode ser uma grande toca de coelho, já que MUITO acontece por trás dessas funções com as quais não precisamos nos preocupar. Obrigado PyTorch!

No processo, acompanhamos os rótulos reais e previstos junto com a perda.

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

validação (dataloader, device_)

Implementei esta função de uma forma muito semelhante ao trem, mas sem a atualização dos parâmetros, passagem para trás e parte decente do gradiente. Não precisamos fazer todas essas tarefas MUITO intensas em termos de computação porque nos preocupamos apenas com as previsões do nosso modelo.

Eu uso o DataLoader de uma forma semelhante à do trem para obter lotes para alimentar nosso modelo.

No processo, acompanho os rótulos reais e previstos junto com a perda.

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

Carregar modelo e tokenizador

Carregando as três partes essenciais do transformador GPT2 pré-treinado: configuração, tokenizer e modelo.

Para este exemplo, vou usar gpt2 dos transformadores pré-treinados HuggingFace. Você pode usar qualquer variação do GP2 que desejar.

Ao criar o model_config Mencionarei o número de rótulos de que preciso para minha tarefa de classificação. Uma vez que só prevejo dois sentimentos: positivo e negativo, só vou precisar de dois rótulos para num_labels.

Criando o tokenizer é bastante padrão ao usar a biblioteca Transformers. Depois de criar o tokenizer, é fundamental para este tutorial definir o preenchimento à esquerda tokenizer.padding_side = "left" e inicializar o token de preenchimento para tokenizer.eos_token que é o token de fim de sequência original do GPT2. Esta é a parte mais essencial deste tutorial, já que o GPT2 usa o último token para predição, então precisamos preencher para a esquerda.

HuggingFace já fez a maior parte do trabalho para nós e adicionou uma camada de classificação ao modelo GPT2. Na criação do modelo que usei GPT2ForSequenceClassification. Uma vez que temos um token de preenchimento personalizado, precisamos inicializá-lo para o modelo usando model.config.pad_token_id. Finalmente, precisaremos mover o modelo para o 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 dados e alceador

É aqui que crio o conjunto de dados PyTorch e o carregador de dados com objetos Data Collator que serão usados ​​para alimentar o nosso modelo.

É aqui que eu uso o Conjunto de dados de resenhas de filmes classe para criar o Dataset PyTorch que retornará textos e rótulos.

Como precisamos inserir números em nosso modelo, precisamos converter os textos e rótulos em números. Este é o propósito de um alceador! Leva os dados gerados pelo Dataset PyTorch e passados ​​pela função Data Collator para gerar a sequência para o nosso modelo.

Estou mantendo o tokenizer longe do conjunto de dados PyTorch para tornar o código mais limpo e melhor estruturado. Obviamente, você pode usar o tokenizer dentro do conjunto de dados PyTorch e sequências de saída que podem ser usadas diretamente no modelo sem usar um Data Collator.

Eu recomendo fortemente o uso de um arquivo de texto de validação para determinar quanto treinamento é necessário para evitar overfitting. Depois de descobrir quais parâmetros geram os melhores resultados, o arquivo de validação pode ser incorporado ao trem e executar um trem final com todo o conjunto de dados.

O colador de dados é usado para formatar as saídas do conjunto de dados PyTorch para corresponder às entradas necessárias 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!

Trem

Criei o otimizador e o planejador para uso do PyTorch em treinamento. Usei os parâmetros mais comuns usados ​​por modelos de transformadores.

Percorri o número de épocas definidas e chamei o trem e validação funções.

Estou tentando gerar informações semelhantes após cada época como Keras: train_loss: - val_loss: - train_acc: - valid_acc.

Após o treinamento, plote as curvas de perda e precisão do trem e da validação para verificar como foi o treinamento.

Observação: Os gráficos de treinamento podem parecer um pouco estranhos: a precisão da validação começa mais alta do que a precisão do treinamento e a perda de validação começa abaixo da perda do treinamento. Normalmente, será o oposto. Presumo que a divisão de dados seja mais fácil para a parte de validação ou muito difícil para a parte de treinamento ou ambos. Como este tutorial é sobre como usar o GPT2 para classificação, não vou me preocupar muito com os resultados do 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
Perda de treinamento e validação.
Precisão de treinamento e validação.

Avaliação

Ao lidar com a classificação, é útil observar a recuperação de precisão e a pontuação F1.

Um bom indicador para avaliar um modelo é a matriz de confusão.

# 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 confusão normalizada.

Nota final

Se você chegou até aqui Parabéns! 🎊 e Obrigado! 🙏 pelo seu interesse no meu tutorial!

Estou usando esse código há algum tempo e sinto que ele chegou a um ponto em que é bem documentado e fácil de seguir.

É claro que é fácil para mim seguir porque eu o construí. É por isso que qualquer feedback é bem-vindo e me ajuda a melhorar meus tutoriais futuros!

Se você vir algo errado, por favor, me avise abrindo um problema no meu repositório GitHub ml_things!

Muitos tutoriais por aí são, em sua maioria, uma coisa única e não estão sendo mantidos. Pretendo manter meus tutoriais atualizados o máximo que puder.

Este artigo foi originalmente publicado em Site pessoal de George Mihaila  e republicado no TOPBOTS com permissão do autor.

Gostou deste artigo? Inscreva-se para mais atualizações de IA.

Avisaremos quando lançarmos mais educação técnica.

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

Carimbo de hora:

Mais de TOPBOTS