Guía para principiantes sobre el ajuste fino de modelos de lenguaje grandes (LLMs)

Guía para principiantes sobre ajuste fino de LLMs

Introducción

Embárcate en un viaje a través de la evolución de la inteligencia artificial y los asombrosos avances realizados en el Procesamiento del Lenguaje Natural (NLP, por sus siglas en inglés). En un abrir y cerrar de ojos, la IA ha avanzado rápidamente, dando forma a nuestro mundo. El impacto sísmico de ajustar los grandes modelos de lenguaje ha transformado por completo el NLP, revolucionando nuestras interacciones tecnológicas. Retrocedamos a 2017, un momento crucial marcado por ‘Atención es todo lo que necesitas’, dando origen a la innovadora arquitectura ‘Transformer’. Esta arquitectura ahora es la piedra angular del NLP, un ingrediente irremplazable en cada receta de los grandes modelos de lenguaje, incluido el famoso ChatGPT.

Imagina generar texto coherente y rico en contexto sin esfuerzo, eso es la magia de modelos como GPT-3. Verdaderas potencias para chatbots, traducciones y generación de contenido, su brillantez se origina en la arquitectura y en la intrincada danza de preentrenamiento y ajuste fino. Nuestro próximo artículo se adentra en esta sinfonía, desvelando el arte detrás de aprovechar los grandes modelos de lenguaje para tareas, utilizando el dúo dinámico de preentrenamiento y ajuste fino de manera magistral. ¡Acompáñanos a desmitificar estas técnicas transformadoras!

Objetivos de Aprendizaje

  • Comprender las diferentes formas de construir aplicaciones de LLM.
  • Aprender técnicas como extracción de características, ajuste fino de capas y métodos de adaptador.
  • Ajustar finamente LLM en una tarea secundaria utilizando la biblioteca de transformers de Huggingface.

Comenzando con LLMs

LLMs son las siglas de Large Language Models (Grandes Modelos de Lenguaje). Los LLMs son modelos de aprendizaje profundo diseñados para comprender el significado de texto similar al generado por los humanos y realizar diversas tareas como análisis de sentimientos, modelado del lenguaje (predicción de la siguiente palabra), generación de texto, resumen de texto y mucho más. Son entrenados con una gran cantidad de datos de texto.

Usamos aplicaciones basadas en estos LLMs a diario sin siquiera darnos cuenta. Google utiliza BERT (Bidirectional Encoder Representations for Transformers) para diversas aplicaciones como completar consultas, comprender el contexto de las consultas, producir resultados de búsqueda más relevantes y precisos, traducción de idiomas y más.

Estos modelos se basan en técnicas de aprendizaje profundo, redes neuronales profundas y técnicas avanzadas como la autoatención. Son entrenados con grandes cantidades de datos de texto para aprender los patrones, estructuras y semántica del lenguaje.

Dado que estos modelos se entrenan con conjuntos de datos extensos, llevaría mucho tiempo y recursos entrenarlos desde cero. Existen técnicas mediante las cuales podemos utilizar directamente estos modelos para una tarea específica. Así que vamos a discutirlas en detalle.

Descripción general de las diferentes formas de construir aplicaciones de LLM

A menudo vemos aplicaciones emocionantes de LLM en nuestra vida cotidiana. ¿Te gustaría saber cómo construir aplicaciones de LLM? Aquí hay 3 formas de construir aplicaciones de LLM:

  1. Entrenar LLMs desde cero
  2. Ajustar finamente grandes modelos de lenguaje
  3. Prompts

Entrenar LLMs desde cero

A menudo, las personas se confunden entre estos dos términos: entrenamiento y ajuste fino de LLMs. Ambas técnicas funcionan de manera similar, es decir, cambian los parámetros del modelo, pero los objetivos de entrenamiento son diferentes.

Entrenar LLMs desde cero también se conoce como preentrenamiento. El preentrenamiento es la técnica en la cual un gran modelo de lenguaje se entrena con una gran cantidad de texto no etiquetado. Pero la pregunta es: “¿Cómo podemos entrenar un modelo con datos no etiquetados y luego esperar que el modelo prediga los datos con precisión?”. Aquí entra en juego el concepto de ‘Aprendizaje Auto-Supervisado’. En el aprendizaje auto-supervisado, un modelo oculta una palabra e intenta predecir la siguiente palabra con la ayuda de las palabras anteriores. Por ejemplo, supongamos que tenemos una frase: ‘Soy un científico de datos’.

El modelo puede crear sus propios datos etiquetados a partir de esta frase, como:

Esto se conoce como predicción de la siguiente palabra, realizada por un Modelo de Lenguaje Enmascarado (MLM, por sus siglas en inglés). BERT, un modelo de lenguaje enmascarado, utiliza esta técnica para predecir la palabra enmascarada. Podemos pensar en el MLM como un concepto de ‘relleno de espacio en blanco’, en el cual el modelo predice qué palabra puede encajar en el espacio en blanco. Hay diferentes formas de predecir la siguiente palabra, pero en este artículo solo hablaremos de BERT, el MLM. BERT puede analizar tanto las palabras precedentes como las siguientes para comprender el contexto de la frase y predecir la palabra enmascarada.

Entonces, como una descripción general de alto nivel del preentrenamiento, es simplemente una técnica en la que el modelo aprende a predecir la siguiente palabra en el texto.

Ajuste fino de modelos de lenguaje grandes

El ajuste fino es ajustar los parámetros del modelo para que sea adecuado para realizar una tarea específica. Después de que el modelo se preentrena, se ajusta fino o, en palabras simples, se entrena para realizar una tarea específica como análisis de sentimiento, generación de texto, encontrar similitud de documentos, etc. No tenemos que entrenar el modelo nuevamente en un texto grande; en cambio, usamos el modelo entrenado para realizar la tarea que queremos realizar. Discutiremos cómo ajustar fino un modelo de lenguaje grande en detalle más adelante en este artículo.

Dar instrucciones

Dar instrucciones es la técnica más fácil de las 3, pero un poco complicada. Implica dar al modelo un contexto (instrucción) en función del cual el modelo realiza tareas. Piense en ello como enseñarle a un niño un capítulo de su libro en detalle, siendo muy discreto en la explicación, y luego pedirle que resuelva el problema relacionado con ese capítulo.

En el contexto de LLM, tomemos, por ejemplo, ChatGPT; establecemos un contexto y le pedimos al modelo que siga las instrucciones para resolver el problema dado.

Supongamos que quiero que ChatGPT me haga algunas preguntas de entrevista solo sobre Transformers. Para una mejor experiencia y resultados precisos, debes establecer un contexto adecuado y dar una descripción detallada de la tarea.

Ejemplo: Soy un científico de datos con dos años de experiencia y actualmente me estoy preparando para una entrevista de trabajo en tal y tal empresa. Me encanta resolver problemas y actualmente estoy trabajando con modelos de procesamiento del lenguaje natural de última generación. Estoy al día con las últimas tendencias y tecnologías. Hazme preguntas muy difíciles sobre el modelo Transformer que el entrevistador de esta empresa puede hacer en función de la experiencia previa de la empresa. Hazme diez preguntas y también da las respuestas a las preguntas.

Cuanto más detallado y específico sea el contexto que proporciones, mejores serán los resultados. La parte más divertida es que puedes generar el contexto desde el propio modelo y luego agregarle un toque personal o la información necesaria.

Comprender diferentes técnicas de ajuste fino

Existen diferentes formas de ajustar fino un modelo de manera convencional, y los enfoques diferentes dependen del problema específico que deseas resolver. Discutamos las técnicas para ajustar fino un modelo.

Hay 3 formas de ajustar fino convencionalmente un LLM.

Extracción de características

Las personas usan esta técnica para extraer características de un texto dado, pero ¿por qué queremos extraer incrustaciones de un texto dado? La respuesta es sencilla. Debido a que las computadoras no comprenden el texto, debe haber una representación del texto que podamos usar para llevar a cabo diversas tareas. Una vez que extraemos las incrustaciones, son capaces de realizar tareas como análisis de sentimiento, identificación de similitud de documentos y más. En la extracción de características, se bloquean las capas principales del modelo, lo que significa que no se actualizan los parámetros de esas capas; solo se actualizan los parámetros de las capas del clasificador. Las capas del clasificador involucran las capas completamente conectadas.

Ajuste fino del modelo completo

Como su nombre lo indica, entrenamos cada capa del modelo en el conjunto de datos personalizado durante un número específico de épocas en esta técnica. Ajustamos los parámetros de todas las capas del modelo según el nuevo conjunto de datos personalizado. Esto puede mejorar la precisión del modelo en los datos y la tarea específica que queremos realizar. Es computacionalmente costoso y lleva mucho tiempo entrenar al modelo, considerando que hay miles de millones de parámetros en los modelos de lenguaje grandes de ajuste fino.

Ajuste fino basado en adaptadores

El ajuste fino basado en adaptadores es un concepto comparativamente nuevo en el que se agrega una capa o un módulo adicional inicializado al azar a la red y luego se entrena para una tarea específica. En esta técnica, los parámetros del modelo se dejan sin cambios, o podemos decir que los parámetros del modelo no se modifican ni ajustan. En cambio, se entrenan los parámetros de la capa del adaptador. Esta técnica ayuda a ajustar el modelo de manera computacionalmente eficiente.

Implementación: Ajuste fino de BERT en una tarea secundaria

Ahora que conocemos las técnicas de ajuste fino, realicemos un análisis de sentimiento en las reseñas de películas de IMDB utilizando BERT. BERT es un modelo de lenguaje grande que combina capas de transformador y solo es codificador. Google lo desarrolló y ha demostrado funcionar muy bien en diversas tareas. BERT viene en diferentes tamaños y variantes como BERT-base-uncased, BERT Large, RoBERTa, LegalBERT y muchos más.

Modelo BERT para realizar análisis de sentimientos

Utilicemos el modelo BERT para realizar análisis de sentimientos en las reseñas de películas de IMDB. Para disponibilidad gratuita de GPU, se recomienda utilizar Google Colab. Comencemos el entrenamiento cargando algunas bibliotecas importantes.

Dado que BERT (Bidirectional Encoder Representations for Encoders) se basa en Transformers, el primer paso sería instalar transformers en nuestro entorno.

!pip install transformers

Carguemos algunas bibliotecas que nos ayudarán a cargar los datos según lo requiera el modelo BERT, tokenizar los datos cargados, cargar el modelo que utilizaremos para la clasificación, realizar la división de entrenamiento y prueba, cargar nuestro archivo CSV y algunas funciones más.

import pandas as pd
import numpy as np
import os
from sklearn.model_selection import train_test_split
import torch
import torch.nn as nn
from transformers import BertTokenizer, BertModel

Para una computación más rápida, debemos cambiar el dispositivo de CPU a GPU

device = torch.device("cuda")

El siguiente paso sería cargar nuestro conjunto de datos y ver los primeros 5 registros en el conjunto de datos.

df = pd.read_csv('/content/drive/MyDrive/movie.csv')
df.head()

Dividiremos nuestro conjunto de datos en conjuntos de entrenamiento y validación. También puedes dividir los datos en conjuntos de entrenamiento, validación y prueba, pero por simplicidad, solo estoy dividiendo el conjunto de datos en entrenamiento y validación.

x_train, x_val, y_train, y_val = train_test_split(df.text, df.label, random_state = 42, test_size = 0.2, stratify = df.label)

Importar y cargar el modelo BERT

Importemos y carguemos el modelo BERT y el tokenizador.

from transformers.models.bert.modeling_bert import BertForSequenceClassification
# importar el modelo BERT-base pre-entrenado
BERT = BertModel.from_pretrained('bert-base-uncased')
# Cargar el tokenizador BERT
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')

Utilizaremos el tokenizador para convertir el texto en tokens con una longitud máxima de 250 y hacer padding y truncamiento cuando sea necesario.

train_tokens = tokenizer.batch_encode_plus(x_train.tolist(), max_length = 250, pad_to_max_length=True, truncation=True)
val_tokens = tokenizer.batch_encode_plus(x_val.tolist(), max_length = 250, pad_to_max_length=True, truncation=True)

El tokenizador devuelve un diccionario con tres pares clave-valor que contienen los input_ids, que son los tokens relacionados con una palabra en particular; token_type_ids, que es una lista de enteros que distingue entre diferentes segmentos o partes de la entrada. Y attention_mask que indica a qué token prestar atención.

Convirtiendo estos valores en tensores

train_ids = torch.tensor(train_tokens['input_ids'])
train_masks = torch.tensor(train_tokens['attention_mask'])
train_label = torch.tensor(y_train.tolist())
val_ids = torch.tensor(val_tokens['input_ids'])
val_masks = torch.tensor(val_tokens['attention_mask'])
val_label = torch.tensor(y_val.tolist())

Cargando TensorDataset y DataLoaders para procesar los datos aún más y hacerlos adecuados para el modelo.

from torch.utils.data import TensorDataset, DataLoader
train_data = TensorDataset(train_ids, train_masks, train_label)
val_data = TensorDataset(val_ids, val_masks, val_label)
train_loader = DataLoader(train_data, batch_size = 32, shuffle = True)
val_loader = DataLoader(val_data, batch_size = 32, shuffle = True)

Nuestra tarea es congelar los parámetros de BERT utilizando nuestro clasificador y luego ajustar esas capas en nuestro conjunto de datos personalizado. Entonces, congelemos los parámetros del modelo. for param in BERT.parameters():param.requires_grad = FalseAhora, tendremos que definir el pase hacia adelante y hacia atrás para las capas que hemos agregado. El modelo BERT actuará como un extractor de características mientras que tendremos que definir explícitamente los pases hacia adelante y hacia atrás para la clasificación.

class Modelo(nn.Module):
  def __init__(self, bert):
    super(Modelo, self).__init__()
    self.bert = bert
    self.dropout = nn.Dropout(0.1)
    self.relu = nn.ReLU()
    self.fc1 = nn.Linear(768, 512)
    self.fc2 = nn.Linear(512, 2)
    self.softmax = nn.LogSoftmax(dim=1)
  def forward(self, sent_id, mask):
    # Pase las entradas al modelo
    outputs = self.bert(sent_id, mask)
    cls_hs = outputs.last_hidden_state[:, 0, :]
    x = self.fc1(cls_hs)
    x = self.relu(x)
    x = self.dropout(x)
    x = self.fc2(x)
    x = self.softmax(x)
    return x

Movamos el modelo a la GPU

modelo = Modelo(BERT)
# enviar el modelo a la GPU
modelo = modelo.to(device)

Definiendo el Optimizador

# optimizador de los transformers de hugging face
from transformers import AdamW
# definir el optimizador
optimizador = AdamW(modelo.parameters(), lr = 1e-5)

Hasta ahora, hemos preprocesado el conjunto de datos y definido nuestro modelo. Ahora es el momento de entrenar el modelo. Tenemos que escribir un código para entrenar y evaluar el modelo. La función de entrenamiento:

def entrenar():
  modelo.train()
  total_perdida, exactitud_total = 0, 0
  predicciones_totales = []
  for paso, lote in enumerate(carga_entrenamiento):
    # Mover el lote a la GPU si está disponible
    lote = [item.to(device) for item in lote]
    id_oracion, mascara, etiquetas = lote
    # Borrar los gradientes calculados previamente
    optimizador.zero_grad()
    # Obtener las predicciones del modelo para el lote actual
    predicciones = modelo(id_oracion, mascara)
    # Calcular la pérdida entre las predicciones y las etiquetas
    funcion_perdida = nn.CrossEntropyLoss()
    perdida = funcion_perdida(predicciones, etiquetas)
    # Agregar a la pérdida total
    total_perdida += perdida.item()
    # Paso de retroceso y actualización del gradiente
    perdida.backward()
    optimizador.step()
    # Mover las predicciones a la CPU y convertirlas en un arreglo numpy
    predicciones = predicciones.detach().cpu().numpy()
    # Agregar las predicciones del modelo
    predicciones_totales.append(predicciones)
  # Calcular la pérdida promedio
  perdida_promedio = total_perdida / len(carga_entrenamiento)
  # Concatenar las predicciones
  predicciones_totales = np.concatenate(predicciones_totales, axis=0)
  # Devolver la pérdida promedio y las predicciones
  return perdida_promedio, predicciones_totales

La Función de Evaluación

def evaluar():
  modelo.eval()
  total_perdida, exactitud_total = 0, 0
  predicciones_totales = []
  for paso, lote in enumerate(carga_validacion):
    # Mover el lote a la GPU si está disponible
    lote = [item.to(device) for item in lote]
    id_oracion, mascara, etiquetas = lote
    # Borrar los gradientes calculados previamente
    optimizador.zero_grad()
    # Obtener las predicciones del modelo para el lote actual
    predicciones = modelo(id_oracion, mascara)
    # Calcular la pérdida entre las predicciones y las etiquetas
    funcion_perdida = nn.CrossEntropyLoss()
    perdida = funcion_perdida(predicciones, etiquetas)
    # Agregar a la pérdida total
    total_perdida += perdida.item()
    # Paso de retroceso y actualización del gradiente
    perdida.backward()
    optimizador.step()
    # Mover las predicciones a la CPU y convertirlas en un arreglo numpy
    predicciones = predicciones.detach().cpu().numpy()
    # Agregar las predicciones del modelo
    predicciones_totales.append(predicciones)
  # Calcular la pérdida promedio
  perdida_promedio = total_perdida / len(carga_validacion)
  # Concatenar las predicciones
  predicciones_totales = np.concatenate(predicciones_totales, axis=0)
  # Devolver la pérdida promedio y las predicciones
  return perdida_promedio, predicciones_totales

Ahora usaremos estas funciones para entrenar el modelo:

# establecer la pérdida inicial en infinito
mejor_perdida_validacion = float('inf')
# definir las épocas
epocas = 5
# listas vacías para almacenar la pérdida de entrenamiento y validación de cada época
perdidas_entrenamiento=[]
perdidas_validacion=[]
# para cada época
for epoca in range(epocas):
  print('\n Epoca {:} / {:}'.format(epoca + 1, epocas))
  # entrenar el modelo
  perdida_entrenamiento, _ = entrenar()
  # evaluar el modelo
  perdida_validacion, _ = evaluar()
  # guardar el mejor modelo
  if perdida_validacion < mejor_perdida_validacion:
    mejor_perdida_validacion = perdida_validacion
    torch.save(modelo.state_dict(), 'pesos_guardados.pt')
    # agregar la pérdida de entrenamiento y validación
  perdidas_entrenamiento.append(perdida_entrenamiento)
  perdidas_validacion.append(perdida_validacion)
  print(f'\nPérdida de Entrenamiento: {perdida_entrenamiento:.3f}')
  print(f'Pérdida de Validación: {perdida_validacion:.3f}')

Y ahí lo tienes. Puedes usar tu modelo entrenado para inferir cualquier dato o texto que elijas.

Conclusión

Este artículo exploró el mundo del ajuste fino de los Modelos de Lenguaje Grandes (LLMs) y su impacto significativo en el procesamiento del lenguaje natural (NLP). Se discutió el proceso de preentrenamiento, donde los LLMs se entrenan con grandes cantidades de texto no etiquetado utilizando el aprendizaje auto-supervisado. También se ahondó en el ajuste fino, que implica adaptar un modelo preentrenado para tareas específicas y en la generación de texto, donde se proporciona contexto a los modelos para generar salidas relevantes. Además, se examinaron diferentes técnicas de ajuste fino, como la extracción de características, el ajuste fino del modelo completo y el ajuste fino basado en adaptadores. Los Modelos de Lenguaje Grandes han revolucionado el NLP y continúan impulsando avances en diversas aplicaciones.

Preguntas frecuentes

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

Inteligencia Artificial

Investigadores de NTU Singapur proponen PointHPS Un marco de IA para la estimación precisa de la postura humana y la forma a partir de nubes de puntos 3D.

Con varios avances en el campo de la Inteligencia Artificial, la estimación de la postura y forma humana (HPS, por su...

Inteligencia Artificial

Alibaba libera el modelo de IA de código abierto para competir con Meta y potenciar a los desarrolladores

En un desarrollo significativo, Alibaba, el gigante chino del comercio electrónico, ha decidido abrir su potente mode...

Ciencia de Datos

Descubriendo los efectos perjudiciales de la IA en la comunidad trans

Cómo la inteligencia artificial está fallando a las personas transgénero. Los peligros del software de reconocimiento...