Las incorporaciones vectoriales son una forma de representar datos del mundo real, como texto, imágenes o audio, matemáticamente, en forma de puntos en un mapa multidimensional. Parecería algo sumamente abstracto, pero con suficientes dimensiones, las computadoras (y por extensión, nosotros) pueden descubrir y comprender las relaciones entre esos datos.
Por ejemplo, tal vez recuerdes “word2vec”, una técnica revolucionaria desarrollada por Google en 2013 que transformó las palabras en vectores numéricos, con lo que desbloqueó el poder de la comprensión semántica de las máquinas. Este logro allanó el camino para innumerables avances en el procesamiento de lenguaje natural, desde la traducción automática hasta el análisis de opiniones.
Luego, sobre esta base lanzamos un poderoso modelo de incorporación de texto llamado text-gecko
, que permite a los desarrolladores explorar las numerosas relaciones semánticas dentro del texto.
La API de incorporaciones multimodales de Vertex te permite ir un paso más allá, ya que puedes representar texto, imágenes y video en ese mismo espacio vectorial compartido, preservando el significado contextual y semántico en diferentes modalidades.
En esta entrada, analizaremos dos aplicaciones prácticas de esta tecnología: buscar todas las diapositivas y los lotes que nuestro equipo creó en los últimos 10 años, y una herramienta de búsqueda visual intuitiva diseñada para artistas. Exploraremos el código en profundidad y compartiremos consejos prácticos sobre cómo puedes aprovechar todo el potencial de las incorporaciones multimodales.
Hace muy poco, con nuestro equipo analizamos cómo podríamos explorar la API de incorporaciones multimodales que habíamos lanzado recientemente. Reconocimos su potencial para grandes conjuntos de datos corporativos y nuestro objetivo fue encontrar aplicaciones más personales y creativas.
Khyati, una diseñadora de nuestro equipo, que también es una ilustradora prolífica, estaba particularmente intrigada por cómo esta tecnología podría ayudarla a administrar y comprender mejor su trabajo. Nos comentó lo siguiente:
“Los artistas suelen tener dificultades para localizar trabajos anteriores en función de la similitud visual o las palabras clave conceptuales. Los métodos tradicionales de organización de archivos simplemente no están a la altura, en especial cuando se busca por términos poco comunes o conceptos abstractos”.
Y así nació nuestra demostración de incorporaciones multimodales de código abierto
.
Si bien el conjunto de datos de Khyati era bastante más pequeño que la escala de un millón de documentos a la que se hace referencia en la documentación de la API de incorporaciones multimodales, proporcionó un caso de prueba ideal para la nueva búsqueda vectorial de Cloud Firestore, presentada en abril en Google Cloud Next.
Así que creamos un proyecto de Firebase y enviamos aproximadamente 250 ilustraciones de Khyati a la API de incorporaciones multimodales. Este proceso generó incorporaciones de matrices de números de punto flotante de 1,408 dimensiones (con el máximo contexto), que luego almacenamos en nuestra base de datos de Firestore:
mm_embedding_model = MultiModalEmbeddingModel.from_pretrained("multimodalembedding")
# create embeddings for each image:
embedding = mm_embedding_model.get_embeddings(
image=image,
dimension=1408,
)
# create a Firestore doc to store and add to a collection
doc = {
"name": "Illustration 1",
"imageEmbedding": Vector(embedding.image_embedding),
... # other metadata
}
khyati_collection.add(doc)
Asegúrate de indexar el campo imageEmbedding
con la CLI de Firestore.
Este bloque de código se acortó por cuestiones de espacio; echa un vistazo a este notebook para obtener un ejemplo completo. Toma el modelo de incorporación del paquete
vertexai.vision_models.
Buscar con la búsqueda vectorial con el método de K vecinos más próximos (KNN) de Firestore es sencillo. Incorpora tu consulta (de la misma manera que incorporaste las imágenes) y envíala a la API:
// Our frontend is typescript but we have access to the same embedding API:
const myQuery = 'fuzzy'; // could also be an image
const myQueryVector = await getEmbeddingsForQuery(myQuery); // MM API call
const vectorQuery: VectorQuery = await khyati_collection.findNearest({
vectorField: 'imageEmbedding', // name of your indexed field
queryVector: myQueryVector,
limit: 10, // how many documents to retrieve
distanceMeasure: 'DOT_PRODUCT' // one of three algorithms for distance
});
¡Eso es todo! El método findNearest
muestra los documentos más cercanos a la incorporación de tu consulta, junto con todos los metadatos asociados, al igual que una consulta estándar de Firestore.
Puedes encontrar la implementación de nuestra demostración/search
implementación aquí. Ten en cuenta cómo usamos la biblioteca de NPM@google-cloud/firestore
, que es donde se encuentra esta tecnología, a diferencia del paquetefirebase
habitual de NPM.
Si llegaste hasta aquí y todavía no comprendes realmente cómo se ven estos vectores de incorporación, te entendemos. Nosotros tampoco lo entendíamos al comienzo de este proyecto. Nuestro mundo es tridimensional, por lo que un espacio de 1,408 dimensiones suena bastante a ciencia ficción.
Por suerte, hay muchas herramientas disponibles para reducir la dimensionalidad de estos vectores, incluida una implementación maravillosa por parte de la gente de Google PAIR llamada UMAP. Al igual que con la incorporación de vecinos estocásticos distribuidos en t (t-SNE), puedes tomar tus vectores de incorporación multimodal y visualizarlos en tres dimensiones fácilmente con UMAP. Incluimos el código para procesar esta tarea en GitHub, además de un conjunto de datos de código abierto de imágenes meteorológicas y sus incorporaciones, que deberían ser plug-and-play.
Al tiempo que creamos la demostración de Khyati, también exploramos cómo flexibilizar la API de incorporaciones multimodales en función de la escala prevista. Tiene sentido que Google se destaque en el ámbito de las incorporaciones; después de todo, una tecnología similar impulsa muchos de nuestros principales productos de búsqueda.
Pero ¿cómo podríamos hacer una prueba a escala? Resulta que la igualmente prolífica creación de lotes de nuestro equipo ofreció un excelente campo de pruebas. Estamos hablando de miles de Presentaciones de Google acumuladas durante la última década. Imagínate una excavación arqueológica digital en la historia de las ideas de nuestro equipo.
La pregunta era la siguiente: ¿podría la API de incorporaciones multimodales desenterrar tesoros ocultos dentro de este vasto archivo? ¿Podrían los líderes de equipo finalmente encontrar esa idea perdida hace mucho tiempo? “¿Cómo era aquella idea, del encuentro intensivo sobre aquello, alguien tomó nota de esa idea?”. ¿Podrían nuestros diseñadores redescubrir fácilmente ese increíble póster que tanto entusiasmó a todos? Alerta de spoiler: ¡sí!
Dedicamos la mayoría de nuestro tiempo de desarrollo a explorar las miles de presentaciones y extraer miniaturas de cada diapositiva utilizando las API de Drive y Presentaciones. El proceso de incorporación en sí fue casi idéntico al de la demostración de la artista y se puede resumir de la siguiente manera:
for preso in all_decks:
for slide in preso.slides:
thumbnail = slides_api.getThumbnail(slide.id, preso.id)
slide_embedding = mm_embedding_model.get_embeddings(
image=thumbnail,
dimension=1408,
)
# store slide_embedding.image_embedding in a document
Este proceso generó incorporaciones para más de 775,000 diapositivas en más de 16,000 presentaciones. Para almacenar y explorar este enorme conjunto de datos de manera eficiente, recurrimos a la búsqueda de vectores de Vertex AI, diseñada específicamente para este tipo de aplicaciones a gran escala.
La búsqueda de vectores de Vertex AI, que cuenta con la misma tecnología que impulsa la Búsqueda de Google, YouTube y Play, puede buscar miles de millones de documentos en milisegundos. Funciona con principios similares al enfoque de Firestore que usamos en la demostración de la artista, pero con una escala y un rendimiento significativamente mayores.
Para aprovechar esta tecnología increíble y poderosa, deberás completar algunos pasos adicionales antes de realizar búsquedas:
# Vector Search relies on Indexes, created via code or UI, so first make sure your embeddings from the previous step are stored in a Cloud bucket, then:
my_index = aiplatform.MatchingEngineIndex.create_tree_ah_index(
display_name = 'my_index_name',
contents_delta_uri = BUCKET_URI,
dimensions = 1408, # use same number as when you created them
approximate_neighbors_count = 10, #
)
# Create and Deploy this Index to an Endpoint
my_index_endpoint = aiplatform.MatchingEngineIndexEndpoint.create(
display_name = "my_endpoint_name",
public_endpoint_enabled = True
)
my_index_endpoint.deploy_index(
index = my_index, deployed_index_id = "my_deployed_index_id"
)
# Once that's online and ready, you can query like before from your app!
response = my_index_endpoint.find_neighbors(
deployed_index_id = "my_deployed_index_id",
queries = [some_query_embedding],
num_neighbors = 10
)
El proceso es similar a la demostración de Khyati, pero con una diferencia clave: creamos especialmente un índice de búsqueda vectorial para liberar el poder de ScaNN, el algoritmo de búsqueda de similitud vectorial altamente eficaz de Google.
Ahora que conoces ambas opciones, veamos en profundidad sus diferencias.
Tal vez notaste que había dos tipos de algoritmos asociados con cada servicio de búsqueda vectorial: el método de K vecinos más próximos (KNN) para Firestore y ScaNN para la implementación de Vertex AI. Comenzamos ambas demostraciones trabajando con Firestore, ya que normalmente no usamos soluciones a escala empresarial en las tareas diarias de nuestro equipo.
Pero la búsqueda con el método KNN de Firestore es un algoritmo O(n) de fuerza bruta, lo que significa que escala linealmente según la cantidad de documentos que agregas a tu índice. Entonces, una vez que comenzamos a superar las 10,000; 15,000; y 20,000 incorporaciones de documentos, el proceso comenzó a hacerse mucho más lento.
Sin embargo, esta ralentización se puede mitigar con los predicados de consulta estándar de Firestore que se utilizan en un paso de “prefiltrado”. Entonces, en lugar de buscar en todas las incorporaciones que indexaste, puedes hacer una consulta where
para limitar tu conjunto solo a los documentos relevantes. Para esto, se necesita otro índice compuesto en los campos que deseas utilizar para filtrar.
# creating additional indexes is easy, but still needs to be considered
gcloud alpha firestore indexes composite create
--collection-group=all_slides
--query-scope=COLLECTION
--field-config=order=ASCENDING,field-path="project" # additional fields
--field-config field-path=slide_embedding,vector-config='{"dimension":"1408", "flat": "{}"}'
ScaNN tiene un funcionamiento similar a KNN, pero utiliza la indexación inteligente basada en ubicaciones “aproximadas” (como en “vecino más próximo aproximado escalable”), y fue un avance de Google Research que se lanzó al público en 2020.
Se pueden consultar miles de millones de documentos en milisegundos, pero ese poder tiene un costo, especialmente en comparación con la lectura/escritura de Firestore. Además, los índices son sencillos de forma predeterminada (pares de clave/valor simples), por lo que se requieren búsquedas secundarias en tus otras colecciones o tablas una vez que se muestran los vecinos más próximos. De todas maneras, para nuestras 775,000 diapositivas, una búsqueda de ~100 ms + una lectura de ~50 ms en Firestore para los metadatos, los órdenes de magnitud seguían siendo más rápidos de lo que la búsqueda vectorial de Cloud Firestore podía proporcionar de forma nativa.
También hay mucha documentación sobre cómo combinar la búsqueda vectorial con la búsqueda tradicional de palabras clave en un enfoque llamado “búsqueda híbrida”. Obtén más información sobre este tema aquí.
Nota adicional sobre el formateo
Para la creación de índices para Vertex AI también se necesitó un formato de archivo de clave/valorjsonl
, que requirió cierto esfuerzo para la conversión desde nuestra implementación original de Firestore. Si no estás seguro de cuál usar, tal vez valga la pena escribir las incorporaciones en un formato que se pueda adaptar fácilmente a cualquiera de los sistemas. De esta manera, te evitarás los grandes problemas que suelen causar las exportaciones de LevelDB Firestore.
Si no buscas una solución totalmente alojada en la nube, puedes aprovechar la potencia de la API de incorporaciones multimodales con una solución local.
También probamos una nueva biblioteca llamada sqlite-vecuna
, una implementación sumamente rápida y sin dependencia de sqlite que puede ejecutarse en casi cualquier lugar y que procesa con facilidad los vectores de 1,408 dimensiones que muestra la API de incorporaciones multimodales. La migración de más de 20,000 de nuestras diapositivas para una prueba mostró búsquedas en el rango de ~200 ms. Sigues creando incorporaciones de documentos y consultas en línea, pero puedes procesar tu búsqueda donde sea necesario una vez que se crean y almacenan.
Desde las primeras versiones de word2vec hasta la API de incorporaciones multimodales de la actualidad, cuentas con nuevas posibilidades interesantes para crear tus propios sistemas de IA multimodal para buscar información.
Elegir la solución de búsqueda vectorial adecuada depende de tus necesidades. Firebase proporciona una opción fácil de usar y rentable para proyectos más pequeños, mientras que Vertex AI ofrece la escalabilidad y el rendimiento necesarios para grandes conjuntos de datos y búsqueda en milisegundos. Para el desarrollo local, herramientas como sqlite-vec te permiten aprovechar el poder de las incorporaciones principalmente sin conexión.
¿Tienes todo listo para explorar el futuro de la búsqueda multimodal? Sumérgete en nuestra demostración de incorporaciones multimodales de código abierto en GitHub, experimenta con el código y comparte tus propias creaciones. Tenemos muchas ganas de ver lo que creas.