Consulta tus DataFrames con potentes modelos de lenguaje grandes utilizando LangChain.

Consulta tus DataFrames con modelos de lenguaje grandes en LangChain.

¡Prepárate para usar tus propios datos con los Modelos de Lenguaje de Hugging Face utilizando una Base de Datos Vectorial y LangChain!

Imagen del autor, generada con Dall-e 2

En el artículo anterior, expliqué cómo utilizar una base de datos vectorial como ChromaDB para almacenar información y utilizarla en la creación de una consulta potenciada para los Modelos de Lenguaje de Hugging Face.

En este artículo, veremos cómo utilizar LangChain para la misma tarea. LangChain se encargará de buscar a través de nuestra información almacenada en ChromaDB y pasarla directamente al modelo de lenguaje que se esté utilizando.

De esta manera, podemos utilizar nuestros datos con los Modelos de Lenguaje de Hugging Face sin necesidad de realizar un ajuste fino del modelo.

Dado que estaremos utilizando modelos de Hugging Face, que se pueden descargar y alojar en nuestros propios servidores o espacios de nube privados, la información no tiene que pasar por empresas como OpenAI.

Veamos los pasos que seguiremos en este artículo:

  1. Instalar las bibliotecas necesarias, como ChromaDB o LangChain
  2. Cargar el conjunto de datos y crear un documento en LangChain utilizando uno de sus cargadores de documentos.
  3. Generar representaciones para almacenar en la base de datos.
  4. Crear un índice con la información.
  5. Configurar un recuperador con el índice, que LangChain utilizará para obtener la información.
  6. Cargar el modelo de Hugging Face.
  7. Crear un pipeline de LangChain utilizando el modelo de lenguaje y el recuperador.
  8. Utilizar el pipeline para hacer preguntas.

¿Qué tecnologías estamos utilizando?

La base de datos vectorial que utilizaremos es ChromaDB. Es posiblemente la opción más conocida entre las bases de datos vectoriales de código abierto.

Para los modelos, hemos elegido dos en la biblioteca de Hugging Face. El primero es dolly-v2-3b y el otro flan-t5-large. Cabe destacar que no solo son dos modelos diferentes, sino que también están entrenados para diferentes funciones.

T5 es una familia de modelos de generación de texto a texto, diseñados para generar texto basado en los conjuntos de datos en los que fueron entrenados. Se pueden utilizar para la generación de texto, pero sus respuestas pueden no ser muy creativas.

Por otro lado, Dolly es una familia de modelos de generación de texto puro. Estos modelos tienden a producir respuestas más creativas y extensas.

La biblioteca estrella es LangChain, una plataforma de código abierto que permite la creación de aplicaciones de lenguaje natural aprovechando el poder de los grandes modelos de lenguaje. Nos permite encadenar entradas y salidas entre estos modelos y otras bibliotecas o productos, como bases de datos o varios complementos.

Comencemos el proyecto con LangChain.

El código está disponible en un cuaderno en Kaggle. Este artículo y cuaderno forman parte de un curso sobre la creación de aplicaciones con grandes modelos de lenguaje, que está disponible en mi perfil de GitHub.

Si no quieres perderte ninguna lección o actualización del contenido existente, es mejor que sigas el repositorio. Publicaré nuevas lecciones en el repositorio público a medida que las complete.

Pregunta a tus documentos con LangChain, VectorDB y HF

Explora y ejecuta código de aprendizaje automático con Kaggle Notebooks | Utilizando datos de múltiples fuentes de datos

www.kaggle.com

GitHub – peremartra/Large-Language-Model-Notebooks-Course

Contribuye al desarrollo de peremartra/Large-Language-Model-Notebooks-Course creando una cuenta en GitHub.

github.com

Instalación y carga de las bibliotecas.

Si está trabajando en su entorno personal y ya ha estado probando estas tecnologías, es posible que no necesite instalar nada. Sin embargo, si está utilizando Kaggle o Colab, deberá instalar las siguientes bibliotecas:

  • langchain: La revolucionaria biblioteca que permite la creación de aplicaciones con modelos de lenguaje grandes.
  • sentence_transformers: Tendremos que generar embeddings del texto que queremos almacenar en la base de datos vectorial, para lo cual necesitamos esta biblioteca.
  • chromadb: La base de datos vectorial a utilizar. Destaca especialmente ChromaDB por su interfaz fácil de usar.
!pip install chromadb!pip install langchain!pip install sentence_transformers

Además de estas bibliotecas, también importaremos las dos bibliotecas de Python más utilizadas en ciencia de datos: pandas y numpy.

import numpy as np import pandas as pd

Cargar los conjuntos de datos.

Como mencioné anteriormente, el cuaderno ha sido preparado para trabajar con dos conjuntos de datos diferentes. Estos conjuntos de datos son los mismos que se utilizaron en el ejemplo anterior de RAG (Generación con Recuperación Aumentada).

RAG significa utilizar sus datos con modelos de lenguaje grandes, comúnmente conocido como “Interrogando sus documentos”.

Ambos conjuntos de datos son tabulares y contienen información relacionada con noticias:

  1. Conjunto de datos de noticias con etiquetas de temas.
  2. Noticias de IA del MIT publicadas hasta 2023.

El contenido de ambos conjuntos de datos es similar, pero los nombres de las columnas y la información almacenada difieren. Personalmente, creo que utilizar múltiples conjuntos de datos puede proporcionar un buen valor, permitiéndole validar y generalizar los resultados con diferentes fuentes de datos.

Sería beneficioso explorar un tercer conjunto de datos diferente y replicar la funcionalidad con él al completar el cuaderno.

Dado que estamos trabajando con recursos limitados en Kaggle, es esencial ser consciente de las limitaciones de memoria. Por lo tanto, no trabajaremos con el conjunto de datos completo para evitar exceder el límite de memoria de Kaggle, que es de 30 GB si no utiliza GPUs.

Trabajar con un subconjunto más pequeño del conjunto de datos nos permitirá explorar y demostrar la funcionalidad de LangChain de manera efectiva, al mismo tiempo que nos mantenemos dentro de las limitaciones de recursos.

Echemos un vistazo a los dos primeros registros del conjunto de datos de noticias con etiquetas de temas.

En el primer conjunto de datos, utilizaremos la columna title como nuestro documento. Aunque los textos pueden no ser muy extensos, nos sirve como un ejemplo perfecto. Podemos usarlo para buscar en la base de datos de artículos y encontrar aquellos que traten sobre un tema específico.

news = pd.read_csv('/kaggle/input/topic-labeled-news-dataset/labelled_newscatcher_dataset.csv', sep=';')MAX_NEWS = 1000DOCUMENT="title"TOPIC="topic"#news = pd.read_csv('/kaggle/input/bbc-news/bbc_news.csv')#MAX_NEWS = 500#DOCUMENT="description"#TOPIC="title"#Como es solo un curso, seleccionamos una pequeña porción de Noticias.subset_news = news.head(MAX_NEWS)

Hemos creado el DataFrame subset_news que contiene una porción de las noticias del conjunto de datos.

Para utilizar uno u otro conjunto de datos, es tan simple como descomentar las líneas correspondientes al conjunto de datos que queremos utilizar. En cada caso, ajustamos el nombre de la columna que se utilizará como datos y el número de registros que contendrá el subconjunto. Este enfoque nos permite cambiar fácilmente entre conjuntos de datos.

Generar el documento a partir del DataFrame.

Para crear el documento, utilizaremos LangChain, utilizando uno de sus cargadores. Para nuestro ejemplo, utilizaremos el DataFrameLoader, pero hay varios cargadores disponibles para una amplia gama de fuentes, como CSVs, archivos de texto, HTML, JSON, PDF e incluso cargadores para productos como Confluence.

from langchain.document_loaders import DataFrameLoaderfrom langchain.vectorstores import Chroma

Una vez que tenemos la biblioteca cargada, necesitamos crear el cargador. Para hacer esto, especificamos el DataFrame y el nombre de la columna que queremos usar como contenido del documento. Esta información se pasará a la base de datos vectorial, ChromaDB, donde se almacenará y será utilizada por el modelo de lenguaje al generar sus respuestas.

df_loader = DataFrameLoader(subset_news, page_content_column=DOCUMENT)

Para crear el documento, simplemente necesitamos llamar a la función load del cargador.

df_document = df_loader.load()display(df_document)

Echemos un vistazo al contenido del documento:

[Document(page_content="A closer look at water-splitting's solar fuel potential", metadata={'topic': 'SCIENCE', 'link': 'https://www.eurekalert.org/pub_releases/2020-08/dbnl-acl080620.php', 'domain': 'eurekalert.org', 'published_date': '2020-08-06 13:59:45', 'lang': 'en'}), Document(page_content='An irresistible scent makes locusts swarm, study finds', metadata={'topic': 'SCIENCE', 'link': 'https://www.pulse.ng/news/world/an-irresistible-scent-makes-locusts-swarm-study-finds/jy784jw', 'domain': 'pulse.ng', 'published_date': '2020-08-12 15:14:19', 'lang': 'en'}),

Como podemos ver, se ha creado un documento donde cada página corresponde al contenido de un registro de la columna especificada. Además, encontramos los otros datos en el campo ‘metadata’, etiquetados con el nombre de la columna.

Te animo a probar con otro conjunto de datos y ver cómo se ve la información.

Creando los embeddings.

Primero, en caso de ser necesario, entendamos qué es un Embedding. Es simplemente una representación numérica de cualquier dato. En nuestro caso específico, será la representación numérica del texto que se va a almacenar.

Esta representación numérica toma la forma de vectores. Un vector es simplemente una representación de un punto en un espacio multidimensional. En otras palabras, no tenemos que visualizar el punto en un plano bidimensional o tridimensional, como estamos acostumbrados. El vector puede representar el punto en cualquier número de dimensiones.

Para nosotros, puede parecer complicado o difícil de imaginar, pero matemáticamente, no hay mucha diferencia entre calcular la distancia entre dos puntos, ya sea que estén en dos dimensiones, tres o cualquier número de dimensiones.

Estos vectores nos permiten calcular las diferencias o similitudes entre ellos, lo que hace posible buscar información similar de manera muy eficiente.

El truco radica en determinar qué vectores asignamos a cada palabra, ya que queremos que las palabras con significados similares estén más cerca en distancia que aquellas con significados más diferentes. Las bibliotecas de Hugging Face se encargan de este aspecto, por lo que no tenemos que preocuparnos demasiado. Solo necesitamos asegurarnos de una conversión consistente para todos los datos que se van a almacenar y las consultas que se van a realizar.

Importemos un par de bibliotecas:

  1. CharacterTextSplitter: Usaremos esta biblioteca para agrupar la información en bloques.
  2. HuggingFaceEmbeddings o SentenceTransformerEmbedding: En el notebook, he utilizado ambos y no he encontrado ninguna diferencia entre ellos. Estas bibliotecas se encargan de recuperar el modelo que ejecutará el embedding de los datos.
from langchain.text_splitter import <a></a><a>CharacterTextSplitter#from langchain.embeddings import HuggingFaceEmbeddings

No hay una manera 100% correcta de dividir los documentos en bloques. La consideración clave es que bloques más grandes proporcionarán al modelo más contexto. Sin embargo, el uso de bloques más grandes también aumentará el tamaño de nuestro Vector Store, lo que puede requerir más memoria.

Es esencial encontrar un equilibrio entre el tamaño del contexto y el uso de memoria para optimizar el rendimiento de nuestra aplicación.

He decidido utilizar un tamaño de bloque de 250 caracteres con un solapamiento de 10. Esto significa que los últimos 10 caracteres de un bloque serán los primeros 10 caracteres del siguiente bloque. Es un tamaño de bloque relativamente pequeño, pero es más que suficiente para el tipo de información con la que estamos trabajando.

text_splitter = CharacterTextSplitter(chunk_size=250, chunk_overlap=10)texts = text_splitter.split_documents(df_document)

Ahora podemos crear embeddings con el texto.

from langchain.embeddings.sentence_transformer import SentenceTransformerEmbeddings
embedding_function = SentenceTransformerEmbeddings(model_name="all-MiniLM-L6-v2")
#embedding_function = HuggingFaceEmbeddings(
#    model_name="sentence-transformers/all-MiniLM-L6-v2"
#)  

Como puedes ver, usé SentenceTransformerEmbeddings en lugar de HuggingFaceEmbeddings. Puedes cambiarlo fácilmente modificando la línea comentada.

Con ambas bibliotecas, puedes llamar al mismo modelo pre-entrenado para generar embeddings. Estoy usando all-MiniLM-L6-v2 para ambos. Por lo tanto, aunque puede haber pequeñas diferencias entre los embeddings generados por cada biblioteca, serán mínimas y no afectarán significativamente el rendimiento.

Inicialmente, SentenceTransformerEmbeddings se especializa en transformar oraciones, mientras que HuggingFaceEmbeddings es más general y capaz de generar embeddings para párrafos o documentos completos.

De hecho, dada la naturaleza de nuestros documentos, se espera que no haya diferencia al usar cualquiera de las bibliotecas.

Con los embeddings generados, podemos crear el índice

chromadb_index = Chroma.from_documents(
    texts, embedding_function, persist_directory='./input')

¡Este índice es lo que usaremos para hacer preguntas y está especialmente diseñado para ser altamente eficiente! Después de todo este esfuerzo, lo último que queremos es que sea lento e impreciso :-).

¡Comencemos a usar LangChain!

Ahora viene la parte divertida: ¡encadenar las acciones con LangChain para crear nuestra primera pequeña aplicación utilizando un gran modelo de lenguaje!

La aplicación es muy simple, consta de solo dos pasos y dos componentes. El primer paso implicará un retriever. Este componente se utiliza para recuperar información de documentos o del texto que proporcionamos como documento. En nuestro caso, realizará una búsqueda basada en similitud utilizando embeddings para recuperar información relevante para la consulta del usuario a partir de lo que hemos almacenado en ChromaDB.

El segundo y último paso implicará nuestro modelo de lenguaje, que recibirá la información devuelta por el retriever.

Por lo tanto, necesitamos importar las bibliotecas para crear el retriever y el pipeline.

from langchain.chains import RetrievalQA
from langchain.llms import HuggingFacePipeline

Ahora podemos crear el retriever, utilizando el índice de embeddings que creamos anteriormente.

retriever = chromadb_index.as_retriever()

Hemos completado el primer paso de nuestra cadena, o pipeline. Ahora pasemos al segundo: el modelo de lenguaje.

En el cuaderno, he utilizado dos modelos diferentes disponibles en Hugging Face.

El primer modelo es dolly-v2-3b, el más pequeño de la familia Dolly. Personalmente, me gusta mucho este modelo. Si bien puede que no sea tan popular como otros, las respuestas que genera son significativamente mejores que las de GPT-2, alcanzando un nivel similar a lo que podríamos lograr con GPT-3.5 de OpenAI. Con 3 mil millones de parámetros, se acerca al límite de memoria que podemos cargar en Kaggle. Este modelo está entrenado para la generación de texto, lo que da como resultado respuestas bien elaboradas.

El segundo modelo es de la familia T5. Presta atención porque este modelo está específicamente diseñado para la generación de texto a partir de texto, lo que da como resultado respuestas mucho más concisas y breves.

Asegúrate de probar ambos modelos al menos para ver cómo se desempeñan.

model_id = "databricks/dolly-v2-3b" #mi modelo favorito de generación de texto para pruebastask="text-generation"#model_id = "google/flan-t5-large" #Buen modelo de texto a texto#task="text2text-generation"

¡Perfecto! ¡Tenemos todo lo que necesitamos para crear el pipeline! ¡Ahora hagámoslo!

hf_llm = HuggingFacePipeline.from_model_id(
    model_id=model_id,
    task=task,
    model_kwargs={
        "temperature": 0,
        "max_length": 256
    },
)

Veamos qué significa cada uno de los parámetros:

  1. model_id: El identificador del modelo en Hugging Face. Puedes obtenerlo de Hugging Face, y generalmente consiste en el nombre del modelo seguido de la versión.
  2. task: Aquí especificamos la tarea para la cual queremos usar el modelo. Algunos modelos están entrenados para múltiples tareas. Puedes encontrar las tareas admitidas para un modelo específico en la documentación de Hugging Face del modelo.
  3. model_kwargs: Este parámetro nos permite especificar argumentos adicionales específicos del modelo. En este caso, estoy proporcionando la temperatura (qué tan creativo queremos que sea el modelo) y la longitud máxima de la respuesta.

Ahora, es hora de configurar la canalización utilizando el modelo y el recuperador.

document_qa = RetrievalQA.from_chain_type(    llm=hf_llm, chain_type="stuff", retriever=retriever)

En la variable chain_type, indicamos cómo debería funcionar la cadena, y tenemos cuatro opciones:

  1. stuff: La opción más simple, simplemente toma los documentos que considera apropiados y los utiliza en la indicación para pasar al modelo.
  2. refine: Realiza múltiples llamadas al modelo con diferentes documentos, intentando obtener una respuesta más refinada cada vez. Puede ejecutar un alto número de llamadas al modelo, por lo que debe usarse con precaución.
  3. map reduce: Intenta reducir todos los documentos en uno, posiblemente a través de varias iteraciones. Puede comprimir y colapsar los documentos para que quepan en la indicación enviada al modelo.
  4. map re-rank: Llama al modelo para cada documento y los clasifica, finalmente devuelve el mejor. Similar a `refine`, puede ser arriesgado dependiendo del número de llamadas esperadas.

Ahora podemos usar la cadena recién creada para hacer nuestras preguntas, y serán respondidas considerando los datos de nuestro DataFrame, que ahora forma parte de la Base de Datos de Vectores.

#Pregunta de muestra para el conjunto de datos newscatcher. response = document_qa.run("¿Puedo comprar una computadora portátil Toshiba?")#Pregunta de muestra para el conjunto de datos BBC. #response = document_qa.run("¿Quién va a reunirse con boris johnson?")display(response)

Entonces, la respuesta obtenida dependerá, como es evidente, del conjunto de datos utilizado y también del modelo. Para la pregunta de si podemos comprar una computadora portátil Toshiba, obtenemos dos respuestas muy diferentes según el modelo:

Dolly: “No, Toshiba cierra oficialmente sus computadoras portátiles en 2023. El legendario Toshiba ha dejado oficialmente de fabricar computadoras portátiles. Toshiba cierra oficialmente sus computadoras portátiles en 2023.”

T5: “No.”

¡Como puedes ver, cada modelo agrega su propia personalidad a la respuesta!

Conclusiones y Aprendizaje Continuo!

En realidad, ha sido mucho más simple de lo que uno podría pensar. Es mucho más fácil ahora que antes de la explosión de los grandes modelos de lenguaje y la aparición de herramientas como LangChain.

Hemos utilizado una Base de Datos de Vectores para almacenar los datos que previamente cargamos en un DataFrame. Aunque podríamos haber utilizado cualquier otra fuente de datos.

Los utilizamos como entrada para un par de modelos de lenguaje disponibles en Hugging Face y observamos cómo los modelos proporcionaron una respuesta considerando la información del DataFrame.

Pero no te detengas aquí, realiza tus propias modificaciones en el cuaderno y resuelve cualquier problema que pueda surgir. Algunas ideas incluyen:

  • Usar ambos conjuntos de datos y, preferiblemente, buscar un tercero. Aún mejor, ¿crees que puedes adaptarlo para leer tu currículum vitae? Estoy seguro de que se puede lograr con algunos ajustes menores.
  • Intenta usar un tercer modelo de Hugging Face.
  • Cambia la fuente de datos. Podría ser un archivo de texto, un archivo de Excel o incluso una herramienta de documentos como Confluence.

El curso completo sobre los grandes modelos de lenguaje está disponible en Github. Para mantenerte actualizado sobre nuevos artículos, considera seguir el repositorio o marcarlo como favorito. De esta manera, recibirás notificaciones cada vez que se agregue nuevo contenido.

GitHub – peremartra/Large-Language-Model-Notebooks-Course

Contribuir a peremartra/Large-Language-Model-Notebooks-Course desarrollo creando una cuenta en GitHub.

github.com

Este artículo es parte de una serie en la que exploramos las aplicaciones prácticas de los grandes modelos de lenguaje. Puedes encontrar el resto de los artículos en la siguiente lista:

Pere Martra

Curso Práctico de Grandes Modelos de Lenguaje

Ver lista3 historias

Escribo regularmente sobre Deep Learning y machine learning. Considera seguirme en VoAGI para recibir actualizaciones sobre nuevos artículos. Y, por supuesto, eres bienvenido/a a conectarte conmigo en LinkedIn.

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

Tesla retira 2 millones de autos con controles de seguridad de 'autoguiado' insuficientes

Tesla está retirando más de 2 millones de vehículos para solucionar los sistemas de Autopilot que los reguladores gub...

Inteligencia Artificial

Empaqueta e implementa fácilmente modelos de ML clásicos y LLMs con Amazon SageMaker, parte 2 Experiencias interactivas para usuarios en SageMaker Studio

Amazon SageMaker es un servicio completamente administrado que permite a los desarrolladores y científicos de datos c...

Inteligencia Artificial

Los modelos Whisper para reconocimiento automático del habla ahora están disponibles en Amazon SageMaker JumpStart.

Hoy, nos complace anunciar que el modelo de base Whisper de OpenAI está disponible para los clientes que utilizan Ama...

Inteligencia Artificial

Presentamos OpenChat La plataforma gratuita y sencilla para construir chatbots personalizados en minutos.

Enseña a tus chatbots cualquier tema conectándolos a recursos como PDFs, sitios web, Notion, Confluence y Office 365.

Ciencias de la Computación

Robots de entrega de comida de Uber Eats listos para ser utilizados en múltiples ciudades de EE. UU.

La compañía de robots de servicio Serve Robotics informó que Uber Eats desplegará hasta 2,000 de sus robots de entreg...