Explorando embeddings multimodales con FiftyOne y Milvus
¿Cuál es el primer paso para crear una aplicación multimodal de generación aumentada por recuperación (RAG)? Obtener embeddings vectoriales multimodales. En cierto modo, decir que un embedding es multimodal es un término inexacto. Hay muchas formas de trabajar con múltiples modalidades dentro de vectores, pero en este tutorial nos centramos en los embeddings vectoriales producidos por modelos multimodales.
En este artículo, cubrimos:
- ¿Qué significa “multimodal”?
- ¿Cómo maneja Milvus los embeddings multimodales?
- Ejemplos de modelos multimodales
- Uso de FiftyOne y Milvus para la exploración de embeddings multimodales
- Exploración de embeddings multimodales para CIFAR 10 mediante FiftyOne y CLIP
- ¿Cómo podemos personalizar aún más FiftyOne para la exploración de datos con Milvus?
- Resumen de la exploración de embeddings multimodales con FiftyOne y Milvus
¿Qué significa “multimodal”?
Al hablar de "multimodal", nos referimos a las capacidades de los modelos. Tanto el modelo de lenguaje grande/modelo fundacional como el modelo de embeddings en una pila RAG pueden ser multimodales. Exploramos embeddings multimodales de un modelo de código abierto para este ejemplo. ¿Cómo obtenemos un embedding vectorial? Los embeddings vectoriales provienen de la penúltima capa de un modelo de embeddings.
Esto se debe a que cada capa del modelo aprende cierta información sobre la entrada, y la última capa hace una predicción. Como no queremos una predicción, sino poder trabajar con una representación numérica de los datos, eliminamos la última capa y tomamos la salida de la penúltima capa, que contiene toda la información que el modelo ha aprendido. Usamos FiftyOne para facilitar la exploración y Milvus para almacenar los vectores.
¿Cómo maneja Milvus los embeddings multimodales?
Lo interesante de los embeddings multimodales, o de los embeddings vectoriales en general, es que no necesitan un tratamiento especial. Los embeddings vectoriales son simplemente representaciones numéricas de un tipo específico de datos de entrada. En cuanto al tipo de datos real, los embeddings vectoriales son simplemente vectores, una lista de números. Milvus maneja todos estos vectores de la misma manera.
Los vectores pueden ser densos o dispersos. Los vectores densos suelen estar compuestos por flotantes y son producidos por modelos de aprendizaje profundo, un ejemplo de lo cual veremos hoy. Los vectores dispersos a veces se llaman vectores binarios y están compuestos por 0 y 1. Algo importante a tener en cuenta al trabajar con vectores es que solo se pueden comparar vectores del mismo tamaño o dimensionalidad. Además, incluso cuando tienen el mismo tamaño, los embeddings generados por distintos modelos no necesariamente pueden compararse de forma equivalente.
Los embeddings multimodales son especialmente complicados. La mayoría de los modelos de aprendizaje profundo están diseñados para tratar con un tipo, o modalidad, de datos. Esto podría ser imágenes, texto, video o algo más específico. Sin embargo, debido a que estos modelos solo están optimizados para un tipo de datos, no pueden procesar ni representar otras modalidades: un modelo entrenado para aceptar entrada de texto normalmente no podrá aceptar imágenes.
Los modelos multimodales se entrenan para interactuar con múltiples tipos de datos. Para nuestros fines, nos interesan los modelos multimodales que producen embeddings vectoriales para múltiples modalidades de datos. En particular, nos interesan los modelos que incrustan datos textuales y visuales en el mismo espacio, de modo que las dimensiones de los vectores generados sean las mismas y podamos tratarlos de manera similar con sentido.
El modelo multimodal más común para generar embeddings de texto e imagen es CLIP, de OpenAI, que utiliza técnicas contrastivas para alinear los embeddings de imágenes de fotografías con los embeddings de texto de sus subtítulos.
Uso de FiftyOne y Milvus para la exploración de embeddings multimodales
FiftyOne es la biblioteca de código abierto líder para la curación y visualización de datos no estructurados. FiftyOne se integra con múltiples backends de almacenes vectoriales, siendo Milvus particularmente adecuado para trabajar de forma flexible con conjuntos de datos grandes y en crecimiento. En este ejemplo, usamos Milvus Lite, una versión embebida de Milvus que puedes iniciar directamente en tu notebook. Para una mirada en profundidad, consulta esta guía de extremo a extremo sobre Milvus Lite.
Antes de adentrarte en el código, asegúrate de que estén instalados todos los prerrequisitos adecuados. Debes ejecutar pip install milvus pymilvus fiftyone torch torchvision. El primer paso es poner en marcha nuestra instancia de Milvus Lite. Podemos hacerlo importando default_server desde Milvus y llamando a la función start().
from milvus import default_server
default_server.start()
Ahora que tenemos una instancia de Milvus lista para usar, podemos vincularla a FiftyOne para comparaciones de embeddings vectoriales. Importamos FiftyOne, FiftyOne Brain y el FiftyOne Zoo y cargamos la división de prueba del conjunto de datos CIFAR 10.
import fiftyone as fo
import fiftyone.brain as fob
import fiftyone.zoo as foz
# Step 1: Load your data into FiftyOne
dataset = foz.load_zoo_dataset("cifar10", split="test")
Usaremos el modelo CLIP para generar embeddings de nuestras imágenes en este ejemplo. Luego, usaremos la función compute_similarity de FiftyOne Brain. Esta función primero genera embeddings para nuestras muestras usando un modelo especificado, luego crea una colección de Milvus a partir de estos embeddings y la adjunta a la colección de muestras de FiftyOne. Con FiftyOne y backends de búsqueda vectorial, puedes generar un índice de similitud sobre imágenes, recortes de objetos e incluso fotogramas de video!
La función compute_similarity recibe el conjunto de datos de FiftyOne y varios parámetros con nombre. brain_key es una clave única que FiftyOne usa para llevar un registro de las ejecuciones. La clave backend le indica a FiftyOne qué backend de base de datos vectorial usar, y model recibe el nombre del modelo que FiftyOne aprovechará para crear embeddings.
fob.compute_similarity(
dataset,
brain_key="clip_sim",
backend="milvus",
model="clip-vit-base32-torch",
)
El último paso que vemos aquí antes de explorar es usar FiftyOne para iniciar la FiftyOne App. Pasamos el conjunto de datos y establecemos auto=False para que la ventana no se abra en el notebook, pero pueda accederse a través de una pestaña de Chrome en localhost:5151.
session = fo.launch_app(dataset, auto=False)
Exploración de embeddings multimodales para CIFAR 10 mediante FiftyOne y CLIP
¡Es hora de explorar! Veamos cómo usar texto para encontrar imágenes semánticamente similares. Veamos tres palabras: Ferrari, Mustang y Pony.
Nuestra primera búsqueda de un Ferrari es un coche.
La siguiente búsqueda, “pony”, claramente nos da imágenes de caballos.
Pero, si buscamos “mustang”, obtenemos una mezcla.
¡Este paso muestra que es esencial evaluar tu conjunto de datos y comprender el contexto de tus datos!
¿Cómo podemos personalizar aún más FiftyOne para la exploración de datos con Milvus?
Para establecer Milvus como el “backend” predeterminado para la búsqueda vectorial en FiftyOne, podemos cargar la siguiente variable de entorno:
export FIFTYONE_BRAIN_DEFAULT_SIMILARITY_BACKEND=milvus
Para cualquier índice dado, también podemos especificar el nombre de la colección, qué nivel de consistencia usar y qué métrica usar para evaluar la similitud. Aquí hay un segundo índice de similitud que utiliza una métrica euclidiana y consistencia Bounded:
fob.compute_similarity(
dataset,
brain_key="clip_euclid",
model="clip-vit-base32-torch",
metric="euclidean",
consistency_level="Bounded"
)
Si tenemos varios índices de similitud en un dataset, podemos seleccionar cuál queremos usar en la app haciendo clic en el icono de engranaje junto a la barra de búsqueda bajo la lupa, y eligiendo el índice por su brain key:
También podemos usar un modelo multimodal diferente para generar nuestros embeddings de imágenes y texto. De hecho, podemos hacerlo con cualquier modelo OpenCLIP (tendremos un enlace mejor aquí en unos días), o cualquier modelo de predicción zero-shot de la biblioteca Transformers de Hugging Face. Como ejemplo, aquí hay un índice construido con AltCLIP:
!pip install transformers
fob.compute_similarity(
dataset,
brain_key="altclip",
model="zero-shot-classification-transformer-torch",
name_or_path="BAAI/AltCLIP",
)
Resumen de la exploración de embeddings multimodales con FiftyOne y Milvus
Esta publicación exploró cómo funcionan los embeddings multimodales con FiftyOne y Milvus. Mostramos cómo puedes explorar un modelo multimodal popular - CLIP - en un dataset popular - CIFAR 10. Usas CLIP para crear los embeddings de los datos de entrada, Milvus para almacenar los embeddings de los datos multimodales (a veces denominados “embeddings multimodales”), y FiftyOne para explorar los embeddings.
Usar CLIP de esta manera te permite buscar imágenes con texto. Con eso, exploramos el espacio usando lenguaje natural para comparar imágenes de palabras que pueden tener diferentes significados en distintos contextos. Vimos cómo “pony” es claramente un caballo, “Ferrari” es claramente un coche, pero “mustang” podría ser cualquiera de los dos.
Sigue leyendo

A Developer's Guide to Exploring Milvus 2.6 Features on Zilliz Cloud
Milvus 2.6 marks a shift from “vector search + glue code” to a more advanced retrieval engine, and it is now Generally Available (GA) on Zilliz Cloud (a managed Milvus service).

How to Improve Retrieval Quality for Japanese Text with Sudachi, Milvus/Zilliz, and AWS Bedrock
Learn how Sudachi normalization and Milvus/Zilliz hybrid search improve Japanese RAG accuracy with BM25 + vector fusion, AWS Bedrock embeddings, and practical code examples.

How Zilliz Saw the Future of Vector Databases—and Built for Production
An inside look at how Zilliz built vector databases for real-world use, focusing on scalability, stability, and running them reliably at scale.



