Aprovechando los superpoderes de NLP Un tutorial paso a paso para ajustar finamente Hugging Face

Potenciando los superpoderes de NLP Un tutorial paso a paso para dominar Hugging Face

Introducción

Ajustar finamente un modelo de procesamiento de lenguaje natural (NLP, por sus siglas en inglés) implica alterar los hiperparámetros y la arquitectura del modelo, y ajustar típicamente el conjunto de datos para mejorar el rendimiento del modelo en una tarea específica. Esto se puede lograr ajustando la tasa de aprendizaje, el número de capas del modelo, el tamaño de las incrustaciones y otros parámetros diversos. El ajuste fino es un procedimiento que consume mucho tiempo y requiere un sólido conocimiento del modelo y del trabajo. Este artículo analizará cómo ajustar finamente un modelo de Hugging Face.

Objetivos de aprendizaje

  • Comprender la estructura del modelo T5, que incluye Transformers y la auto-atención.
  • Aprender a optimizar los hiperparámetros para mejorar el rendimiento del modelo.
  • Dominar la preparación de datos de texto, incluida la tokenización y el formato.
  • Saber cómo adaptar modelos pre-entrenados a tareas específicas.
  • Aprender a limpiar, dividir y crear conjuntos de datos para el entrenamiento.
  • Obtener experiencia en el entrenamiento y la evaluación de modelos utilizando métricas como la pérdida y la precisión.
  • Explorar aplicaciones del mundo real del modelo ajustado finamente para generar respuestas o respuestas.

Este artículo se publicó como parte de la blogatón de ciencia de datos.

Acerca de los modelos de Hugging Face

Hugging Face es una empresa que proporciona una plataforma para el entrenamiento y despliegue de modelos de procesamiento de lenguaje natural (NLP). La plataforma alberga una biblioteca de modelos adecuados para diversas tareas de NLP, como la traducción de idiomas, la generación de texto y la respuesta a preguntas. Estos modelos se entrenan en conjuntos de datos extensos y están diseñados para destacarse en una amplia gama de actividades de procesamiento de lenguaje natural (NLP).

La plataforma de Hugging Face también incluye herramientas para ajustar finamente modelos pre-entrenados en conjuntos de datos específicos, lo que puede ayudar a adaptar los algoritmos a dominios o idiomas particulares. La plataforma también cuenta con APIs para acceder y utilizar modelos pre-entrenados en aplicaciones y herramientas para construir modelos personalizados y entregarlos en la nube.

El uso de la biblioteca de Hugging Face para tareas de procesamiento de lenguaje natural (NLP) tiene varias ventajas:

  1. Amplia selección de modelos: La biblioteca de Hugging Face ofrece una amplia gama de modelos pre-entrenados de NLP, incluyendo modelos entrenados en tareas como la traducción de idiomas, la respuesta a preguntas y la categorización de texto. Esto hace que sea fácil elegir un modelo que se adapte a tus necesidades exactas.
  2. Compatibilidad en diferentes plataformas: La biblioteca de Hugging Face es compatible con sistemas estándar de aprendizaje profundo, como TensorFlow, PyTorch y Keras, lo que facilita su integración en tu flujo de trabajo existente.
  3. Ajuste fino sencillo: La biblioteca de Hugging Face contiene herramientas para ajustar finamente modelos pre-entrenados en tu conjunto de datos, lo que te ahorra tiempo y esfuerzo en comparación con entrenar un modelo desde cero.
  4. Comunidad activa: La biblioteca de Hugging Face cuenta con una vasta y activa comunidad de usuarios, lo que significa que puedes obtener ayuda y soporte, y contribuir al crecimiento de la biblioteca.
  5. Bien documentado: La biblioteca de Hugging Face contiene una extensa documentación, lo que facilita comenzar y aprender a utilizarla de manera eficiente.

Importar bibliotecas necesarias

Importar las bibliotecas necesarias es análogo a construir un conjunto de herramientas para una actividad específica de programación y análisis de datos. Estas bibliotecas, que son frecuentemente colecciones de código pre-escrito, ofrecen una amplia gama de funciones y herramientas que ayudan a acelerar el desarrollo. Los desarrolladores y científicos de datos pueden acceder a nuevas capacidades, aumentar la productividad y utilizar soluciones existentes importando las bibliotecas adecuadas.

import pandas as pdimport numpy as npfrom sklearn.model_selection import train_test_splitimport torchfrom transformers import T5Tokenizerfrom transformers import T5ForConditionalGeneration, AdamWimport pytorch_lightning as plfrom pytorch_lightning.callbacks import ModelCheckpointpl.seed_everything(100)import warningswarnings.filterwarnings("ignore")

Importar Conjunto de Datos

Importar un conjunto de datos es un paso inicial crucial en proyectos basados en datos.

df = pd.read_csv("/kaggle/input/queestion-answer-dataset-qa/train.csv")df.columns

df = df[['context','question', 'text']]print("Número de registros: ", df.shape[0])

Declaración del Problema

“Crear un modelo capaz de generar respuestas basadas en el contexto y las preguntas”.

Por ejemplo,

Contexto = “Agrupar casos similares, por ejemplo, puede encontrar pacientes similares o utilizar para la segmentación de clientes en el campo bancario. La técnica de asociación se utiliza para encontrar elementos o eventos que a menudo ocurren juntos, por ejemplo, productos de supermercado que un cliente particular compra regularmente. La detección de anomalías se utiliza para descubrir casos anormales e inusuales, por ejemplo, la detección de fraude con tarjetas de crédito”.

Pregunta = “¿Cuál es un ejemplo de detección de anomalías?”

Respuesta = ????????????????????????????????

df["context"] = df["context"].str.lower()df["question"] = df["question"].str.lower()df["text"] = df["text"].str.lower()df.head()

Inicializar Parámetros

  • Longitud de entrada: Durante el entrenamiento, nos referimos al número de tokens de entrada (por ejemplo, palabras o caracteres) en un único ejemplo alimentado al modelo como la longitud de entrada. Si estás entrenando un modelo de lenguaje para predecir la siguiente palabra en una oración, la longitud de entrada sería el número de palabras en la frase.
  • Longitud de salida: Durante el entrenamiento, se espera que el modelo genere una cantidad específica de tokens de salida, como palabras o caracteres, en una sola muestra. La longitud de salida corresponde al número de palabras que el modelo predice en la oración.
  • Tamaño de lote de entrenamiento: Durante el entrenamiento, el modelo procesa varias muestras a la vez. Si estableces el tamaño de lote de entrenamiento en 32, el modelo maneja 32 instancias, como 32 frases, simultáneamente antes de actualizar los pesos del modelo.
  • Tamaño de lote de validación: Similar al tamaño de lote de entrenamiento, este parámetro indica el número de instancias que el modelo maneja durante la fase de validación. En otras palabras, representa el volumen de datos que el modelo procesa cuando se prueba en un conjunto de datos de retención.
  • Épocas: Una época es un recorrido completo por el conjunto de datos de entrenamiento. Entonces, si el conjunto de datos de entrenamiento consta de 1000 instancias y el tamaño de lote de entrenamiento es 32, una época necesitará 32 pasos de entrenamiento. Si el modelo se entrena durante diez épocas, habrá procesado diez mil instancias (10 * 1000 = diez mil).
DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu') INPUT_MAX_LEN = 512 # Longitud de entradaOUT_MAX_LEN = 128 # Longitud de salidaTRAIN_BATCH_SIZE = 8 # Tamaño de lote de entrenamientoVALID_BATCH_SIZE = 2 # Tamaño de lote de validaciónEPOCHS = 5 # Número de iteraciones

Transformador T5

El modelo T5 se basa en la arquitectura del Transformador, una red neuronal diseñada para manejar eficazmente datos de entrada secuenciales. Consta de un codificador y un decodificador, que incluyen una secuencia de “capas” interconectadas.

Las capas del codificador y decodificador comprenden varios mecanismos de “atención” y redes “feedforward”. Los mecanismos de atención permiten que el modelo se centre en diferentes secciones de la secuencia de entrada en diferentes momentos. Al mismo tiempo, las redes feedforward alteran los datos de entrada utilizando un conjunto de pesos y sesgos.

El modelo T5 también emplea “auto-atención”, que permite que cada elemento de la secuencia de entrada preste atención a todos los demás elementos. Esto permite que el modelo reconozca las relaciones entre palabras y frases en los datos de entrada, lo cual es fundamental para muchas aplicaciones de procesamiento del lenguaje natural (PLN).

Además del codificador y decodificador, el modelo T5 contiene una “cabeza de modelo de lenguaje” que predice la siguiente palabra en una secuencia en función de las palabras anteriores. Esto es fundamental para trabajos de traducción y producción de texto, donde el modelo debe proporcionar una salida cohesiva y con un sonido natural.

El modelo T5 representa una red neural grande y sofisticada diseñada para un procesamiento altamente eficiente y preciso de entrada secuencial. Ha sido sometido a un entrenamiento exhaustivo en un conjunto de datos de texto variado y puede realizar eficientemente una amplia gama de tareas de procesamiento de lenguaje natural.

T5Tokenizer

T5Tokenizer se utiliza para convertir un texto en una lista de tokens, cada uno representando una sola palabra o signo de puntuación. El tokenizador también inserta tokens únicos en el texto de entrada para denotar el inicio y final del texto y distinguir diversas frases.

T5Tokenizer utiliza una combinación de tokenización a nivel de caracteres y palabras, y una estrategia de tokenización a nivel de subpalabras comparable al tokenizador SentencePiece. Divide el texto de entrada en subpalabras en función de la frecuencia de cada carácter o secuencia de caracteres en los datos de entrenamiento. Esto ayuda al tokenizador a lidiar con términos fuera del vocabulario (OOV) que no ocurren en los datos de entrenamiento pero aparecen en los datos de prueba.

Además, T5Tokenizer inserta tokens únicos en el texto para denotar el inicio y final de las frases y para dividirlas. Por ejemplo, agrega los tokens s> y /s> para indicar el inicio y final de una frase, y pad> para indicar el relleno.

MODEL_NAME = "t5-base"tokenizer = T5Tokenizer.from_pretrained(MODEL_NAME, model_max_length= INPUT_MAX_LEN)

print("eos_token: {} and id: {}".format(tokenizer.eos_token,                   tokenizer.eos_token_id)) # Fin del token (eos_token)print("unk_token: {} and id: {}".format(tokenizer.unk_token,                   tokenizer.eos_token_id)) # Token desconocido (unk_token)print("pad_token: {} and id: {}".format(tokenizer.pad_token,                 tokenizer.eos_token_id)) # Token de relleno (pad_token)

Preparación del conjunto de datos

Cuando trabajas con PyTorch, generalmente preparas tus datos para usarlos con el modelo utilizando una clase de conjunto de datos. La clase de conjunto de datos se encarga de cargar los datos del disco y ejecutar los procedimientos de preparación requeridos, como la tokenización y numeración. La clase también debe implementar la función getitem, que se utiliza para obtener un solo elemento del conjunto de datos por índice.

El método init popula el conjunto de datos con la lista de texto, lista de etiquetas y el tokenizador. La función len devuelve el número de muestras en el conjunto de datos. La función getitem devuelve un solo elemento del conjunto de datos por índice. Acepta un índice idx y devuelve la entrada y etiquetas tokenizadas.

También es habitual incluir varios pasos de preprocesamiento, como el relleno y truncamiento de las entradas tokenizadas. También puedes convertir las etiquetas en tensores.

class T5Dataset:    def __init__(self, contexto, pregunta, objetivo):        self.contexto = contexto        self.pregunta = pregunta        self.objetivo = objetivo        self.tokenizador = tokenizador        self.longitud_max_entrada = LONGITUD_MAX_ENTRADA        self.longitud_max_salida = LONGITUD_MAX_SALIDA    def __len__(self):        return len(self.contexto)    def __getitem__(self, item):        contexto = str(self.contexto[item])        contexto = " ".join(contexto.split())        pregunta = str(self.pregunta[item])        pregunta = " ".join(pregunta.split())        objetivo = str(self.objetivo[item])        objetivo = " ".join(objetivo.split())                        codificacion_entradas = self.tokenizador(            contexto,            pregunta,            add_special_tokens=True,            max_length=self.longitud_max_entrada,            padding = 'max_length',            truncation='only_first',            return_attention_mask=True,            return_tensors="pt"        )                codificacion_salida = self.tokenizador(            objetivo,            None,            add_special_tokens=True,            max_length=self.longitud_max_salida,            padding = 'max_length',            truncation=True,            return_attention_mask=True,            return_tensors="pt"        )        ids_entradas = codificacion_entradas["input_ids"].flatten()        mascara_atencion = codificacion_entradas["attention_mask"].flatten()        etiquetas = codificacion_salida["input_ids"]        etiquetas[etiquetas == 0] = -100  # Según la documentación de T5        etiquetas = etiquetas.flatten()        resultado = {            "contexto": contexto,            "pregunta": pregunta,            "respuesta": objetivo,            "ids_entradas": ids_entradas,            "mascara_atencion": mascara_atencion,            "etiquetas": etiquetas        }        return resultado   

DataLoader

La clase DataLoader carga datos en paralelo y en lotes, lo que hace posible trabajar con grandes conjuntos de datos que de otro modo serían demasiado vastos para almacenar en memoria. Combina la clase DataLoader con una clase de conjunto de datos que contiene los datos que se van a cargar.

El DataLoader se encarga de iterar sobre el conjunto de datos y devolver un lote de datos al modelo para el entrenamiento o la evaluación mientras se entrena un modelo de transformador. La clase DataLoader ofrece varios parámetros para controlar la carga y el preprocesamiento de los datos, incluyendo el tamaño del lote, el número de hilos de trabajo y si se deben mezclar los datos antes de cada época.

class T5DatasetModule(pl.LightningDataModule):
    def __init__(self, df_train, df_valid):
        super().__init__()
        self.df_train = df_train
        self.df_valid = df_valid
        self.tokenizer = tokenizer
        self.input_max_len = INPUT_MAX_LEN
        self.out_max_len = OUT_MAX_LEN

    def setup(self, stage=None):
        self.train_dataset = T5Dataset(
            context=self.df_train.context.values,
            question=self.df_train.question.values,
            target=self.df_train.text.values
        )
        self.valid_dataset = T5Dataset(
            context=self.df_valid.context.values,
            question=self.df_valid.question.values,
            target=self.df_valid.text.values
        )

    def train_dataloader(self):
        return torch.utils.data.DataLoader(
            self.train_dataset,
            batch_size= TRAIN_BATCH_SIZE,
            shuffle=True,
            num_workers=4
        )

    def val_dataloader(self):
        return torch.utils.data.DataLoader(
            self.valid_dataset,
            batch_size= VALID_BATCH_SIZE,
            num_workers=1
        )

Construcción del modelo

Cuando se crea un modelo de transformador en PyTorch, generalmente se comienza creando una nueva clase que se deriva de torch.nn.Module. Esta clase describe la arquitectura del modelo, incluyendo las capas y la función forward. La función init de la clase define la arquitectura del modelo, a menudo instanciando los diferentes niveles del modelo y asignándolos como atributos de clase.

El método forward se encarga de pasar los datos a través del modelo en la dirección forward. Este método acepta datos de entrada y aplica las capas del modelo para crear la salida. El método forward debe implementar la lógica del modelo, como pasar la entrada a través de una secuencia de capas y devolver el resultado.

El método init de la clase crea una capa de embedding, una capa de transformador y una capa completamente conectada y las asigna como atributos de clase. El método forward acepta los datos de entrada entrantes x, los procesa a través de las etapas dadas y devuelve el resultado. Al entrenar un modelo de transformador, el proceso de entrenamiento típicamente implica dos etapas: entrenamiento y validación.

El método training_step especifica la razón para llevar a cabo un solo paso de entrenamiento, que generalmente incluye:

  • paso forward a través del modelo
  • cálculo de la pérdida
  • cálculo de los gradientes
  • actualización de los parámetros del modelo

El método val_step, al igual que el método training_step, se utiliza para evaluar el modelo en un conjunto de validación. Por lo general, incluye:

  • paso forward a través del modelo
  • cálculo de las métricas de evaluación
class T5Model(pl.LightningModule):
    def __init__(self):
        super().__init__()
        self.model = T5ForConditionalGeneration.from_pretrained(MODEL_NAME, return_dict=True)
        
    def forward(self, input_ids, attention_mask, labels=None):
        output = self.model(
            input_ids=input_ids,
            attention_mask=attention_mask,
            labels=labels
        )
        return output.loss, output.logits
    
    def training_step(self, batch, batch_idx):
        input_ids = batch["inputs_ids"]
        attention_mask = batch["attention_mask"]
        labels= batch["targets"]
        loss, outputs = self(input_ids, attention_mask, labels)
        
        self.log("train_loss", loss, prog_bar=True, logger=True)
        return loss
    
    def validation_step(self, batch, batch_idx):
        input_ids = batch["inputs_ids"]
        attention_mask = batch["attention_mask"]
        labels= batch["targets"]
        loss, outputs = self(input_ids, attention_mask, labels)
        self.log("val_loss", loss, prog_bar=True, logger=True)
        
        return loss
    
    def configure_optimizers(self):
        return AdamW(self.parameters(), lr=0.0001)

Entrenamiento del modelo

Iterar sobre el conjunto de datos en lotes, enviar la entrada a través del modelo y cambiar los parámetros del modelo basado en los gradientes calculados y un conjunto de criterios de optimización es habitual para entrenar un modelo de transformador.

def run():
    df_train, df_valid = train_test_split(
        df[0:10000], test_size=0.2, random_state=101
    )
    df_train = df_train.fillna("none")
    df_valid = df_valid.fillna("none")
    
    df_train['context'] = df_train['context'].apply(lambda x: " ".join(x.split()))
    df_valid['context'] = df_valid['context'].apply(lambda x: " ".join(x.split()))
    
    df_train['text'] = df_train['text'].apply(lambda x: " ".join(x.split()))
    df_valid['text'] = df_valid['text'].apply(lambda x: " ".join(x.split()))
    
    df_train['question'] = df_train['question'].apply(lambda x: " ".join(x.split()))
    df_valid['question'] = df_valid['question'].apply(lambda x: " ".join(x.split()))
    
    df_train = df_train.reset_index(drop=True)
    df_valid = df_valid.reset_index(drop=True)
    
    dataModule = T5DatasetModule(df_train, df_valid)
    dataModule.setup()
    
    device = DEVICE
    model = T5Model()
    model.to(device)
    
    checkpoint_callback  = ModelCheckpoint(
        dirpath="/kaggle/working",
        filename="best_checkpoint",
        save_top_k=2,
        verbose=True,
        monitor="val_loss",
        mode="min"
    )
    
    trainer = pl.Trainer(
        callbacks=checkpoint_callback,
        max_epochs=EPOCHS,
        gpus=1,
        accelerator="gpu"
    )
    
    trainer.fit(model, dataModule)
    
run()

Predicción del modelo

Para realizar predicciones con un modelo de PLN ajustado como T5 utilizando nuevos datos de entrada, puedes seguir estos pasos:

  • Preprocesar los nuevos datos de entrada: Tokeniza y preprocesa el texto de entrada para que coincida con el preprocesamiento que aplicaste a tus datos de entrenamiento. Asegúrate de que tenga el formato correcto esperado por el modelo.
  • Usar el modelo ajustado para inferencia: Carga tu modelo T5 ajustado, que previamente entrenaste o cargaste desde un punto de control.
  • Generar predicciones: Pasa los nuevos datos de entrada preprocesados al modelo para realizar la predicción. En el caso de T5, puedes usar el método generate para generar respuestas.
train_model = T5Model.load_from_checkpoint("/kaggle/working/best_checkpoint-v1.ckpt")train_model.freeze()def generate_question(context, question):    inputs_encoding =  tokenizer(        context,        question,        add_special_tokens=True,        max_length= INPUT_MAX_LEN,        padding = 'max_length',        truncation='only_first',        return_attention_mask=True,        return_tensors="pt"        )        generate_ids = train_model.model.generate(        input_ids = inputs_encoding["input_ids"],        attention_mask = inputs_encoding["attention_mask"],        max_length = INPUT_MAX_LEN,        num_beams = 4,        num_return_sequences = 1,        no_repeat_ngram_size=2,        early_stopping=True,        )    preds = [        tokenizer.decode(gen_id,        skip_special_tokens=True,         clean_up_tokenization_spaces=True)        for gen_id in generate_ids    ]    return "".join(preds)

Predicción

Vamos a generar una predicción utilizando el modelo T5 ajustado con nuevos datos de entrada:

contexto = “Agrupar grupos de casos similares, por ejemplo, puede encontrar pacientes similares o utilizarlos para la segmentación de clientes en el campo bancario. Utilizando técnicas de asociación para encontrar elementos o eventos que a menudo coocurren, por ejemplo, artículos de supermercado que se compran juntos con frecuencia por un cliente en particular. Utilizando detección de anomalías para descubrir casos anormales e inusuales, por ejemplo, la detección de fraudes con tarjetas de crédito.”

pregunta = “¿Cuál es un ejemplo de detección de anomalías?”

print(generate_question(contexto, pregunta))

contexto = "La clasificación se utiliza cuando tu objetivo es categórico, mientras que la regresión se utiliza cuando tu variable objetivo es continua. Tanto la clasificación como la regresión pertenecen a la categoría de algoritmos de aprendizaje supervisado."

Conclusión

En este artículo, nos embarcamos en un viaje para ajustar un modelo de procesamiento de lenguaje natural (PLN), específicamente el modelo T5, para una tarea de pregunta-respuesta. A lo largo de este proceso, exploramos diversos aspectos del desarrollo y despliegue de modelos de PLN.

Principales conclusiones:

  • Exploramos la estructura codificador-decodificador y los mecanismos de auto-atención que fundamentan sus capacidades.
  • El arte de la sintonización de hiperparámetros es una habilidad esencial para optimizar el rendimiento del modelo.
  • Experimentar con tasas de aprendizaje, tamaños de lote y tamaños de modelo nos permitió ajustar el modelo de manera efectiva.
  • Proficientes en fichas de tokens, relleno y conversión de datos de texto sin formato en un formato adecuado para la entrada del modelo.
  • Profundizamos en el ajuste fino, incluida la carga de pesos pre-entrenados, la modificación de las capas del modelo y su adaptación a tareas específicas.
  • Aprendimos cómo limpiar y estructurar datos, dividiéndolos en conjuntos de entrenamiento y validación.
  • Mostramos cómo el modelo puede generar respuestas basadas en el contexto y las preguntas de entrada, mostrando su utilidad en el mundo real.

Preguntas frecuentes

Los medios mostrados en este artículo no son propiedad de Analytics Vidhya y se utilizan a discreción del autor.

We will continue to update Zepes; if you have any questions or suggestions, please contact us!

Share:

Was this article helpful?

93 out of 132 found this helpful

Discover more

Aprendizaje Automático

Los ejércitos de robots luchan en las épicas batallas en pantalla de Battlecode.

La competencia de programación de larga duración fomenta habilidades y amistades que duran toda la vida.

Inteligencia Artificial

Ordenando el marco de los cambios en los conjuntos de datos El ejemplo

Hablé recientemente sobre las causas de la degradación del rendimiento del modelo, es decir, cuando la calidad de sus...

Inteligencia Artificial

Investigación de Google revela Transformadores Generativos de Vocabulario Infinito (GIVT) Pioneros en secuencias de vectores de valor real en IA

Los Transformers fueron introducidos por primera vez y rápidamente se elevaron a la prominencia como la arquitectura ...

Inteligencia Artificial

Tiempo 100 IA ¿Los más influyentes?

La revista Time acaba de publicar su lista Time 100 AI, destacando a 100 figuras clave en IA en categorías como líder...