La era de la búsqueda y recuperación que mezcla texto, imágenes, audio y video ya está aquí. ¿Te imaginas poder buscar una imagen con una frase, luego afinar resultados con un reranker que entiende text+imagen? Hugging Face y Sentence Transformers presentan soporte multimodal que vuelve esto práctico y accesible.
¿Qué son los modelos multimodales?
Los modelos de embedding tradicionales convierten texto en vectores fijos. Los modelos multimodales extienden esa idea: mapean entradas de distintas modalidades (texto, imagen, audio, video) a un mismo espacio de embeddings. ¿Resultado? Puedes comparar directamente una consulta en texto con documentos que son imágenes o screenshots usando las mismas funciones de similitud que ya conoces.
Los rerankers multimodales (CrossEncoders) hacen lo contrario: reciben pares mixtos (texto+imagen, imagen+imagen, etc.) y devuelven un score de relevancia por par. Suelen dar mejor calidad que los embeddings, pero son más lentos porque procesan cada par de forma individual.
Nota práctica: las similitudes cross-modal suelen ser más bajas en magnitud que las text-to-text. No te alarmes si los scores máximos no se acercan a 1.0; lo importante es el orden relativo.
Consejo: los modelos VLM grandes (p. ej. Qwen3-VL-2B) requieren GPU con al menos ~8 GB VRAM; las variantes 8B necesitan ~20 GB. Si no tienes GPU local, usa un GPU en la nube o Google Colab. En CPU serán muy lentos: para CPU, los CLIP o modelos sólo texto rinden mejor.
Modelos de embedding multimodales: carga y uso
Cargar un modelo multimodal es tan sencillo como con uno de texto:
from sentence_transformers import SentenceTransformer
model = SentenceTransformer('Qwen/Qwen3-VL-Embedding-2B', revision='refs/pr/23')
Por ahora algunas integraciones requieren el argumento revision hasta que se fusionen los PR. El modelo detecta automáticamente las modalidades soportadas. model.encode() acepta imágenes (URLs, rutas locales o objetos PIL), texto y dicts multimodales.
Ejemplo de codificación y similitud cross-modal:
# Encode imágenes
img_embeddings = model.encode([
'https://.../car.jpg',
'https://.../bee.jpg',
])
# Encode texto
text_embeddings = model.encode([
'A green car parked in front of a yellow building',
'A red car driving on a highway',
'A bee on a pink flower',
'A wasp on a wooden table',
])
# Similitudes
similarities = model.similarity(text_embeddings, img_embeddings)
print(similarities)
Verás que las mejores correspondencias se mantienen en orden, aunque los valores absolutos sean moderados por la modality gap.
encode_query / encode_document
Para tareas de recuperación es recomendable usar encode_query() y encode_document(). Muchos modelos incluyen prompts distintos para consultas y documentos; estos métodos aplican automáticamente el prompt correcto antes de generar embeddings.
Rerankers multimodales (CrossEncoder)
Los rerankers multimediales puntúan pares mixtos. Son ideales para refinar listas cortas de candidatos. Ejemplo de uso con rank:
from sentence_transformers import CrossEncoder
model = CrossEncoder('Qwen/Qwen3-VL-Reranker-2B', revision='refs/pr/11')
query = 'A green car parked in front of a yellow building'
documents = [
'https://.../car.jpg',
'https://.../bee.jpg',
'A vintage Volkswagen Beetle painted in bright green sits in a driveway.',
{'text': 'A car in a European city', 'image': 'https://.../car.jpg'},
]
rankings = model.rank(query, documents)
El reranker suele ordenar correctamente (imagen del coche arriba, abeja abajo), pero recuerda que los rangos de scores pueden variar según si el par es text-image o text-text.
También puedes usar predict() para obtener scores crudos sobre pares específicos.
Recuperar y reordenar: patrón recomendable
Un patrón efectivo y escalable:
Recuperación inicial con un modelo de embeddings (rápido, indexable). Precomputas embeddings del corpus.
Reranking de los top-k con un CrossEncoder multimodal para obtener precisión.
processor_kwargs ajusta la resolución y calidad de imágenes (más max_pixels implica mayor memoria y tiempo). model_kwargs controla la precisión, atención y otros parámetros de carga de modelo.
Si tienes hardware limitado, los modelos CLIP siguen siendo una opción sólida para CPU:
sentence-transformers/clip-ViT-L-14
sentence-transformers/clip-ViT-B-16
Buenas prácticas y consideraciones técnicas
Precompute embeddings del corpus y usa índices (FAISS, Milvus) para escalar.
Usa batching y FP16/bfloat16 cuando el hardware lo permita para reducir memoria.
Ten en cuenta la modality gap: normaliza expectativas sobre magnitud de scores, pero confía en el ordenamiento.
Verifica qué modalidades soporta un modelo con model.modalities y model.supports('image').
Si necesitas control fino sobre mensajes chat-style, puedes pasar message dicts crudos y evitar la conversión automática.
Si vas a entrenar/finetunear, pronto habrá una guía dedicada (Hugging Face anuncia un post sobre entrenamiento multimodal próximamente).
La llegada de embeddings y rerankers multimodales en Sentence Transformers hace que construir pipelines RAG y buscadores cross-modal sea mucho más directo. ¿La moraleja? Puedes empezar a experimentar hoy sin reinventar la rueda: prueba con CLIP si estás en CPU, sube a VLMs en GPU y combina recuperación rápida con reranking para producción.