Entrenar y Ajustar Finalemente Modelos de Sentence Transformers

Entrenamiento y ajuste de modelos de Sentence Transformers.

Revisa este tutorial con el Notebook Companion:



Entrenar o ajustar un modelo de Sentence Transformers depende en gran medida de los datos disponibles y la tarea objetivo. La clave es doble:

  1. Comprender cómo ingresar los datos en el modelo y preparar el conjunto de datos en consecuencia.
  2. Conocer las diferentes funciones de pérdida y cómo se relacionan con el conjunto de datos.

En este tutorial, aprenderás:

  1. Comprender cómo funcionan los modelos de Sentence Transformers al crear uno desde cero o ajustar uno desde el Hugging Face Hub.
  2. Aprender los diferentes formatos que puede tener tu conjunto de datos.
  3. Revisar las diferentes funciones de pérdida que puedes elegir según el formato de tu conjunto de datos.
  4. Entrenar o ajustar tu modelo.
  5. Compartir tu modelo en el Hugging Face Hub.
  6. Aprender cuándo los modelos de Sentence Transformers pueden no ser la mejor opción.

Cómo funcionan los modelos de Sentence Transformers

En un modelo de Sentence Transformers, asignas un texto de longitud variable (o píxeles de imagen) a una incrustación de tamaño fijo que representa el significado de esa entrada. Para comenzar con las incrustaciones, revisa nuestro tutorial anterior. Esta publicación se centra en el texto.

Así es como funcionan los modelos de Sentence Transformers:

  1. Capa 1 – El texto de entrada se pasa a través de un modelo de Transformer preentrenado que se puede obtener directamente desde el Hugging Face Hub. Este tutorial utilizará el modelo “distilroberta-base”. Las salidas del Transformer son incrustaciones de palabras contextualizadas para todos los tokens de entrada; imagina una incrustación para cada token del texto.
  2. Capa 2 – Las incrustaciones pasan por una capa de agrupación para obtener una única incrustación de longitud fija para todo el texto. Por ejemplo, la agrupación media promedia las incrustaciones generadas por el modelo.

Esta figura resume el proceso:

Recuerda instalar la biblioteca Sentence Transformers con pip install -U sentence-transformers. En código, este proceso de dos pasos es simple:

from sentence_transformers import SentenceTransformer, models

## Paso 1: utilizar un modelo de lenguaje existente
word_embedding_model = models.Transformer('distilroberta-base')

## Paso 2: utilizar una función de agrupación sobre las incrustaciones de tokens
pooling_model = models.Pooling(word_embedding_model.get_word_embedding_dimension())

## Combina los pasos 1 y 2 utilizando el argumento modules
model = SentenceTransformer(modules=[word_embedding_model, pooling_model])

A partir del código anterior, puedes ver que los modelos de Sentence Transformers están compuestos por módulos, es decir, una lista de capas que se ejecutan de forma consecutiva. El texto de entrada ingresa al primer módulo y la salida final proviene del último componente. Por más simple que parezca, el modelo anterior es una arquitectura típica para los modelos de Sentence Transformers. Si es necesario, se pueden agregar capas adicionales, como densas, de bolsa de palabras y convolucionales.

¿Por qué no usar un modelo Transformer, como BERT o Roberta, directamente para crear incrustaciones para oraciones y textos completos? Hay al menos dos razones.

  1. Los Transformers preentrenados requieren una gran cantidad de cálculos para realizar tareas de búsqueda semántica. Por ejemplo, encontrar el par más similar en una colección de 10,000 oraciones requiere aproximadamente 50 millones de cálculos de inferencia (~65 horas) con BERT. En cambio, un modelo de Sentence Transformers con BERT reduce el tiempo a aproximadamente 5 segundos.
  2. Una vez entrenados, los Transformers crean representaciones de oraciones deficientes de forma predeterminada. Un modelo BERT con sus incrustaciones de tokens promediadas para crear una incrustación de oración tiene un rendimiento peor que las incrustaciones GloVe desarrolladas en 2014.

En esta sección estamos creando un modelo de Sentence Transformers desde cero. Si deseas ajustar un modelo de Sentence Transformers existente, puedes omitir los pasos anteriores e importarlo desde el Hugging Face Hub. La mayoría de los modelos de Sentence Transformers se encuentran en la tarea de “Similitud de oraciones”. Aquí cargamos el modelo “sentence-transformers/all-MiniLM-L6-v2”:

from sentence_transformers import SentenceTransformer

model_id = "sentence-transformers/all-MiniLM-L6-v2"
model = SentenceTransformer(model_id)

Ahora, la parte más crítica: el formato del conjunto de datos.

Cómo preparar tu conjunto de datos para entrenar un modelo de Sentence Transformers

Para entrenar un modelo de Sentence Transformers, necesitas informar de alguna manera que dos frases tienen un cierto grado de similitud. Por lo tanto, cada ejemplo en los datos requiere una etiqueta o estructura que permita al modelo entender si dos frases son similares o diferentes.

Desafortunadamente, no hay una única forma de preparar tus datos para entrenar un modelo de Sentence Transformers. Esto depende en gran medida de tus objetivos y de la estructura de tus datos. Si no tienes una etiqueta explícita, que es el escenario más probable, puedes derivarla del diseño de los documentos de donde obtuviste las frases. Por ejemplo, dos frases en el mismo informe deberían ser más comparables que dos frases en informes diferentes. Las frases vecinas podrían ser más comparables que las frases no vecinas.

Además, la estructura de tus datos influirá en la función de pérdida que puedes usar. Esto se discutirá en la siguiente sección.

Recuerda que el Cuaderno Complementario de esta publicación ya tiene todo el código implementado.

La mayoría de las configuraciones de conjuntos de datos tomarán una de cuatro formas (a continuación verás ejemplos de cada caso):

  • Caso 1: El ejemplo es un par de frases y una etiqueta que indica cuán similares son. La etiqueta puede ser un número entero o un número decimal. Este caso se aplica a conjuntos de datos preparados originalmente para Inferencia de Lenguaje Natural (NLI), ya que contienen pares de frases con una etiqueta que indica si se infieren entre sí o no.
  • Caso 2: El ejemplo es un par de frases positivas (similares) sin una etiqueta. Por ejemplo, pares de paráfrasis, pares de textos completos y sus resúmenes, pares de preguntas duplicadas, pares de ( consulta , respuesta ), o pares de ( idioma_origen , idioma_destino ). Los conjuntos de datos de Inferencia de Lenguaje Natural también pueden estar formateados de esta manera al emparejar frases que implican a otras. Tener tus datos en este formato puede ser genial, ya que puedes usar la MultipleNegativesRankingLoss, una de las funciones de pérdida más utilizadas para modelos de Sentence Transformers.
  • Caso 3: El ejemplo es una frase con una etiqueta numérica. Este formato de datos se convierte fácilmente por las funciones de pérdida en tres frases (tripletes) donde la primera es un “ancla”, la segunda es un “positivo” de la misma clase que el ancla, y la tercera es un “negativo” de una clase diferente. Cada frase tiene una etiqueta numérica que indica la clase a la que pertenece.
  • Caso 4: El ejemplo es un triplet (ancla, positivo, negativo) sin clases ni etiquetas para las frases.

Como ejemplo, en este tutorial entrenarás un Sentence Transformer utilizando un conjunto de datos en el cuarto caso. Luego, lo ajustarás finamente utilizando la configuración del conjunto de datos del segundo caso (consulta el Cuaderno Complementario para este blog).

Ten en cuenta que los modelos de Sentence Transformers se pueden entrenar con etiquetado humano (casos 1 y 3) o con etiquetas deducidas automáticamente a partir del formato del texto (principalmente caso 2; aunque el caso 4 no requiere etiquetas, es más difícil encontrar datos en un triplet a menos que lo proceses como lo hace la función MegaBatchMarginLoss).

Hay conjuntos de datos en el Hub de Hugging Face para cada uno de los casos mencionados anteriormente. Además, los conjuntos de datos en el Hub tienen una funcionalidad de Vista Previa de Conjunto de Datos que te permite ver la estructura de los conjuntos de datos antes de descargarlos. Aquí tienes ejemplos de conjuntos de datos para cada uno de estos casos:

  • Caso 1: Puedes utilizar la misma configuración que para Inferencia de Lenguaje Natural si tienes (o fabricas) una etiqueta que indica el grado de similitud entre dos frases; por ejemplo {0,1,2} donde 0 es contradicción y 2 es implicación. Revisa la estructura del conjunto de datos SNLI.

  • Caso 2: El conjunto de datos de Compresión de Frases tiene ejemplos compuestos por pares positivos. Si tu conjunto de datos tiene más de dos frases positivas por ejemplo, quintetos como en los conjuntos de datos COCO Captions o Flickr30k Captions, puedes formatear los ejemplos para tener diferentes combinaciones de pares positivos.

  • Caso 3: El conjunto de datos TREC tiene etiquetas numéricas que indican la clase de cada frase. Cada ejemplo en el conjunto de datos de Temas de Yahoo Answers contiene tres frases y una etiqueta que indica su tema; por lo tanto, cada ejemplo se puede dividir en tres.

  • Caso 4: El conjunto de datos de Tripletes de Quora tiene tripletes (ancla, positivo, negativo) sin etiquetas.

El siguiente paso es convertir el conjunto de datos a un formato que el modelo de Sentence Transformers pueda entender. El modelo no puede aceptar listas de cadenas sin procesar. Cada ejemplo debe convertirse en una clase sentence_transformers.InputExample y luego en una clase torch.utils.data.DataLoader para agrupar y mezclar los ejemplos.

Instala Hugging Face Datasets con pip install datasets. Luego importa un conjunto de datos con la función load_dataset:

from datasets import load_dataset

dataset_id = "embedding-data/QQP_triplets"
dataset = load_dataset(dataset_id)

Esta guía utiliza un conjunto de datos de tripletes no etiquetados, el cuarto caso mencionado anteriormente.

Con la biblioteca datasets puedes explorar el conjunto de datos:

print(f"- El conjunto de datos {dataset_id} tiene {dataset['train'].num_rows} ejemplos.")
print(f"- Cada ejemplo es de tipo {type(dataset['train'][0])} con un valor de tipo {type(dataset['train'][0]['set'])}.")
print(f"- Los ejemplos se ven así: {dataset['train'][0]}")

Resultado:

- El conjunto de datos embedding-data/QQP_triplets tiene 101762 ejemplos.
- Cada ejemplo es de tipo <class 'dict'> con un valor de tipo <class 'dict'>.
- Los ejemplos se ven así: {'set': {'query': '¿Por qué en India no tenemos debates políticos uno a uno como en Estados Unidos?', 'pos': ['¿Por qué no podemos tener un debate público entre políticos en India como el que hay en Estados Unidos?'], 'neg': ['¿Pueden las personas en Quora dejar de debatir sobre India y Pakistán? Estamos hartos de ver esto todos los días en grandes cantidades?'...]

Puedes ver que query (el ancla) tiene una sola oración, pos (positivo) es una lista de oraciones (la que imprimimos tiene solo una oración), y neg (negativo) es una lista de múltiples oraciones.

Convierte los ejemplos en objetos InputExample. Para simplificar, (1) solo se usará uno de los positivos y uno de los negativos en el conjunto de datos embedding-data/QQP_triplets. (2) Solo se utilizará la mitad de los ejemplos disponibles. Puedes obtener resultados mucho mejores aumentando la cantidad de ejemplos.

from sentence_transformers import InputExample

train_examples = []
train_data = dataset['train']['set']
# Para agilidad, solo usaremos la mitad de nuestros datos disponibles
n_examples = dataset['train'].num_rows // 2

for i in range(n_examples):
  example = train_data[i]
  train_examples.append(InputExample(texts=[example['query'], example['pos'][0], example['neg'][0]]))

Convierte los ejemplos de entrenamiento en un Dataloader.

from torch.utils.data import DataLoader

train_dataloader = DataLoader(train_examples, shuffle=True, batch_size=16)

El siguiente paso es elegir una función de pérdida adecuada que pueda ser utilizada con el formato de datos.

Funciones de pérdida para entrenar un modelo de Sentence Transformers

¿Recuerdas los cuatro formatos diferentes en los que pueden estar tus datos? Cada uno tendrá una función de pérdida asociada.

Caso 1: Par de oraciones y una etiqueta que indica cuán similares son. La función de pérdida optimiza para que (1) las oraciones con las etiquetas más cercanas estén cerca en el espacio vectorial, y (2) las oraciones con las etiquetas más lejanas estén lo más separadas posible. La función de pérdida depende del formato de la etiqueta. Si es un número entero, utiliza ContrastiveLoss o SoftmaxLoss; si es un decimal, puedes usar CosineSimilarityLoss.

Caso 2: Si solo tienes dos oraciones similares (dos positivos) sin etiquetas, entonces puedes usar la función MultipleNegativesRankingLoss. También se puede utilizar la función MegaBatchMarginLoss, la cual convertiría tus ejemplos en tripletes (ancla_i, positivo_i, positivo_j) donde positivo_j actúa como el negativo.

Caso 3: Cuando tus muestras son tripletes de la forma [ancla, positivo, negativo] y tienes una etiqueta entera para cada una, una función de pérdida optimiza el modelo para que las oraciones ancla y positivas estén más cerca en el espacio vectorial que las oraciones ancla y negativas. Puedes usar BatchHardTripletLoss, que requiere que los datos tengan etiquetas enteras (por ejemplo, etiquetas 1, 2, 3) asumiendo que las muestras con la misma etiqueta son similares. Por lo tanto, las anclas y los positivos deben tener la misma etiqueta, mientras que los negativos deben tener una etiqueta diferente. Alternativamente, puedes usar BatchAllTripletLoss, BatchHardSoftMarginTripletLoss o BatchSemiHardTripletLoss. Las diferencias entre ellas están más allá del alcance de este tutorial, pero se pueden revisar en la documentación de Sentence Transformers.

Caso 4: Si no tienes una etiqueta para cada oración en los tripletes, debes usar TripletLoss. Esta pérdida minimiza la distancia entre el ancla y las oraciones positivas mientras maximiza la distancia entre el ancla y las oraciones negativas.

Esta figura resume los diferentes tipos de formatos de conjuntos de datos, ejemplos de conjuntos de datos en el Hub y sus funciones de pérdida adecuadas.

La parte más difícil es elegir una función de pérdida adecuada conceptualmente. En el código, solo hay dos líneas:

from sentence_transformers import losses

train_loss = losses.TripletLoss(model=model)

Una vez que el conjunto de datos esté en el formato deseado y haya una función de pérdida adecuada en su lugar, ajustar y entrenar un modelo de Sentence Transformers es sencillo.

Cómo entrenar o ajustar un modelo de Sentence Transformer

“SentenceTransformers fue diseñado para que sea fácil ajustar tus propios modelos de incrustación de oraciones/texto. Proporciona la mayoría de los bloques de construcción que puedes combinar para ajustar las incrustaciones para tu tarea específica”. – Documentación de Sentence Transformers.

Esto es cómo se ve el entrenamiento o ajuste:

model.fit(train_objectives=[(train_dataloader, train_loss)], epochs=10) 

Recuerda que si estás ajustando un modelo de Sentence Transformers existente (ver Notebook Compañero), puedes llamar directamente al método fit desde él. Si se trata de un nuevo modelo de Sentence Transformers, primero debes definirlo como lo hiciste en la sección “Cómo funcionan los modelos de Sentence Transformers”.

¡Eso es todo! ¡Tienes un modelo de Sentence Transformers nuevo o mejorado! ¿Quieres compartirlo en el Hugging Face Hub?

Primero, inicia sesión en el Hugging Face Hub. Necesitarás crear un token de write en tu Configuración de cuenta. Luego tienes dos opciones para iniciar sesión:

  1. Escribe huggingface-cli login en tu terminal e ingresa tu token.

  2. Si estás en un cuaderno de Python, puedes usar notebook_login.

from huggingface_hub import notebook_login

notebook_login()

Luego, puedes compartir tus modelos llamando al método save_to_hub desde el modelo entrenado. Por defecto, el modelo se cargará en tu cuenta, pero puedes cargarlo en una organización pasándola como parámetro en organization. save_to_hub genera automáticamente una tarjeta de modelo, un widget de inferencia, fragmentos de código de ejemplo y más detalles. Puedes agregar automáticamente a la tarjeta de modelo del Hub una lista de conjuntos de datos que utilizaste para entrenar el modelo con el argumento train_datasets:

model.save_to_hub(
    "distilroberta-base-sentence-transformer", 
    organization= # Añade tu nombre de usuario
    train_datasets=["embedding-data/QQP_triplets"],
    )

En el Notebook Compañero, ajusté este mismo modelo utilizando el conjunto de datos “embedding-data/sentence-compression” y la pérdida MultipleNegativesRankingLoss.

¿Cuáles son los límites de Sentence Transformers?

Los modelos de Sentence Transformers funcionan mucho mejor que los modelos Transformers simples para la búsqueda semántica. Sin embargo, ¿en qué casos los modelos de Sentence Transformers no funcionan bien? Si tu tarea es la clasificación, entonces usar incrustaciones de oraciones es un enfoque equivocado. En ese caso, la biblioteca 🤗 Transformers sería una mejor elección.

Recursos adicionales

  • Empezando con las incrustaciones.
  • Entendiendo la búsqueda semántica.
  • Comienza tu primer modelo de Sentence Transformers.
  • Genera listas de reproducción usando Sentence Transformers.
  • Documentación de Hugging Face + Sentence Transformers.

¡Gracias por leer! ¡Feliz creación de incrustaciones!

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

Congelación de capas de un modelo de aprendizaje profundo - la forma correcta

A menudo es útil congelar algunos de los parámetros, por ejemplo, cuando estás ajustando tu modelo y quieres congelar...

Inteligencia Artificial

El salto de KPMG hacia el futuro de la IA generativa

En un giro notable de los acontecimientos, el mundo de la consultoría y las finanzas está experimentando un viaje tra...

Inteligencia Artificial

Las ratas utilizan la imaginación para navegar en realidad virtual

Investigadores del Instituto Howard Hughes Medical Institute probaron si las ratas, al igual que los humanos, pueden ...

Inteligencia Artificial

De harapos a riquezas

A medida que los modelos de lenguaje grandes (LLMs por sus siglas en inglés) se han apoderado del mundo, los motores ...