RoBERTa: Un método optimizado para el preentrenamiento de sistemas de PLN autosupervisados
Los modelos de lenguaje preentrenados han logrado un éxito notable en el procesamiento del lenguaje natural (NLP), lo que ha llevado a un cambio de paradigma desde el aprendizaje supervisado hacia el preentrenamiento seguido del ajuste fino. El objetivo del modelado del lenguaje es predecir el siguiente token en una secuencia, dado un historial de textos no anotados, que son grandes cantidades de datos de texto sin procesar que no han sido etiquetados con información específica. BERT (Bidirectional Encoder Representations from Transformers) establece nuevos estándares para este concepto al permitir la comprensión bidireccional del lenguaje, ya que analiza toda la oración, no solo una palabra a la vez. Considera las palabras anteriores y posteriores para comprender mejor su significado.
Sin embargo, el principal problema encontrado con BERT fue su entrenamiento insuficiente, lo que limitó su rendimiento en tareas de NLP. Esta limitación llevó a los investigadores a explorar metodologías de entrenamiento mejoradas en modelos posteriores, como RoBERTa.
RoBERTa (A Robustly Optimized BERT Pretraining Approach) es una versión mejorada de BERT diseñada para abordar sus limitaciones. RoBERTa introdujo varias mejoras clave que potencian su rendimiento en diversos problemas de NLP.
Este artículo analizará las metodologías y tecnologías utilizadas en el desarrollo de RoBERTa, incluido su enfoque de entrenamiento, los resultados que ha logrado y las posibles oportunidades de investigación futura que abre.
Una breve introducción a BERT (Bidirectional Encoder Representations from Transformers)
Para comprender RoBERTa, es esencial comprender su predecesor, BERT, y los desafíos que enfrentó. BERT introdujo el concepto de transformers bidireccionales, lo que permitió a los modelos de aprendizaje profundo comprender el contexto de una manera que antes era inalcanzable.
Pero, para comprender realmente cómo funciona BERT, necesitamos desglosarlo. Así que echemos un vistazo más de cerca a su arquitectura y a cómo fue entrenado.
Arquitectura y proceso de preentrenamiento de BERT
La arquitectura de BERT se basa en transformers, introducidos por Devlin et al. en 2018. Utiliza un codificador bidireccional multicapa (de izquierda a derecha y de derecha a izquierda) para ponderar la importancia de diferentes palabras en una oración.
Arquitectura de BERT
Figura 1: Arquitectura de BERT
Una palabra comienza con su representación de embedding de la capa de embedding; un embedding es un vector denso (representación numérica) de una palabra o token en un espacio de alta dimensión. La capa de embedding es la primera capa de una red neuronal que convierte las palabras de entrada en estos vectores densos. Cada capa realiza cálculos de atención multicabezal sobre la representación de palabras de la capa anterior para generar una nueva representación intermedia. Todas estas representaciones intermedias tienen el mismo tamaño. En la figura anterior, E1 es la representación de embedding, T1 es la salida final y Trm es la representación intermedia del token.
El proceso de preentrenamiento de BERT incluye dos tareas principales:
Modelado de lenguaje enmascarado (MLM)
Predicción de la siguiente oración (NSP)
El modelado del lenguaje predice la siguiente palabra dada una secuencia de palabras. Sin embargo, en la tarea de MLM, en lugar de predecir cada token siguiente, un porcentaje de los tokens de entrada se enmascara aleatoriamente, y solo se predicen esos tokens enmascarados. La tarea de NSP, por otro lado, es una tarea de clasificación binaria que predice si dos oraciones dadas se siguen entre sí en el texto original. Este enfoque ayuda al modelo a comprender las relaciones entre oraciones.
Next Sentence Prediction
Figura 2: Next Sentence Prediction
El proceso de preentrenamiento de BERT tenía limitaciones que le impedían alcanzar todo su potencial. Uno de los principales problemas era el uso de un patrón de enmascaramiento estático en la tarea de MLM. En BERT, una vez que una palabra se enmascaraba durante el entrenamiento, las mismas palabras se enmascaraban en todas las iteraciones. Este enfoque estático limitaba al modelo a diversos escenarios de enmascaramiento, reduciendo su capacidad de generalización. Además, el tamaño y la duración de los datos de entrenamiento también eran limitados.
Estas limitaciones provocaron inconsistencias en el rendimiento de BERT en tareas específicas de dominio, como el análisis de textos legales o médicos, y en escenarios complejos de comprensión del lenguaje, como el análisis de sentimientos o el razonamiento de varios pasos. Abordar estas deficiencias requiere más investigación y desarrollo.
La aparición de RoBERTa
La motivación principal detrás del desarrollo de RoBERTa fue abordar los desafíos observados en el proceso de preentrenamiento de BERT. Sin embargo, RoBERTa mantiene la misma arquitectura central que Bert Large, que consta de 24 capas, 1024 unidades ocultas y 16 cabezas de atención, con un total de 355 millones de parámetros.
Los desafíos que RoBERTa pretendía abordar fueron:
Patrón de enmascaramiento estático: El enmascaramiento estático de BERT condujo a escenarios de entrenamiento limitados, causando sobreajuste. El sobreajuste ocurre cuando un modelo funciona muy bien con los datos de entrenamiento pero funciona mal con los datos de prueba (datos nuevos). RoBERTa introdujo el enmascaramiento dinámico, generando nuevas máscaras para cada época y mejorando su capacidad para manejar datos nuevos.
Datos de entrenamiento insuficientes: El entrenamiento de BERT se basó en un conjunto de datos de aproximadamente 16 GB de texto, lo cual es insuficiente para capturar toda la diversidad del lenguaje. RoBERTa amplió los datos de entrenamiento, utilizando más de 160 GB de texto de diversas fuentes.
Duración de entrenamiento corta: El modelo BERT original fue entrenado durante una duración relativamente corta, pero RoBERTa extendió significativamente la duración del entrenamiento, ejecutándose durante más épocas e iteraciones.
Tamaños de lote pequeños y tasas de aprendizaje conservadoras: El preentrenamiento de BERT utilizó tamaños de lote relativamente pequeños y tasas de aprendizaje conservadoras, lo cual era un enfoque seguro pero limitante. Por otro lado, RoBERTa experimentó con tamaños de lote más grandes y tasas de aprendizaje más agresivas, lo que llevó a un mejor rendimiento del modelo.
¿Qué es RoBERTa y cómo funciona?
RoBERTa (A Robustly Optimized BERT Pretraining Approach) es una versión mejorada de BERT diseñada para abordar sus limitaciones y mejorar el rendimiento. Introdujo modificaciones en el proceso de entrenamiento de BERT que mejoran su rendimiento en tareas de procesamiento del lenguaje natural.
Estas modificaciones incluyen:
Enmascaramiento dinámico
Eliminación de NSP
Datos de entrenamiento más grandes y duración extendida
Aumento de los tamaños de lote
Codificación de texto en bytes
Enmascaramiento dinámico
A partir de la arquitectura de BERT, recordamos que durante el preentrenamiento, BERT realizaba Masked Language Modeling (MLM) intentando predecir un cierto porcentaje de tokens enmascarados. Estos tokens enmascarados elegidos eran los mismos (estáticos) en cada iteración.
RoBERTa abordó este problema implementando un enfoque ligeramente mejor llamado enmascaramiento dinámico. Este enfoque cambia el esquema de enmascaramiento cada vez que se pasa una secuencia a BERT durante el entrenamiento. Este cambio hizo que los datos de entrenamiento fueran más variados, lo que permitió al modelo aprender una gama más amplia de patrones lingüísticos. Como resultado, RoBERTa desarrolló una comprensión más profunda del contexto, lo que mejoró el rendimiento en tareas posteriores.
Enmascaramiento estático vs. enmascaramiento dinámico
Figura 3: Enmascaramiento estático vs. enmascaramiento dinámico
Los investigadores que desarrollaron RoBERT también reimplementaron el enfoque de enmascaramiento estático duplicando los datos de entrenamiento 10 veces. Esta duplicación permitió que cada secuencia se enmascarara de diez maneras diferentes a lo largo de las 40 épocas de entrenamiento. Así, cada secuencia de entrenamiento se vio con la misma máscara cuatro veces durante el entrenamiento. El rendimiento fue similar al comparar la reimplementación del enmascaramiento estático con el modelo BERT original. Sin embargo, el enmascaramiento dinámico muestra un rendimiento ligeramente mejor que el enmascaramiento estático.
Comparación entre enmascaramiento estático y dinámico
Figura 4: Comparación entre enmascaramiento estático y dinámico
Eliminación de la predicción de la siguiente oración (NSP)
Otra modificación clave en RoBERTa fue la eliminación de la tarea NSP. En NSP, al modelo se le daban pares de oraciones y tenía que predecir si la segunda oración seguía a la primera en el texto original. Sin embargo, el desarrollo de RoBERTa descubrió que la tarea NSP contribuía mínimamente al rendimiento del modelo en tareas posteriores.
RoBERTa utiliza un enfoque FULL-SENTENCES (empaquetando secuencias de múltiples documentos). Cada entrada al modelo se empaqueta con oraciones completas muestreadas de forma contigua de uno o más documentos hasta la longitud máxima de secuencia de 512 tokens. Esto permite al modelo aprender dependencias de largo alcance de manera más efectiva.
BERT con y sin NSP
Figura 5: BERT con y sin NSP
Además, los investigadores analizaron cuatro formas diferentes de formatear los datos de entrada para un modelo de lenguaje. Compararon dos formatos principales: el SEGMENT-PAIR original y SENTENCE-PAIR. Ambos formatos usan NSP, pero el formato SENTENCE-PAIR usa oraciones individuales en lugar de pares. Los investigadores descubrieron que usar oraciones individuales empeoraba el rendimiento del modelo en las tareas porque tenía dificultades para entender conexiones entre palabras muy separadas en el texto.
Luego, probaron el modelo entrenándolo sin el método NSP y usando bloques de texto de un documento llamado DOC-SENTENCES. En la mayoría de los casos, descubrieron que funcionaba mejor que el BERT original, y no usar la pérdida NSP no perjudicó el rendimiento del modelo.
El método de texto de un solo documento (DOC-SENTENCES) fue ligeramente mejor que el de múltiples documentos (FULL-SENTENCES). Sin embargo, dado que DOC-SENTENCES dio lugar a diferentes tamaños de lote durante el entrenamiento, decidieron usar FULL-SENTENCES para el resto de sus experimentos. Esta elección facilitó la comparación de sus resultados con los de otros estudios relacionados.
Resultados para modelos base preentrenados sobre BOOK CORPUS y WIKIPEDIA
Figura 6: Resultados para modelos base preentrenados sobre BOOK CORPUS y WIKIPEDIA
Datos de entrenamiento más grandes y duración extendida
Quizás la optimización más sencilla, pero no por ello menos importante, es simplemente entrenar con más datos durante más tiempo. BERT se entrenó con un conjunto de datos de aproximadamente 16 GB de texto, y RoBERTa usó más de 160 GB de texto.
Conjuntos de datos de RoBERTa:
BOOK-CORPUS y WIKIPEDIA: Igual que BERT.
CC-NEWS: RoBERTa introduce un nuevo conjunto de datos llamado CC-NEWS, un conjunto de datos de noticias a gran escala que presenta lenguaje contemporáneo y una amplia gama de temas, estilos y perspectivas.
Conjuntos de datos adicionales: RoBERTa combina los conjuntos de datos anteriores con otros tres conjuntos de datos privados descritos en el artículo, mejorando el rendimiento en tareas posteriores.
Al utilizar datos de entrenamiento más grandes, ampliar la duración del entrenamiento y ejecutar más épocas e iteraciones, RoBERTa muestra una gran mejora del 4-6% en tareas posteriores en comparación con los resultados de BERT reportados originalmente (Devlin et al. in 2018).
Resultados de RoBERTa sobre BERT
Figura 7: Resultados de RoBERTa sobre BERT
Aumento de los tamaños de lote
Trabajos anteriores en traducción automática neuronal han demostrado que entrenar con mini-lotes muy grandes puede mejorar la perplejidad para el modelado de lenguaje enmascarado. Este enfoque mejora el rendimiento en la tarea final cuando la tasa de aprendizaje se aumenta adecuadamente (Ott et al., 2018). La perplejidad es una métrica utilizada para medir el rendimiento de los modelos de lenguaje. Cuantifica la incertidumbre (distribución de probabilidad) que tiene un modelo al predecir la siguiente palabra en una secuencia. Por ejemplo, cuanto menor sea la perplejidad, más precisas serán las predicciones.
Basándose en este concepto, RoBERTa utiliza mini-lotes mucho más grandes durante el entrenamiento. Mientras que BERT usó un tamaño de lote de 256 secuencias durante un millón de pasos, RoBERTa lo aumentó a 8k secuencias durante 31k pasos con un valor de tasa de aprendizaje de 1e-3. Sin embargo, el rendimiento óptimo se observó con 2k secuencias durante 125k pasos.
Comparación de la perplejidad y el rendimiento en la tarea final de BERT frente a RoBERTa
Figura 8: Comparación de la perplejidad y el rendimiento en la tarea final de BERT frente a RoBERTa
Codificación de texto en bytes
RoBERTa también introdujo un método alternativo para manejar palabras fuera de vocabulario (OOV) empleando Byte Pair Encoding (BPE) a nivel de byte. BERT utilizó un vocabulario de Byte-Pair Encoding (BPE) a nivel de carácter de 30K unidades. RoBERTa amplía esto a un vocabulario BPE a nivel de byte de 50K unidades de subpalabras sin preprocesamiento ni tokenización adicional de la entrada. En comparación con BERT, este método permitió a RoBERTa codificar casi cualquier palabra o subpalabra sin usar el token desconocido.
Codificación de texto en bytes
Figura 9: Codificación de texto en bytes
Resultados del experimento
Después de modificar BERT(Devlin et al. 2019), RoBERTa se probó en benchmarks de NLP. Analizaremos su rendimiento en tres benchmarks: GLUE, SQuAD, y RACE.
GLUE (General Language Understanding Evaluation): Una colección de 9 conjuntos de datos para tareas de NLU (comprensión del lenguaje natural).
SQuAD (Stanford Question Answering Dataset): Un conjunto de datos diseñado para entrenar y evaluar sistemas de preguntas y respuestas. Consiste en preguntas reales planteadas por humanos sobre un conjunto de artículos de Wikipedia, donde la respuesta a cada pregunta es un tramo específico de texto dentro del artículo correspondiente.
RACE (Reading Comprehension from Examinations): Un conjunto de datos de comprensión lectora a gran escala recopilado a partir de exámenes de inglés.
Resultados de las pruebas en el conjunto de datos GLUE
RoBERTa fue probado usando dos configuraciones de ajuste fino. En la primera configuración (tarea única), RoBERTa fue ajustado finamente por separado durante 10 épocas para cada tarea de GLUE , usando solo los datos de entrenamiento de la tarea correspondiente. Logró resultados de vanguardia en las nueve tareas de GLUE, superando tanto a BERT como a XLNet. En la segunda configuración (ensambles), RoBERTa obtuvo 88.5 en la clasificación de GLUE, igualando el estado del arte anterior establecido por XLNet. RoBERTa estableció nuevos resultados de vanguardia en 4 de 9 tareas de GLUE: MNLI, QNLI, RTE y STS-B.
Resultados en GLUE
Figura 10: Resultados en GLUE
SQuAD
RoBERTa fue ajustado finamente usando los datos de entrenamiento de SQuAD. En SQuAD v1.1, RoBERTa iguala el estado del arte establecido por XLNet. En SQuAD v2.0, RoBERTa logró una puntuación F1 de 89.4, estableciendo un nuevo estado del arte para modelos individuales sin aumento de datos. Esto es particularmente impresionante dado que RoBERTa no utiliza ninguna técnica específica de SQuAD y solo se ajusta finamente con datos de SQuAD.
Resultados en SQuAD
Figura 11: Resultados en SQuAD
Resultados de prueba en el conjunto de datos RACE
RACE es un benchmark desafiante de comprensión lectora que requiere que los modelos respondan preguntas de opción múltiple basadas en pasajes de exámenes de inglés. Este benchmark es particularmente difícil porque requiere que los modelos comprendan pasajes complejos e infieran las respuestas correctas según el contexto. RoBERTa logró una precisión de 83.2% en el benchmark RACE y estableció nuevos estándares de vanguardia.
Resultados en el conjunto de prueba RACE
Figura 12: Resultados en el conjunto de prueba RACE
Ajuste fino de RoBERTa para análisis de sentimientos
Más allá de su rendimiento en benchmarks estándar, RoBERTa también ha demostrado ser altamente efectivo para el ajuste fino de tareas específicas, como el análisis de sentimientos. El ajuste fino consiste en tomar un modelo preentrenado y adaptarlo a una tarea específica entrenándolo con un conjunto de datos más pequeño y específico de la tarea. El código fuente utilizado en este artículo proviene de Hugging Face.
Importar y preparar el conjunto de datos
Usaremos el conjunto de datos disponible en la Kaggle Competition y solo haremos referencia al primer archivo csv del volcado de datos: train.tsv.
Importar bibliotecas de Python:
!pip install transformers==3.0.2
Importa las bibliotecas y módulos necesarios para ejecutar nuestro script en este paso.
# 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'
Preparar el conjunto de datos
Primero, carga el conjunto de datos y léelo usando el paquete Pandas.
train = pd.read_csv('train.tsv', delimiter='\t')
new_df = train[['Phrase', 'Sentiment']]
Definamos algunas variables:
MAX_LEN: La longitud máxima del texto de entrada (256).
TRAIN_BATCH_SIZE y VALID_BATCH_SIZE: Los tamaños de lote para entrenamiento y validación (8 y 4, respectivamente).
LEARNING_RATE: La tasa de aprendizaje para el modelo (1e-05).
Tokenizer: Se utiliza una instancia de RobertaTokenizer para preprocesar los datos de texto.
La clase SentimentData implementa una clase de conjunto de datos personalizada, que toma como entradas un marco de datos, un tokenizer y una longitud máxima. Preprocesa los datos de texto y devuelve un diccionario que contiene IDs de entrada, máscaras de atención, IDs de tipo de token y etiquetas de sentimiento objetivo.
La clase DataLoader crea cargadores de datos para los conjuntos de entrenamiento y prueba, iterando sobre los datos en lotes durante el entrenamiento y la validación.
# 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)
Creación de la red neuronal para el ajuste fino
Crearemos una red neuronal con RobertaClass.
Esta red tendrá el modelo de lenguaje Roberta, seguido de un dropout y, finalmente, una capa lineal para obtener las salidas finales.
Los datos se introducirán en el modelo de lenguaje Roberta como se define en el conjunto de datos.
La salida de la capa final se comparará con la categoría de sentimiento para determinar la precisión de la predicción del modelo.
Iniciaremos una instancia de la red llamada Model. Esta instancia se utilizará para el entrenamiento.
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 del modelo
Después de todo el esfuerzo de cargar y preparar el conjunto de datos y crear el modelo. Este es probablemente el paso más fácil del proceso.
Aquí, definimos una función de entrenamiento que entrena el modelo durante un número especificado de épocas en el conjunto de datos de entrenamiento anterior. Una época define con qué frecuencia los datos completos pasarán por la red.
# 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)
Salida:
Figura 13- Detalles del entrenamiento del modelo
Validación del rendimiento del modelo
Durante la etapa de validación, pasamos los datos no vistos (el conjunto de datos de prueba) al modelo. Este paso determina qué tan bien funciona el modelo con los datos no vistos, que son el 20% de train.tsv, que se separó durante la etapa de creación del conjunto de datos.
La etapa de validación comprueba la capacidad de generalización del modelo a datos nuevos y no vistos. Los pesos del modelo no se han actualizado. Solo se compara la salida final con el valor real, que luego se utiliza para calcular la precisión del modelo.
La función valid implementa la etapa de validación, tomando el modelo y el cargador de pruebas como entradas. Establece el modelo en modo de evaluación, inicializa variables para hacer seguimiento de las predicciones correctas e incorrectas, e itera sobre el cargador de pruebas. Para cada lote, calcula la pérdida y la precisión, imprimiendo la pérdida de validación y la precisión cada 5000 pasos y al final de la época. Finalmente, devuelve la precisión de la é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)
Salida:
Figura 14- Detalles de la validación del modelo
Como puedes ver, el modelo predice la categoría correcta de una muestra dada con una precisión del 69,47%, que puede mejorarse aún más entrenando más.
Oportunidades de investigación futuras
El éxito de RoBERTa ha abierto nuevas puertas para la investigación en NLP y la optimización de modelos. Estas son algunas posibles oportunidades de investigación:
Escalado de conjuntos de datos
Conjuntos de datos más grandes y tiempos de entrenamiento más largos mejoraron RoBERTa. Investigaciones futuras podrían estudiar el escalado dinámico de conjuntos de datos, donde los modelos se entrenan con conjuntos de datos progresivamente más grandes a lo largo del tiempo. Este enfoque podría ayudarnos a entender cómo el modelo aprende de nuevos datos y si puede seguir mejorando a medida que sus datos escalan.
Ajuste fino multitarea
El rendimiento de RoBERTa podría mejorarse aún más explorando procedimientos avanzados de ajuste fino multitarea. En este momento, es bueno en muchas cosas sin estar entrenado en múltiples tareas a la vez. Sin embargo, los investigadores pueden estudiar cómo integrar múltiples tareas durante la fase de ajuste fino podría mejorar el rendimiento en diferentes benchmarks.
Exploración de objetivos de preentrenamiento
Eliminar el objetivo NSP y usar un enfoque de enmascaramiento dinámico en lugar de enmascaramiento estático en RoBERTa plantea dudas sobre si existen formas aún mejores de enseñar a los modelos de lenguaje. Investigaciones futuras pueden explorar diferentes métodos de preentrenamiento que afecten qué tan bien RoBERTa entiende y completa tareas.
Conclusión
El artículo de RoBERTa hace varias contribuciones importantes al campo de NLP. Los autores descubren que cambiar dinámicamente el patrón de enmascaramiento en los datos de entrenamiento, entrenar con secuencias más largas y eliminar la tarea NSP puede mejorar el rendimiento en tareas posteriores.
Además, usar un tamaño de lote y un conjunto de datos de entrenamiento más grandes también contribuye a esta mejora. RoBERTa logra resultados de vanguardia en GLUE, RACE y SQuAD sin ajuste fino multitarea para GLUE ni datos adicionales para SQuAD.
Además, el debate entre RoBERTa y BERT no se trata solo de qué modelo es mejor. Se trata de entender las compensaciones entre los recursos computacionales, el rendimiento del modelo y las implicaciones éticas de desplegar estos modelos. Los avances de RoBERTa sobre BERT muestran que el campo de NLP está lejos de ser estático y abren la puerta a un camino hacia capacidades de procesamiento del lenguaje más avanzadas y complejas.
Recursos adicionales
Sigue leyendo

Notion's Vector Search Is Excellent. Their Next Problem Is Harder.
Notion solved vector search scaling in two years. The next bottleneck — offline context engineering, unified data, and the real-time/offline gap — is harder.

Will Amazon S3 Vectors Kill Vector Databases—or Save Them?
AWS S3 Vectors aims for 90% cost savings for vector storage. But will it kill vectordbs like Milvus? A deep dive into costs, limits, and the future of tiered storage.

Zilliz Cloud Audit Logs Goes GA: Security, Compliance, and Transparency at Scale
Zilliz Cloud Audit Logs are now GA, giving enterprises real-time visibility, compliance-ready trails, and stronger security across AWS, GCP, and Azure.



