RoBERTa: Um método otimizado para o pré-treinamento de sistemas de PLN autossupervisionados
Modelos de linguagem pré-treinados alcançaram um sucesso impressionante em processamento de linguagem natural (NLP), levando a uma mudança de paradigma do aprendizado supervisionado para o pré-treinamento seguido de ajuste fino. O objetivo da modelagem de linguagem é prever o próximo token em uma sequência, dado um histórico de textos não anotados, que são grandes quantidades de dados de texto bruto que não foram rotulados com informações específicas. BERT (Representações de Codificador Bidirecional de Transformers) estabelece novos padrões para esse conceito ao possibilitar a compreensão bidirecional da linguagem, pois analisa a frase inteira, não apenas uma palavra por vez. Ele considera as palavras antes e depois para entender melhor seu significado.
No entanto, o principal problema encontrado no BERT foi seu treinamento insuficiente, o que limitou seu desempenho em tarefas de NLP. Essa limitação levou os pesquisadores a explorar metodologias de treinamento aprimoradas em modelos subsequentes, como o RoBERTa.
RoBERTa (Uma Abordagem de Pré-treinamento BERT Robustamente Otimizada) é uma versão aprimorada do BERT projetada para abordar suas limitações. O RoBERTa introduziu várias melhorias importantes que aprimoram seu desempenho em diversos problemas de NLP.
Este artigo discutirá as metodologias e tecnologias usadas no desenvolvimento do RoBERTa, incluindo sua abordagem de treinamento, os resultados que alcançou e as possíveis oportunidades futuras de pesquisa que ele abre.
Uma rápida introdução ao BERT (Representações de Codificador Bidirecional de Transformers)
Para entender o RoBERTa, é essencial entender seu predecessor, o BERT, e os desafios que ele enfrentou. O BERT introduziu o conceito de transformers bidirecionais, permitindo que modelos de aprendizado profundo entendessem o contexto de uma forma anteriormente inatingível.
Mas, para realmente entender como o BERT funciona, precisamos dividi-lo em partes. Então, vamos examinar mais de perto sua arquitetura e como ele foi treinado.
Arquitetura e processo de pré-treinamento do BERT
A arquitetura do BERT é baseada em transformers, introduzidos por Devlin et al. em 2018. Ela usa um codificador bidirecional multicamadas (da esquerda para a direita e da direita para a esquerda) para ponderar a importância de diferentes palavras em uma frase.
Arquitetura do BERT
Figura 1: Arquitetura do BERT
Uma palavra começa com sua representação de embedding a partir da camada de embedding; um embedding é um vetor denso (representação numérica) de uma palavra ou token em um espaço de alta dimensionalidade. A camada de embedding é a primeira camada em uma rede neural que converte palavras de entrada nesses vetores densos. Cada camada realiza cálculos de atenção multi-head na representação da palavra da camada anterior para gerar uma nova representação intermediária. Todas essas representações intermediárias têm o mesmo tamanho. Na figura acima, E1 é a representação de embedding, T1 é a saída final e Trm é a representação intermediária do token.
O processo de pré-treinamento do BERT inclui duas tarefas principais:
Modelagem de Linguagem Mascarada (MLM)
Predição da Próxima Frase (NSP)
A modelagem de linguagem prevê a próxima palavra dada uma sequência de palavras. Na tarefa MLM, porém, em vez de prever cada próximo token, uma porcentagem dos tokens de entrada é mascarada aleatoriamente, e apenas esses tokens mascarados são previstos. A tarefa NSP, por outro lado, é uma tarefa de classificação binária que prevê se duas frases fornecidas se seguem no texto original. Essa abordagem ajuda o modelo a entender as relações entre as frases.
Next Sentence Prediction
Figura 2: Next Sentence Prediction
O processo de pré-treinamento do BERT tinha limitações que o impediam de alcançar todo o seu potencial. Um dos principais problemas era o uso de um padrão de mascaramento estático na tarefa MLM. No BERT, uma vez que uma palavra era mascarada durante o treinamento, as mesmas palavras eram mascaradas em todas as iterações. Essa abordagem estática limitava o modelo a cenários de mascaramento diversos, reduzindo sua capacidade de generalização. Além disso, o tamanho e a duração dos dados de treinamento também eram limitados.
Essas limitações levaram a inconsistências no desempenho do BERT em tarefas específicas de domínio, como análise de textos jurídicos ou médicos, e em cenários complexos de compreensão de linguagem, como análise de sentimentos ou raciocínio em múltiplas etapas. Abordar essas deficiências requer mais pesquisa e desenvolvimento.
O Surgimento do RoBERTa
A principal motivação por trás do desenvolvimento do RoBERTa foi abordar os desafios observados no processo de pré-treinamento do BERT. No entanto, o RoBERTa mantém a mesma arquitetura central do Bert Large, que consiste em 24 camadas, 1024 unidades ocultas e 16 cabeças de atenção, totalizando 355 milhões de parâmetros.
Os desafios que o RoBERTa buscou abordar foram:
Padrão de mascaramento estático: O mascaramento estático do BERT levou a cenários de treinamento limitados, causando overfitting. Overfitting ocorre quando um modelo apresenta desempenho muito bom nos dados de treinamento, mas apresenta desempenho ruim com dados de teste (novos dados). O RoBERTa introduziu o mascaramento dinâmico, gerando novas máscaras para cada época e melhorando sua capacidade de lidar com novos dados.
Dados de treinamento insuficientes: O treinamento do BERT foi baseado em um conjunto de dados de aproximadamente 16 GB de texto, o que é insuficiente para capturar toda a diversidade da linguagem. O RoBERTa ampliou os dados de treinamento, usando mais de 160 GB de texto de várias fontes.
Duração curta do treinamento: O modelo BERT original foi treinado por uma duração relativamente curta, mas o RoBERTa estendeu significativamente a duração do treinamento, executando mais épocas e iterações.
Tamanhos de lote pequenos e taxas de aprendizado conservadoras: O pré-treinamento do BERT usou tamanhos de lote relativamente pequenos e taxas de aprendizado conservadoras, o que era uma abordagem segura, mas limitante. Por outro lado, o RoBERTa experimentou tamanhos de lote maiores e taxas de aprendizado mais agressivas, o que levou a um melhor desempenho do modelo.
O que é RoBERTa e como ele funciona?
RoBERTa (A Robustly Optimized BERT Pretraining Approach) é uma versão aprimorada do BERT projetada para abordar suas limitações e melhorar o desempenho. Ele introduziu modificações no processo de treinamento do BERT que melhoram seu desempenho em tarefas de processamento de linguagem natural.
Essas modificações incluem:
Mascaramento dinâmico
Remoção do NSP
Dados de Treinamento Maiores e Duração Estendida
Aumento dos tamanhos de lote
Codificação de texto em bytes
Mascaramento dinâmico
A partir da arquitetura do BERT, lembramos que, durante o pré-treinamento, o BERT realizava Masked Language Modeling (MLM) tentando prever uma certa porcentagem de tokens mascarados. Esses tokens mascarados escolhidos eram os mesmos (estáticos) em cada iteração.
RoBERTa abordou esse problema implementando uma abordagem ligeiramente melhor chamada mascaramento dinâmico. Essa abordagem altera o esquema de mascaramento toda vez que uma sequência é passada para o BERT durante o treinamento. Essa mudança tornou os dados de treinamento mais variados, permitindo que o modelo aprendesse uma gama mais ampla de padrões de linguagem. Como resultado, o RoBERTa desenvolveu uma compreensão mais profunda do contexto, o que melhorou o desempenho em tarefas downstream.
Mascaramento estático vs. mascaramento dinâmico
Figura 3: Mascaramento estático vs. mascaramento dinâmico
Os pesquisadores que desenvolveram o RoBERT também reimplementaram a abordagem de mascaramento estático duplicando os dados de treinamento 10 vezes. Essa duplicação permitiu que cada sequência fosse mascarada de dez maneiras diferentes ao longo das 40 épocas de treinamento. Assim, cada sequência de treinamento foi vista com a mesma máscara quatro vezes durante o treinamento. O desempenho foi semelhante ao comparar a reimplementação do mascaramento estático com o modelo BERT original. No entanto, o mascaramento dinâmico apresenta desempenho ligeiramente melhor do que o mascaramento estático.
Comparação entre mascaramento estático e dinâmico
Figura 4: Comparação entre mascaramento estático e dinâmico
Remoção da previsão da próxima sentença (NSP)
Outra modificação importante no RoBERTa foi a remoção da tarefa NSP. Na NSP, o modelo recebia pares de sentenças e precisava prever se a segunda sentença seguia a primeira no texto original. No entanto, o desenvolvimento do RoBERTa constatou que a tarefa NSP contribuía minimamente para o desempenho do modelo em tarefas downstream.
O RoBERTa usa uma abordagem FULL-SENTENCES (empacotamento de sequências de vários documentos). Cada entrada do modelo é empacotada com sentenças completas amostradas de forma contígua de um ou mais documentos até o comprimento máximo de sequência de 512 tokens. Isso permite que o modelo aprenda dependências de longo alcance de forma mais eficaz.
BERT com e sem NSP
Figura 5: BERT com e sem NSP
Além disso, os pesquisadores analisaram quatro maneiras diferentes de formatar dados de entrada para um modelo de linguagem. Eles compararam dois formatos principais: o SEGMENT-PAIR original e o SENTENCE-PAIR. Ambos os formatos usam NSP, mas o formato SENTENCE-PAIR usa sentenças individuais em vez de pares. Os pesquisadores descobriram que usar sentenças individuais piorava o desempenho do modelo nas tarefas porque ele tinha dificuldade para entender conexões entre palavras muito distantes no texto.
Em seguida, eles testaram o modelo treinando-o sem o método NSP e usando blocos de texto de um documento chamado DOC-SENTENCES. Na maioria dos casos, descobriram que ele se saía melhor do que o BERT original, e não usar a perda NSP não prejudicava o desempenho do modelo.
O método de texto de um único documento (DOC-SENTENCES) foi ligeiramente melhor do que o de múltiplos documentos (FULL-SENTENCES). No entanto, como DOC-SENTENCES levou a tamanhos de lote diferentes durante o treinamento, eles decidiram usar FULL-SENTENCES no restante de seus experimentos. Essa escolha facilitou a comparação de seus resultados com os de outros estudos relacionados.
Resultados para modelos base pré-treinados em BOOK CORPUS e WIKIPEDIA
Figura 6: Resultados para modelos base pré-treinados em BOOK CORPUS e WIKIPEDIA
Dados de treinamento maiores e duração estendida
Talvez a otimização mais direta, mas não menos importante, seja simplesmente treinar com mais dados por mais tempo. O BERT foi treinado em um conjunto de dados de aproximadamente 16 GB de texto, e o RoBERTa usou mais de 160 GB de texto.
Conjuntos de dados do RoBERTa:
BOOK-CORPUS e WIKIPEDIA: Igual ao BERT.
CC-NEWS: RoBERTa introduz um novo conjunto de dados chamado CC-NEWS, um conjunto de dados de notícias em larga escala que apresenta linguagem contemporânea e uma ampla variedade de tópicos, estilos e perspectivas.
Conjuntos de dados adicionais: RoBERTa combina os conjuntos de dados acima com três outros conjuntos de dados privados descritos no artigo, melhorando o desempenho em tarefas downstream.
Usando dados de treinamento maiores, estendendo a duração do treinamento e executando por mais épocas e iterações, RoBERTa mostra uma grande melhoria de 4-6% em tarefas downstream em comparação com os resultados do BERT originalmente relatados (Devlin et al. em 2018).
Resultados do RoBERTa sobre o BERT
Figura 7: Resultados do RoBERTa sobre o BERT
Aumentando os tamanhos dos lotes
Trabalhos anteriores em tradução automática neural mostraram que treinar com mini-lotes muito grandes pode melhorar a perplexidade para modelagem de linguagem mascarada. Essa abordagem melhora o desempenho na tarefa final quando a taxa de aprendizado é aumentada adequadamente (Ott et al., 2018). Perplexidade é uma métrica usada para medir o desempenho de modelos de linguagem. Ela quantifica a incerteza (distribuição de probabilidade) que um modelo tem ao prever a próxima palavra em uma sequência. Por exemplo, quanto menor a perplexidade, mais precisas são as previsões.
Com base nesse conceito, RoBERTa usa mini-lotes muito maiores durante o treinamento. Enquanto o BERT usou um tamanho de lote de 256 sequências por um milhão de etapas, RoBERTa aumentou isso para 8k sequências por 31k etapas com um valor de taxa de aprendizado de 1e-3. No entanto, o desempenho ideal foi observado com 2k sequências por 125k etapas.
Comparação de Perplexidade e Desempenho na Tarefa Final do BERT vs. RoBERTa
Figura 8: Comparação de Perplexidade e Desempenho na Tarefa Final do BERT vs. RoBERTa
Codificação de texto em bytes
RoBERTa também introduziu um método alternativo para lidar com palavras fora do vocabulário (OOV) empregando Byte Pair Encoding (BPE) em nível de byte. O BERT usou um vocabulário de Byte-Pair Encoding (BPE) em nível de caractere de 30K unidades. RoBERTa expande isso para um vocabulário BPE em nível de byte de 50K unidades de subpalavras sem pré-processamento ou tokenização de entrada adicional. Comparado ao BERT, esse método permitiu que RoBERTa codificasse quase qualquer palavra ou subpalavra sem usar o token desconhecido.
Codificação de texto em bytes
Figura 9: Codificação de texto em bytes
Resultados do Experimento
Após modificar o BERT(Devlin et al. 2019), RoBERTa foi testado em benchmarks de NLP. Discutiremos seu desempenho em três benchmarks: GLUE, SQuAD, e RACE.
GLUE (General Language Understanding Evaluation): Uma coleção de 9 conjuntos de dados para tarefas de NLU (compreensão de linguagem natural).
SQuAD (Stanford Question Answering Dataset): Um conjunto de dados projetado para treinar e avaliar sistemas de perguntas e respostas. Ele consiste em perguntas reais feitas por humanos sobre um conjunto de artigos da Wikipedia, em que a resposta a cada pergunta é um trecho específico de texto dentro do artigo correspondente.
RACE (Reading Comprehension from Examinations): Um conjunto de dados de compreensão de leitura em larga escala foi coletado de exames em inglês.
Resultados de teste no conjunto de dados GLUE
RoBERTa foi testado usando duas configurações de fine-tuning. Na primeira configuração (tarefa única), RoBERTa foi ajustado separadamente por 10 épocas para cada tarefa GLUE , usando apenas os dados de treinamento da tarefa correspondente. Ele alcançou resultados de estado da arte em todas as nove tarefas GLUE, superando tanto BERT quanto XLNet. Na segunda configuração (ensembles), RoBERTa obteve 88.5 no ranking GLUE, igualando o estado da arte anterior estabelecido pelo XLNet. RoBERTa estabeleceu novos resultados de estado da arte em 4 de 9 tarefas GLUE: MNLI, QNLI, RTE e STS-B.
Resultados no GLUE
Figura 10: Resultados no GLUE
SQuAD
RoBERTa foi ajustado usando os dados de treinamento do SQuAD. No SQuAD v1.1, RoBERTa iguala o estado da arte estabelecido pelo XLNet. No SQuAD v2.0, RoBERTa alcançou uma pontuação F1 de 89.4, estabelecendo um novo estado da arte para modelos únicos sem aumento de dados. Isso é particularmente impressionante, considerando que RoBERTa não usa nenhuma técnica específica do SQuAD e é ajustado apenas com dados do SQuAD.
Resultados no SQuAD
Figura 11: Resultados no SQuAD
Resultados dos testes no conjunto de dados RACE
RACE é um benchmark desafiador de compreensão de leitura que exige que os modelos respondam a perguntas de múltipla escolha com base em passagens de exames de inglês. Este benchmark é particularmente difícil porque exige que os modelos compreendam passagens complexas e infiram as respostas corretas com base no contexto. RoBERTa alcançou uma precisão de 83.2% no benchmark RACE e estabeleceu novos padrões de estado da arte.
Resultados no conjunto de teste RACE
Figura 12: Resultados no conjunto de teste RACE
Fine-Tuning do RoBERTa para Análise de Sentimentos
Além de seu desempenho em benchmarks padrão, RoBERTa também se mostrou altamente eficaz para o fine-tuning de tarefas específicas, como análise de sentimentos. Fine-tuning é pegar um modelo pré-treinado e adaptá-lo a uma tarefa específica, treinando-o em um conjunto de dados menor e específico da tarefa. O código-fonte usado neste artigo é da Hugging Face.
Importando e preparando o conjunto de dados
Usaremos o conjunto de dados disponível na Kaggle Competition e nos referiremos apenas ao primeiro arquivo csv do despejo de dados: train.tsv.
Importando bibliotecas Python:
!pip install transformers==3.0.2
Importe as bibliotecas e módulos necessários para executar nosso script nesta etapa.
# Importing the libraries needed
import pandas as pd
import numpy as np
import torch
import transformers
import json
from tqdm import tqdm
from torch.utils.data import Dataset, DataLoader
from transformers import RobertaModel, RobertaTokenizer
import logging
logging.basicConfig(level=logging.ERROR)
# Setting up the device for GPU usage
from torch import cuda
device = 'cuda' if cuda.is_available() else 'cpu'
Preparando o conjunto de dados
Primeiro, carregue o conjunto de dados e leia-o usando o pacote Pandas.
train = pd.read_csv('train.tsv', delimiter='\t')
new_df = train[['Phrase', 'Sentiment']]
Vamos definir algumas variáveis:
MAX_LEN: O comprimento máximo do texto de entrada (256).
TRAIN_BATCH_SIZE and VALID_BATCH_SIZE: Os tamanhos de lote para treinamento e validação (8 e 4, respectivamente).
LEARNING_RATE: A taxa de aprendizado para o modelo (1e-05).
Tokenizer: Uma instância de RobertaTokenizer é usada para pré-processar os dados de texto.
A classe SentimentData implementa uma classe de dataset personalizada, recebendo um data frame, tokenizer e comprimento máximo como entradas. Ela pré-processa os dados de texto, retornando um dicionário contendo IDs de entrada, máscaras de atenção, IDs de tipo de token e rótulos de sentimento alvo.
A classe DataLoader cria carregadores de dados para os conjuntos de treinamento e teste, iterando sobre os dados em lotes durante o treinamento e a validação.
# Defining some key variables that will be used later on in the training
MAX_LEN = 256
TRAIN_BATCH_SIZE = 8
VALID_BATCH_SIZE = 4
LEARNING_RATE = 1e-05
tokenizer = RobertaTokenizer.from_pretrained('roberta-base', truncation=True, do_lower_case=True)
class SentimentData(Dataset):
def __init__(self, dataframe, tokenizer, max_len):
self.tokenizer = tokenizer
self.data = dataframe
self.text = dataframe.Phrase
self.targets = self.data.Sentiment
self.max_len = max_len
def __len__(self):
return len(self.text)
def __getitem__(self, index):
text = str(self.text[index])
text = " ".join(text.split())
inputs = self.tokenizer.encode_plus(
text,
None,
add_special_tokens=True,
max_length=self.max_len,
pad_to_max_length=True,
return_token_type_ids=True
)
ids = inputs['input_ids']
mask = inputs['attention_mask']
token_type_ids = inputs["token_type_ids"]
return {
'ids': torch.tensor(ids, dtype=torch.long),
'mask': torch.tensor(mask, dtype=torch.long),
'token_type_ids': torch.tensor(token_type_ids, dtype=torch.long),
'targets': torch.tensor(self.targets[index], dtype=torch.float)
}
train_size = 0.8
train_data=new_df.sample(frac=train_size,random_state=200)
test_data=new_df.drop(train_data.index).reset_index(drop=True)
train_data = train_data.reset_index(drop=True)
print("FULL Dataset: {}".format(new_df.shape))
print("TRAIN Dataset: {}".format(train_data.shape))
print("TEST Dataset: {}".format(test_data.shape))
training_set = SentimentData(train_data, tokenizer, MAX_LEN)
testing_set = SentimentData(test_data, tokenizer, MAX_LEN)
train_params = {'batch_size': TRAIN_BATCH_SIZE,
'shuffle': True,
'num_workers': 0
}
test_params = {'batch_size': VALID_BATCH_SIZE,
'shuffle': True,
'num_workers': 0
}
training_loader = DataLoader(training_set, **train_params)
testing_loader = DataLoader(testing_set, **test_params)
Criando a rede neural para ajuste fino
Criaremos uma rede neural com RobertaClass.
Esta rede terá o modelo de linguagem Roberta, seguido por um dropout e, finalmente, uma camada linear para obter as saídas finais.
Os dados serão fornecidos ao modelo de linguagem Roberta conforme definido no dataset.
A saída da camada final será comparada à categoria de sentimento para determinar a precisão da previsão do modelo.
Iniciaremos uma instância da rede chamada Model. Esta instância será usada para treinamento.
class RobertaClass(torch.nn.Module):
def __init__(self):
super(RobertaClass, self).__init__()
self.l1 = RobertaModel.from_pretrained("roberta-base")
self.pre_classifier = torch.nn.Linear(768, 768)
self.dropout = torch.nn.Dropout(0.3)
self.classifier = torch.nn.Linear(768, 5)
def forward(self, input_ids, attention_mask, token_type_ids):
output_1 = self.l1(input_ids=input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids)
hidden_state = output_1[0]
pooler = hidden_state[:, 0]
pooler = self.pre_classifier(pooler)
pooler = torch.nn.ReLU()(pooler)
pooler = self.dropout(pooler)
output = self.classifier(pooler)
return output
model = RobertaClass()
model.to(device)
Ajuste fino do modelo
Depois de todo o esforço de carregar e preparar o conjunto de dados e criar o modelo. Esta é provavelmente a etapa mais fácil do processo.
Aqui, definimos uma função de treinamento que treina o modelo em um número especificado de épocas no conjunto de dados de treinamento acima. Uma época define com que frequência os dados completos serão passados pela rede.
# Creating the loss function and optimizer
loss_function = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(params = model.parameters(), lr=LEARNING_RATE)
def calcuate_accuracy(preds, targets):
n_correct = (preds==targets).sum().item()
return n_correct
# Defining the training function on the 80% of the dataset for tuning the distilbert model
def train(epoch):
tr_loss = 0
n_correct = 0
nb_tr_steps = 0
nb_tr_examples = 0
model.train()
for _,data in tqdm(enumerate(training_loader, 0)):
ids = data['ids'].to(device, dtype = torch.long)
mask = data['mask'].to(device, dtype = torch.long)
token_type_ids = data['token_type_ids'].to(device, dtype = torch.long)
targets = data['targets'].to(device, dtype = torch.long)
outputs = model(ids, mask, token_type_ids)
loss = loss_function(outputs, targets)
tr_loss += loss.item()
big_val, big_idx = torch.max(outputs.data, dim=1)
n_correct += calcuate_accuracy(big_idx, targets)
nb_tr_steps += 1
nb_tr_examples+=targets.size(0)
if _%5000==0:
loss_step = tr_loss/nb_tr_steps
accu_step = (n_correct*100)/nb_tr_examples
print(f"Training Loss per 5000 steps: {loss_step}")
print(f"Training Accuracy per 5000 steps: {accu_step}")
optimizer.zero_grad()
loss.backward()
# # When using GPU
optimizer.step()
print(f'The Total Accuracy for Epoch {epoch}: {(n_correct*100)/nb_tr_examples}')
epoch_loss = tr_loss/nb_tr_steps
epoch_accu = (n_correct*100)/nb_tr_examples
print(f"Training Loss Epoch: {epoch_loss}")
print(f"Training Accuracy Epoch: {epoch_accu}")
return
EPOCHS = 1
for epoch in range(EPOCHS):
train(epoch)
Saída:
Figura 13- Detalhes do treinamento do modelo
Validando o desempenho do modelo
Durante a etapa de validação, passamos os dados não vistos (o conjunto de dados de teste) para o modelo. Esta etapa determina quão bem o modelo se desempenha nos dados não vistos, que são 20% de train.tsv, separados durante a etapa de criação do conjunto de dados.
A etapa de validação verifica a capacidade de generalização do modelo para dados novos e não vistos. Os pesos do modelo não foram atualizados. Apenas a saída final é comparada ao valor real, que então é usado para calcular a precisão do modelo.
A função valid implementa a etapa de validação, recebendo o modelo e o carregador de teste como entradas. Ela define o modelo para o modo de avaliação, inicializa variáveis para rastrear previsões corretas e incorretas e itera sobre o carregador de teste. Para cada lote, ela calcula a perda e a precisão, imprimindo a perda de validação e a precisão a cada 5000 etapas e no fim da época. Por fim, ela retorna a precisão da época.
def valid(model, testing_loader):
model.eval()
n_correct = 0; n_wrong = 0; total = 0; tr_loss=0; nb_tr_steps=0; nb_tr_examples=0
with torch.no_grad():
for _, data in tqdm(enumerate(testing_loader, 0)):
ids = data['ids'].to(device, dtype = torch.long)
mask = data['mask'].to(device, dtype = torch.long)
token_type_ids = data['token_type_ids'].to(device, dtype=torch.long)
targets = data['targets'].to(device, dtype = torch.long)
outputs = model(ids, mask, token_type_ids).squeeze()
loss = loss_function(outputs, targets)
tr_loss += loss.item()
big_val, big_idx = torch.max(outputs.data, dim=1)
n_correct += calcuate_accuracy(big_idx, targets)
nb_tr_steps += 1
nb_tr_examples+=targets.size(0)
if _%5000==0:
loss_step = tr_loss/nb_tr_steps
accu_step = (n_correct*100)/nb_tr_examples
print(f"Validation Loss per 100 steps: {loss_step}")
print(f"Validation Accuracy per 100 steps: {accu_step}")
epoch_loss = tr_loss/nb_tr_steps
epoch_accu = (n_correct*100)/nb_tr_examples
print(f"Validation Loss Epoch: {epoch_loss}")
print(f"Validation Accuracy Epoch: {epoch_accu}")
return epoch_accu
acc = valid(model, testing_loader)
print("Accuracy on test data = %0.2f%%" % acc)
Saída:
Figura 14- Detalhes da validação do modelo
Como você pode ver, o modelo prevê a categoria correta de uma determinada amostra com uma precisão de 69,47%, que pode ser ainda mais melhorada com mais treinamento.
Oportunidades de Pesquisa Futuras
O sucesso do RoBERTa abriu novas portas para a pesquisa em NLP e otimização de modelos. Aqui estão algumas oportunidades de pesquisa potenciais:
Escalabilidade de conjuntos de dados
Conjuntos de dados maiores e tempos de treinamento mais longos melhoraram o RoBERTa. Pesquisas futuras poderiam investigar a escalabilidade dinâmica de conjuntos de dados, em que os modelos são treinados em conjuntos de dados progressivamente maiores ao longo do tempo. Essa abordagem poderia nos ajudar a entender como o modelo aprende com novos dados e se ele pode continuar melhorando à medida que seus dados aumentam.
Ajuste fino multitarefa
O desempenho do RoBERTa poderia ser ainda mais melhorado explorando procedimentos avançados de ajuste fino multitarefa. No momento, ele é bom em muitas coisas sem ser treinado em várias tarefas ao mesmo tempo. No entanto, pesquisadores podem investigar como a integração de várias tarefas durante a fase de ajuste fino poderia melhorar o desempenho em diferentes benchmarks.
Exploração de objetivos de pré-treinamento
A remoção do objetivo NSP e o uso de uma abordagem de mascaramento dinâmico em vez de mascaramento estático no RoBERTa levantam questões sobre se existem maneiras ainda melhores de ensinar modelos de linguagem. Pesquisas futuras podem explorar diferentes métodos de pré-treinamento que afetam o quão bem o RoBERTa entende e conclui tarefas.
Conclusão
O artigo do RoBERTa faz várias contribuições importantes para o campo de NLP. Os autores descobrem que alterar dinamicamente o padrão de mascaramento nos dados de treinamento, treinar em sequências mais longas e remover a tarefa NSP pode melhorar o desempenho em tarefas downstream.
Além disso, usar um tamanho de lote maior e um conjunto de dados de treinamento maior também contribui para essa melhoria. O RoBERTa alcança resultados de ponta em GLUE, RACE e SQuAD sem ajuste fino multitarefa para GLUE ou dados adicionais para SQuAD.
Além disso, o debate entre RoBERTa e BERT não é apenas sobre qual modelo é melhor. Trata-se de entender as compensações entre recursos computacionais, desempenho do modelo e as implicações éticas de implantar esses modelos. Os avanços do RoBERTa em relação ao BERT mostram que o campo de NLP está longe de ser estático e abrem a porta para um caminho rumo a capacidades de processamento de linguagem mais avançadas e complexas.
Recursos Adicionais
Continue lendo

How Zilliz Saw the Future of Vector Databases—and Built for Production
An inside look at how Zilliz built vector databases for real-world use, focusing on scalability, stability, and running them reliably at scale.

Zilliz Cloud Update: Smarter Autoscaling for Cost Savings, Stronger Compliance with Audit Logs, and More
What's new in Zilliz Cloud? Smarter autoscaling with scale-down, audit logs GA, enhanced SSO, and Milvus 2.6 in Private Preview.

Zilliz Cloud Launches in AWS Australia, Expanding Global Reach to Australia and Neighboring Markets
We're thrilled to announce that Zilliz Cloud is now available in the AWS Sydney, Australia region (ap-southeast-2).



