Cuando se trata del procesamiento del lenguaje natural (PNL) y la recuperación de la información, la capacidad de recuperar la información relevante de manera eficiente y precisa es primordial. A medida que el campo continúa evolucionando, se están desarrollando nuevas técnicas y metodologías para mejorar el rendimiento de los sistemas de recuperación, particularmente en el contexto de la generación aumentada de recuperación (RAG). Una de esas técnicas, conocida como recuperación de dos etapas con los reanicadores, se ha convertido en una solución poderosa para abordar las limitaciones inherentes de los métodos de recuperación tradicionales.
En este artículo, discutimos las complejidades de la recuperación de dos etapas y los reanicadores, explorando sus principios subyacentes, estrategias de implementación y los beneficios que ofrecen para mejorar la precisión y eficiencia de los sistemas RAG. También proporcionaremos ejemplos prácticos y fragmentos de código para ilustrar los conceptos y facilitar una comprensión más profunda de esta técnica de vanguardia.
Comprensión de la generación aumentada de recuperación (trapo)
Antes de sumergirnos en los detalles de la recuperación de dos etapas y los vuelos a los vuelos, revisemos brevemente el concepto de generación aumentada de recuperación (RAG). RAG es una técnica que extiende el conocimiento y las capacidades de los modelos de idiomas grandes (LLM) al proporcionarles acceso a fuentes de información externas, como bases de datos o colecciones de documentos. Consulte más del artículo «Una inmersión profunda en la generación aumentada de recuperación en LLM».
El proceso de trapo típico implica los siguientes pasos:
- Consulta: Un usuario plantea una pregunta o proporciona una instrucción al sistema.
- Recuperación: El sistema consulta una base de datos vectorial o una recopilación de documentos para encontrar información relevante para la consulta del usuario.
- Aumento: La información recuperada se combina con la consulta o instrucción original del usuario.
- Generación: El modelo de lenguaje procesa la entrada aumentada y genera una respuesta, aprovechando la información externa para mejorar la precisión y la integridad de su salida.
Si bien Rag ha demostrado ser una técnica poderosa, no está exenta de desafíos. Uno de los temas clave radica en la etapa de recuperación, donde los métodos de recuperación tradicionales pueden no identificar los documentos más relevantes, lo que lleva a respuestas subóptimas o inexactas del modelo de idioma.
La necesidad de recuperación de dos etapas y vueltas
Los métodos de recuperación tradicionales, como los basados en modelos de coincidencia de palabras clave o espacios vectoriales, a menudo luchan por capturar las relaciones semánticas matizadas entre consultas y documentos. Esta limitación puede dar lugar a la recuperación de documentos que solo son de forma superficial o se pierden información crucial que podría mejorar significativamente la calidad de la respuesta generada.
Para abordar este desafío, los investigadores y los profesionales han recurrido a la recuperación de dos etapas con Rerankers. Este enfoque implica un proceso de dos pasos:
- Recuperación inicial: En la primera etapa, se recupera un conjunto relativamente grande de documentos potencialmente relevantes utilizando un método de recuperación rápido y eficiente, como un modelo de espacio vectorial o una búsqueda basada en palabras clave.
- Reestructuración: En la segunda etapa, se emplea un modelo de reordenamiento más sofisticado para reordenar los documentos inicialmente recuperados en función de su relevancia para la consulta, llevando efectivamente los documentos más relevantes a la parte superior de la lista.
El modelo Reranking, a menudo una red neuronal o una arquitectura basada en transformadores, está específicamente capacitado para evaluar la relevancia de un documento para una consulta dada. Al aprovechar las capacidades avanzadas de comprensión del lenguaje natural, el Reranker puede capturar los matices semánticos y las relaciones contextuales entre la consulta y los documentos, lo que resulta en una clasificación más precisa y relevante.
Beneficios de la recuperación de dos etapas y los vueltas
La adopción de la recuperación de dos etapas con Rerankers ofrece varios beneficios significativos en el contexto de los sistemas RAG:
- Precisión mejorada: Al volver a ser los documentos inicialmente recuperados y promover los más relevantes en la parte superior, el sistema puede proporcionar información más precisa y precisa al modelo de lenguaje, lo que lleva a respuestas generadas de mayor calidad.
- Problemas fuera de dominio mitigados: La incrustación de los modelos utilizados para la recuperación tradicional a menudo se capacitan en corpus de texto de uso general, que pueden no capturar adecuadamente el lenguaje y la semántica específicos de dominio. Los modelos de remodelación, por otro lado, pueden ser entrenados en datos específicos del dominio, mitigando el problema del «fuera del dominio» y mejorando la relevancia de los documentos recuperados dentro de dominios especializados.
- Escalabilidad: El enfoque de dos etapas permite una escala eficiente al aprovechar los métodos de recuperación rápidos y livianos en la etapa inicial, al tiempo que reserva el proceso de rehabilitación más intensivo computacionalmente para un subconjunto más pequeño de documentos.
- Flexibilidad: Los modelos de rehabilitación se pueden intercambiar o actualizar independientemente del método de recuperación inicial, proporcionando flexibilidad y adaptabilidad a las necesidades en evolución del sistema.
Colbert: interacción tardía eficiente y efectiva
Uno de los modelos más destacados en el ámbito de la reranking es Colbert (interacción tardía contextualizada sobre Bert). Colbert es un modelo de Reranker de documentos que aprovecha las capacidades de comprensión del lenguaje profundo de Bert al tiempo que introduce un nuevo mecanismo de interacción conocido como «interacción tardía».
Colbert: búsqueda eficiente y efectiva de pasaje a través de la interacción tardía contextualizada sobre Bert
El mecanismo de interacción tardía en Colbert permite una recuperación eficiente y precisa mediante el procesamiento de consultas y documentos por separado hasta las etapas finales del proceso de recuperación. Específicamente, Colbert codifica independientemente la consulta y el documento usando Bert, y luego emplea un paso de interacción liviano pero poderoso que modela su similitud de grano fino. Al retrasar pero retener esta interacción de grano fino, Colbert puede aprovechar la expresividad de los modelos de lenguaje profundo y al mismo tiempo obtener la capacidad de precomputar representaciones de documentos fuera de línea, acelerando considerablemente el procesamiento de consultas.
La arquitectura de interacción tardía de Colbert ofrece varios beneficios, incluida la eficiencia computacional mejorada, la escalabilidad con el tamaño de la recopilación de documentos y la aplicabilidad práctica para los escenarios del mundo real. Además, Colbert se ha mejorado aún más con técnicas como la supervisión desolada y la compresión residual (en Colbertv2), que refinan el proceso de entrenamiento y reducen la huella espacial del modelo mientras mantienen una alta efectividad de recuperación.
Este fragmento de código demuestra cómo configurar y usar el modelo Jina-Colbert-V1-EN para indexar una colección de documentos, aprovechando su capacidad para manejar contextos largos de manera eficiente.
Implementación de la recuperación de dos etapas con Rerankers
Ahora que tenemos una comprensión de los principios detrás de la recuperación de dos etapas y los vuelvos, exploremos su implementación práctica en el contexto de un sistema de trapo. Aprovecharemos bibliotecas y marcos populares para demostrar la integración de estas técnicas.
Configuración del medio ambiente
Antes de sumergirnos en el código, establezcamos nuestro entorno de desarrollo. Usaremos Python y varias bibliotecas populares de la PNL, incluidos abrazos de los transformadores faciales, transformadores de oraciones y LancedB.
# Install required libraries
!pip install datasets huggingface_hub sentence_transformers lancedb
Preparación de datos
Para fines de demostración, utilizaremos el conjunto de datos «A-Ai-ARXIV» de los conjuntos de datos de abrazos de abrazo, que contiene más de 400 documentos ARXIV en aprendizaje automático, procesamiento de lenguaje natural y modelos de idiomas grandes.
from datasets import load_dataset
dataset = load_dataset("jamescalam/ai-arxiv-chunked", split="train")
Next, we'll preprocess the data and split it into smaller chunks to facilitate efficient retrieval and processing.
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
def chunk_text(text, chunk_size=512, overlap=64):
tokens = tokenizer.encode(text, return_tensors="pt", truncation=True)
chunks = tokens.split(chunk_size - overlap)
texts = (tokenizer.decode(chunk) for chunk in chunks)
return texts
chunked_data = ()
for doc in dataset:
text = doc("chunk")
chunked_texts = chunk_text(text)
chunked_data.extend(chunked_texts)
For the initial retrieval stage, we'll use a Sentence Transformer model to encode our documents and queries into dense vector representations, and then perform approximate nearest neighbor search using a vector database like LanceDB.
from sentence_transformers import SentenceTransformer
from lancedb import lancedb
# Load Sentence Transformer model
model = SentenceTransformer('all-MiniLM-L6-v2')
# Create LanceDB vector store
db = lancedb.lancedb('/path/to/store')
db.create_collection('docs', vector_dimension=model.get_sentence_embedding_dimension())
# Index documents
for text in chunked_data:
vector = model.encode(text).tolist()
db.insert_document('docs', vector, text)
from sentence_transformers import SentenceTransformer
from lancedb import lancedb
# Load Sentence Transformer model
model = SentenceTransformer('all-MiniLM-L6-v2')
# Create LanceDB vector store
db = lancedb.lancedb('/path/to/store')
db.create_collection('docs', vector_dimension=model.get_sentence_embedding_dimension())
# Index documents
for text in chunked_data:
vector = model.encode(text).tolist()
db.insert_document('docs', vector, text)
Con nuestros documentos indexados, podemos realizar la recuperación inicial al encontrar a los vecinos más cercanos a un vector de consulta determinado.
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
def chunk_text(text, chunk_size=512, overlap=64):
tokens = tokenizer.encode(text, return_tensors="pt", truncation=True)
chunks = tokens.split(chunk_size - overlap)
texts = (tokenizer.decode(chunk) for chunk in chunks)
return texts
chunked_data = ()
for doc in dataset:
text = doc("chunk")
chunked_texts = chunk_text(text)
chunked_data.extend(chunked_texts)
Reestructuración
Después de la recuperación inicial, emplearemos un modelo de reordenamiento para reordenar los documentos recuperados en función de su relevancia para la consulta. En este ejemplo, utilizaremos el Colbert Reranker, un modelo basado en transformadores rápido y preciso diseñado específicamente para la clasificación de documentos.
from lancedb.rerankers import ColbertReranker
reranker = ColbertReranker()
# Rerank initial documents
reranked_docs = reranker.rerank(query, initial_docs)
El reranked_docs La lista ahora contiene los documentos reordenados en función de su relevancia para la consulta, según lo determinado por el Colbert Reranker.
Aumento y generación
Con los documentos relevantes y relevantes en la mano, podemos proceder a las etapas de aumento y generación de la tubería RAG. Usaremos un modelo de lenguaje de la biblioteca de transformadores faciales para generar la respuesta final.
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
tokenizer = AutoTokenizer.from_pretrained("t5-base")
model = AutoModelForSeq2SeqLM.from_pretrained("t5-base")
# Augment query with reranked documents
augmented_query = query + " " + " ".join(reranked_docs(:3))
# Generate response from language model
input_ids = tokenizer.encode(augmented_query, return_tensors="pt")
output_ids = model.generate(input_ids, max_length=500)
response = tokenizer.decode(output_ids(0), skip_special_tokens=True)
print(response)