¿Cómo construir una aplicación de búsqueda multi-modal con Chroma?

¿Cómo crear una aplicación multi-modal de búsqueda utilizando Chroma?

Introducción

¿Alguna vez te has preguntado cómo nuestros intricados cerebros procesan el mundo? Si bien el funcionamiento interno del cerebro sigue siendo un misterio, podemos compararlo con una red neural versátil. Gracias a las señales electroquímicas, maneja diferentes tipos de datos: audio, visual, olores, sabores y tacto. A medida que la inteligencia artificial avanza, surgen modelos multi-modales, revolucionando las capacidades de búsqueda. Esta innovación abre posibilidades, mejorando la precisión y relevancia de la búsqueda. Descubre el fascinante mundo de la búsqueda multi-modal.

Objetivos de aprendizaje

  • Comprender el término “Multi-modalidad en IA”.
  • Obtener conocimientos sobre el modelo de imagen-texto CLIP de OpenAI.
  • Aprender qué es una base de datos vectorial y entender el índice vectorial de manera breve.
  • Utilizar CLIP y la base de datos vectorial Chroma para construir un recomendador de alimentos con una interfaz Gradio.
  • Explorar otros casos de uso del mundo real de una búsqueda multi-modal.

Este artículo fue publicado como parte del Data Science Blogathon.

¿Qué es la Multi-modalidad en IA?

Si lo buscas en Google, encontrarás que multi-modal se refiere a involucrar múltiples modos o métodos en un proceso. En Inteligencia Artificial, los modelos multi-modales son aquellas redes neuronales que pueden procesar y entender diferentes tipos de datos. Por ejemplo, GPT-4 y Bard. Estos son modelos de lenguaje de lenguaje y visión que pueden entender texto e imágenes. Otros ejemplos podrían ser los autos Tesla con conducción automática que combinan datos visuales y sensoriales para entender el entorno, y Midjourney o Dalle, que pueden generar imágenes a partir de descripciones de texto.

Pre-entrenamiento Contrastivo de Lenguaje-Imagen (CLIP)

CLIP es una red neural multi-modal de código abierto desarrollada por OpenAI y entrenada con un gran conjunto de datos de pares imagen-texto. Esto asegura que CLIP aprenda a asociar conceptos visuales en imágenes con sus descripciones de texto. El modelo CLIP puede ser instruido en lenguaje humano para clasificar una amplia gama de datos de imágenes sin necesidad de entrenamiento específico.

La capacidad de “zero-shot” de CLIP es comparable a la de GPT 3. Por lo tanto, CLIP se puede utilizar para clasificar imágenes en cualquier conjunto de categorías sin necesidad de ser entrenado en esas categorías específicamente. Por ejemplo, para clasificar imágenes de perros vs. gatos, solo necesitamos comparar las puntuaciones logit de la imagen con la descripción de texto “una imagen de un perro” o “una imagen de un gato”; Una foto de un gato o un perro probablemente tendrá puntuaciones logit más altas con sus respectivas descripciones de texto.

Esto se conoce como clasificación “zero-shot” porque CLIP no necesita ser entrenado con un conjunto de datos de imágenes de perros y gatos para poder clasificarlos. Aquí tienes una presentación visual de cómo funciona CLIP.

CLIP utiliza un Vision Transformer (ViT) para imágenes y un modelo de texto para características de texto. Las codificaciones vectoriales luego se proyectan en un espacio vectorial compartido con dimensiones idénticas. El producto punto entre los dos se utiliza como un puntaje de similitud para predecir la similitud entre el fragmento de texto y la imagen. En otras palabras, CLIP puede clasificar imágenes en cualquier conjunto de categorías sin estar optimizado para ello. En este artículo, implementaremos CLIP de manera programática.

¿Por qué se requieren las bases de datos vectoriales?

Los algoritmos de aprendizaje automático no entienden los datos en su formato raw. Por lo tanto, para hacer que funcionen, debemos transformar los datos en su forma numérica. Los vectores o embeddings son las representaciones numéricas de diferentes tipos de datos como texto, imágenes, audio y videos. Sin embargo, las bases de datos tradicionales no son completamente capaces de consultar datos vectoriales de alta dimensionalidad. Para construir una aplicación que utilice millones de embeddings vectoriales, necesitamos una base de datos que pueda almacenar, buscar y consultarlos. Esto no es posible con bases de datos tradicionales. Para lograr esto, necesitamos bases de datos vectoriales, diseñadas específicamente para almacenar y consultar embeddings.

La siguiente imagen ilustra un flujo de trabajo simplificado de una base de datos vectorial.

Necesitamos modelos de incrustación especializados capaces de capturar el significado semántico subyacente de los datos. Los modelos son diferentes para diferentes tipos de datos. Utilice modelos de imagen como Resnet o Visual Transformers para datos de imágenes. Para textos, se utilizan modelos de texto como Ada y SentenceTransformers. Para la interacción multimodal, se utilizan modelos multimodales como Tortoise (Texto-A-Voz) y CLIP (Texto-A-Imagen). Estos modelos se utilizarán para obtener las incrustaciones de los datos de entrada. Las bases de datos de vectores suelen tener implementaciones personalizadas de modelos de incrustación, pero también podemos definir nuestros propios modelos para obtener las incrustaciones y almacenarlas en almacenes de vectores.

Indexación

Las incrustaciones suelen ser de alta dimensionalidad y las consultas a vectores de alta dimensionalidad suelen requerir mucho tiempo y capacidad de cálculo. Por lo tanto, las bases de datos de vectores emplean diversos métodos de indexación para realizar consultas eficientes. La indexación se refiere a organizar vectores de alta dimensionalidad de manera que se puedan realizar consultas eficientes de vectores vecinos más cercanos.

Algunos algoritmos de indexación populares son HNSW (Hierarchical Navigable Small World), Quantización de productos, Sistema de archivos invertido, Cuantización escalar, etc. De todos estos, HNSW es el algoritmo más popular y ampliamente utilizado en diversas bases de datos de vectores.

Para esta aplicación, utilizaremos la Base de Datos de Vectores Chroma. Chroma es una base de datos de vectores de código abierto. Le permite configurar rápidamente un cliente para almacenar y consultar vectores y metadatos asociados. Hay otros almacenes de vectores similares que puede utilizar, como Weaviate, Qdrant, Milvus, etc.

¿Qué es Gradio?

Gradio, escrito en Python, tiene como objetivo construir rápidamente una interfaz web para compartir modelos de Aprendizaje Automático como una herramienta de código abierto. Nos permite configurar una interfaz web de demostración utilizando Python. Proporciona flexibilidad para crear un prototipo decente para mostrar los modelos backend.

Para obtener más información sobre cómo construir, consulta este artículo.

Construyendo la Aplicación

Esta sección explicará los códigos para crear una aplicación simple de recomendación de platos de restaurante utilizando Gradio, Chroma y CLIP. Chroma aún no tiene soporte incorporado para modelos multimodales. Por lo tanto, esto será una solución alternativa.

Hay dos formas de utilizar CLIP en tu proyecto. Ya sea la implementación de CLIP de OpenAI o la implementación de CLIP de Huggingface. Para este proyecto, utilizaremos CLIP de OpenAI. Asegúrate de tener un entorno virtual con las siguientes dependencias instaladas.

cliptorchchromadbgradio

Esta es nuestra estructura de directorio.

├── app.py├── clip_chroma├── clip_embeddings.py├── __init__.py├── load_data.py

Incrustaciones de CLIP

Lo primero que debemos hacer es construir una clase para extraer las incrustaciones de imágenes y textos. Como sabemos, CLIP tiene dos partes para procesar textos e imágenes. Utilizaremos los modelos respectivos para codificar diferentes modalidades.

import clip  import torchfrom numpy import ndarray  from typing import List  from PIL import Image  class ClipEmbeddingsfunction:    def __init__(self, model_name: str = "ViT-B/32", device: str = "cpu"):                self.device = device  # Almacena el dispositivo especificado para la ejecución del modelo                self.model, self.preprocess = clip.load(model_name, self.device)    def __call__(self, docs: List[str]) -> List[ndarray]:        # Define un método que toma una lista de rutas de archivos de imagen (docs) como entrada        lista_de_incrustaciones = []  # Crea una lista vacía para almacenar las incrustaciones de imagen        for image_path in docs:            image = Image.open(image_path)  # Abre y carga una imagen desde la ruta proporcionada                        image = image.resize((224, 224))              # Procesa previamente la imagen y muévela al dispositivo especificado            image_input = self.preprocess(image).unsqueeze(0).to(self.device)              with torch.no_grad():                # Calcula las incrustaciones de imagen utilizando el modelo CLIP y conviértelas a matrices NumPy                embeddings = self.model.encode_image(image_input).cpu().detach().numpy()            lista_de_incrustaciones.append(list(embeddings[0]))         return lista_de_incrustaciones      def get_text_embeddings(self, text: str) -> List[ndarray]:        # Define un método que toma una cadena de texto como entrada        text_token = clip.tokenize(text)  # Tokeniza el texto de entrada        with torch.no_grad():            # Calcula las incrustaciones de texto utilizando el modelo CLIP y conviértelas a matrices NumPy            text_embeddings = self.model.encode_text(text_token).cpu().detach().numpy()        return list(text_embeddings[0])  

En el código anterior, hemos definido una clase para extraer incrustaciones de textos e imágenes. La clase toma el nombre del modelo y el dispositivo como entradas. Si tu dispositivo es compatible con Cuda, puedes habilitarlo pasándolo con el dispositivo. CLIP admite varios modelos, como

clip.available_models()['RN50', 'RN101', 'RN50x4', 'RN50x16', 'RN50x64', 'ViT-B/32', 'ViT-B/16', 'ViT-L/14', 'ViT-L/14@336px']

El nombre del modelo por defecto está configurado como “ViT-B/32”. Puedes pasar cualquier otro modelo que desees.

El método __call__ toma una lista de rutas de imágenes y devuelve una lista de matrices numpy. El método get_text_embeddings toma una entrada de tipo string y devuelve una lista de incrustaciones.

Cargar Incrustaciones

Primero, necesitamos poblar nuestra base de datos de vectores. Así que, recopilé algunas imágenes de platos para agregar a nuestra colección. Crea una lista de rutas de imágenes y una lista de descripciones sobre ellas. Las rutas de las imágenes serán nuestros documentos, mientras que almacenaremos las descripciones de las imágenes como metadatos.

Pero primero, crea una colección Chroma.

import osfrom chromadb import Client, Settingsfrom clip_embeddings import ClipEmbeddingsfunctionfrom typing import Listef = ClipEmbeddingsfunction()client = Client(settings = Settings(is_persistent=True, persist_directory="./clip_chroma"))coll = client.get_or_create_collection(name = "clip", embedding_function = ef)

Importamos la función de incrustación que definimos anteriormente y la pasamos como función de incrustación predeterminada para la colección.

Ahora, carga los datos en la base de datos.

coll.add(ids=[str(i) for i in range(len(img_list))],         documents = img_list, #rutas de imágenes         metadatas = menu_description,# descripción de los platos         )

Eso es todo. Ahora estás listo para construir la parte final.

Aplicación Gradio

Primero, crea un archivo app.py, importa las siguientes dependencias e inicializa la función de incrustación.

import gradio as grfrom chromadb import Client, Settingsfrom clip_embeddings import ClipEmbeddingsfunctionclient = Client(Settings(is_persistent=True, persist_directory="./clip_chroma"))ef = ClipEmbeddingsfunction()

Como interfaz gráfica, utilizaremos esto para crear una interfaz simple que reciba una consulta de búsqueda, ya sea un texto o una imagen, y muestre imágenes relevantes como salida.

with gr.Blocks() as demo:    with gr.Row():        with gr.Column():            query = gr.Textbox(placeholder = "Ingresa una consulta")            gr.HTML("O")            photo = gr.Image()            button = gr.UploadButton(label = "Cargar archivo", file_types=["imagen"])        with gr.Column():            gallery = gr.Gallery().style(                                     object_fit='contain',                                      height='auto',                                      preview=True                                  )

Ahora, definiremos eventos desencadenantes para la aplicación Gradio.

query.submit(        fn = retrieve_image_from_query,         inputs=[query],         outputs=        )    button.upload(        fn = show_img,         inputs=[button],        outputs = [photo]).\        then(            fn = retrieve_image_from_image,             inputs=[button],             outputs=            )

En el código anterior, tenemos eventos desencadenantes. Procesamos una consulta de texto con la función retrieve_image_from_query. Primero mostramos imágenes en el objeto photo y luego invocamos retrieve_image_from_image(), mostrando la salida en el objeto Gallery.

Ejecuta el archivo app.py con el comando gradio y visita la dirección local que se muestra en la terminal.

Ahora, definiremos las funciones reales.

def retrieve_image_from_image(image):    # Obtén una colección llamada "clip" utilizando la función de incrustación especificada (ef)    coll = client.get_collection(name="clip", embedding_function=ef)    # Extrae el nombre del archivo de imagen    image = image.name    # Consulta la colección utilizando el nombre del archivo de imagen como texto de consulta    result = coll.query(        query_texts=image,  # Usa el nombre del archivo de imagen como texto de consulta        include=["documents", "metadatas"],  # Incluye tanto documentos como metadatos en los resultados        n_results=4  # Especifica el número de resultados a recuperar    )    # Obtén los documentos y sus metadatos recuperados    docs = result['documents'][0]    descs = result["metadatas"][0]    # Crea una lista para almacenar pares de documentos y sus metadatos correspondientes    lista_de_docs = []    # Itera a través de los documentos y metadatos recuperados    for doc, desc in zip(docs, descs):        # Agrega una tupla que contiene el documento y sus metadatos a la lista        lista_de_docs.append((doc, list(desc.values())[0]))    # Devuelve la lista de pares de documento-metadatos    return lista_de_docs

También tenemos otra función para manejar consultas de texto.

def recuperar_imagen_desde_consulta(consulta: str):    # Obtener una colección llamada "clip" utilizando la función de incrustación especificada (ef)    coll = client.get_collection(name="clip", embedding_function=ef)    # Obtener incrustaciones de texto para la consulta de entrada utilizando la función de incrustación (ef)    emb = ef.get_text_embeddings(text=consulta)    # Convertir las incrustaciones de texto a valores de punto flotante    emb = [float(i) for i in emb]    # Consultar la colección utilizando las incrustaciones de texto    resultado = coll.query(        query_embeddings=emb,  # Utilizar las incrustaciones de texto como consulta        include=["documents", "metadatas"],  # Incluir tanto los documentos como los metadatos en los resultados        n_results=4  # Especificar el número de resultados a recuperar    )    # Obtener los documentos y sus metadatos recuperados    docs = resultado['documents'][0]    descs = resultado["metadatas"][0]    # Crear una lista para almacenar pares de documentos y sus metadatos correspondientes    lista_de_docs = []    # Iterar a través de los documentos y metadatos recuperados    for doc, desc in zip(docs, descs):        # Agregar una tupla que contenga el documento y sus metadatos a la lista        lista_de_docs.append((doc, list(desc.values())[0]))    # Devolver la lista de pares de documentos y metadatos    return lista_de_docs

En lugar de pasar textos directamente en el código, extraímos las incrustaciones y luego las pasamos al método de consulta de Choma.

Entonces, aquí está el código completo para app.py.

# Importar las bibliotecas necesariasimport gradio as grfrom chromadb import Client, Settingsfrom clip_embeddings import ClipEmbeddingsfunction# Inicializar un cliente de chromadb con almacenamiento persistenteclient = Client(Settings(is_persistent=True, persist_directory="./clip_chroma"))# Inicializar la función ClipEmbeddingsfunctionef = ClipEmbeddingsfunction()# Función para recuperar imágenes a partir de una consulta de textodef recuperar_imagen_desde_consulta(consulta: str):    # Obtener la colección "clip" con la función de incrustación especificada    coll = client.get_collection(name="clip", embedding_function=ef)        # Obtener las incrustaciones de texto para la consulta de entrada    emb = ef.get_text_embeddings(text=consulta)    emb = [float(i) for i in emb]        # Consultar la colección para obtener documentos similares    resultado = coll.query(        query_embeddings=emb,        include=["documents", "metadatas"],        n_results=4    )        # Extraer los documentos y sus metadatos    docs = resultado['documents'][0]    descs = resultado["metadatas"][0]    lista_de_docs = []        # Combinar documentos y descripciones en una lista    for doc, desc in zip(docs, descs):        lista_de_docs.append((doc, list(desc.values())[0]))        return lista_de_docs# Función para recuperar imágenes a partir de una imagen cargadadef recuperar_imagen_desde_imagen(imagen):    # Obtener la colección "clip" con la función de incrustación especificada    coll = client.get_collection(name="clip", embedding_function=ef)        # Obtener el nombre de archivo de la imagen cargada    imagen = imagen.name        # Consultar la colección con el nombre de archivo de la imagen    resultado = coll.query(        query_texts=imagen,        include=["documents", "metadatas"],        n_results=4    )        # Extraer los documentos y sus metadatos    docs = resultado['documents'][0]    descs = resultado["metadatas"][0]    lista_de_docs = []        # Combinar documentos y descripciones en una lista    for doc, desc in zip(docs, descs):        lista_de_docs.append((doc, list(desc.values())[0]))        return lista_de_docs# Función para mostrar una imagenef mostrar_imagen(imagen):    return image.name# Crear una interfaz utilizando Blockswith gr.Blocks() as demo:    with gr.Row():        with gr.Column():            # Entrada de texto para la consulta            consulta = gr.Textbox(placeholder="Ingrese consulta")            gr.HTML("O")            # Entrada de imagen mediante carga de archivos            foto = gr.Image()            boton = gr.UploadButton(label="Cargar archivo", file_types=["image"])        with gr.Column():            # Mostrar una galería de imágenes            galeria = gr.Gallery().style(                object_fit='contain',                height='auto',                preview=True            )    # Definir la entrada y salida para el envío de consultas    consulta.submit(        fn=recuperar_imagen_desde_consulta,        inputs=[consulta],        outputs=    )        # Definir la entrada y salida para la carga de imágenes    boton.upload(        fn=mostrar_imagen,        inputs=[boton],        outputs=[foto]).\        then(            fn=recuperar_imagen_desde_imagen,            inputs=[boton],            outputs=        )# Ejecutar la interfaz Gradio si se ejecuta el script como programa principalif __name__ == "__main__":    demo.launch()

Para empezar, ejecuta el archivo app.py en la terminal y visita la dirección local.

Repositorio de GitHub: https://github.com/sunilkumardash9/multi-modal-search-app

Casos de uso reales

La búsqueda multimodal puede tener muchas aplicaciones en diversas industrias.

  • E-commerce: La búsqueda multimodal puede mejorar la experiencia de compra del cliente. Por ejemplo, puedes tomar una foto de un producto en una tienda física y buscarlo en línea para encontrar productos similares.
  • Atención médica: Esto puede ayudar a diagnosticar enfermedades y encontrar tratamientos. Los médicos podrían usar una imagen para encontrar datos de investigación clínica en una base de datos médica.
  • Educación: Las aplicaciones educativas habilitadas para la búsqueda multimodal pueden ayudar a los estudiantes y profesores a encontrar documentos relevantes de forma más rápida. Recuperar texto basado en imágenes y viceversa puede ahorrar mucho tiempo.
  • Servicio al cliente: La búsqueda multimodal puede ayudar a encontrar respuestas relevantes a las consultas de los clientes en la base de conocimientos. Estas consultas pueden incluir imágenes o videos de productos.

Conclusión

La búsqueda multimodal será revolucionaria en el futuro. Poder interactuar en múltiples modalidades abre nuevas oportunidades de crecimiento. Así que este artículo trata sobre cómo utilizar la base de datos de vectores cromáticos y un modelo multimodal CLIP para construir una aplicación básica de búsqueda. Dado que la base de datos cromática no tiene soporte integrado para modelos multimodales, creamos una clase personalizada de incrustación CLIP para obtener incrustaciones de imágenes y ensamblamos diferentes partes para construir la aplicación de búsqueda de comida.

Puntos clave

  • En IA, la multimodalidad implica la capacidad de interactuar con múltiples modos de comunicación como texto, imagen, audio y video.
  • CLIP es un modelo de texto e imagen entrenado con miles de ejemplos de texto e imagen y capacidad de clasificación sin entrenamiento líder en su clase.
  • Las bases de datos de vectores están diseñadas para almacenar, buscar y consultar vectores de alta dimensión.
  • Los motores que permiten las tiendas de vectores son algoritmos ANN. HNSW es uno de los algoritmos ANN basados en gráficos más populares y eficientes.

Pregunta frecuente

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

Inteligencia Artificial

Spotify adopta la IA desde listas de reproducción personalizadas hasta anuncios de audio

La popular plataforma de música en streaming, Spotify, ha estado a la vanguardia de la tecnología, explorando continu...

Inteligencia Artificial

¿Podrían ser los Parches? Este enfoque de IA analiza el principal contribuyente al éxito de los Transformadores de Visión

Las redes neuronales convolucionales (CNN) han sido la columna vertebral de los sistemas para tareas de visión por co...

Inteligencia Artificial

¿Cómo supera Bing Chat a ChatGPT en proporcionar conocimiento en tiempo real actualizado? Conoce la Generación con Recuperación Mejorada (RAG)

Con el desarrollo de los Modelos de Lenguaje Grande (LLMs) en los últimos tiempos, estos modelos han provocado un cam...

Inteligencia Artificial

Algoritmo para la detección y movimiento robótico

Investigadores de la Universidad de California, Los Ángeles formularon un algoritmo que mejora las habilidades de nav...

Inteligencia Artificial

Demanda afirma que Meta diseñó Instagram y Facebook para enganchar a los niños

Meta dijo en un comunicado que la denuncia tergiversa su trabajo durante la última década para hacer que la experienc...

Inteligencia Artificial

Los efectos de ChatGPT en las escuelas y por qué está siendo prohibido.

Muchas escuelas están prohibiendo ChatGPT debido a preocupaciones de plagio, precisión y privacidad. Sin embargo, el ...