La IA dentro de tu biblioteca de fotos, y por qué la hemos trasladado a nuestras propias GPU

La IA dentro de tu biblioteca de fotos, y por qué la hemos trasladado a nuestras propias GPU

Cuando buscas «perro en la nieve» en tu biblioteca de fotos y aparece la imagen correcta, algo ya ha leído esa foto por ti. Nadie la etiquetó. Un modelo de machine learning miró los píxeles, decidió qué había en el encuadre y guardó esa comprensión para que pudieras encontrarla después. Hace poco trasladamos ese trabajo de las CPU a nuestras propias GPU (graphics processing units, unidades de procesamiento gráfico). Este artículo explica qué hace realmente la IA y por qué importa el hardware que la sustenta.

Los modelos que hacen esto posible no son nuestros. Provienen del proyecto de código abierto Immich sobre el que está construido PixelUnion. Lo que sí es nuestro es dónde se ejecutan: en hardware que poseemos y operamos nosotros mismos, en suelo europeo, no en una nube de IA de terceros. Los modelos leen tus fotos, y para nosotros importa que lo hagan en nuestros propios racks y en ningún otro lugar.

Hay una distinción que conviene hacer antes de seguir, porque es la que más cuenta para tu privacidad. Usar un modelo no es lo mismo que entrenarlo. El entrenamiento es el proceso caro y único en el que un modelo aprende a partir de millones de imágenes de ejemplo, y lo llevan a cabo los autores del modelo mucho antes de que llegue a nosotros. Lo que nosotros hacemos es inferencia: tomamos un modelo terminado, ya entrenado, y pasamos tu foto por él una sola vez para obtener un resultado, igual que pasas un documento por un escáner. Tus fotos nunca se usan para enseñar nada a los modelos. No se añaden a un conjunto de entrenamiento, no mejoran un modelo compartido y nada de ellas sale para hacer más lista una versión futura. El modelo mira tu foto, da su respuesta y la olvida.


Tres tareas, un truco compartido: hacer que los píxeles se puedan buscar

Immich ejecuta su IA en un servicio aparte, el contenedor immich-machine-learning, documentado en el README de machine learning del proyecto. Realiza tres tareas, y cada una resuelve un problema distinto:

  • La búsqueda inteligente convierte una foto en algo que puedes buscar con lenguaje corriente, mediante un modelo CLIP.
  • El reconocimiento facial encuentra caras y determina cuáles pertenecen a la misma persona, mediante un paquete de modelos como buffalo_l.
  • El OCR lee el texto que aparece dentro de tus fotos, mediante un modelo PP-OCRv5.

Conviene ser preciso aquí, porque «tres modelos» es una simplificación. Dos de estas tareas son en realidad un par de modelos que trabajan en secuencia, y cada tarea puede sustituirse por un modelo distinto. El reconocimiento facial ejecuta un modelo de detección seguido de un modelo de reconocimiento, y buffalo_l es un paquete que contiene ambos. Immich también ofrece alternativas como antelopev2, buffalo_m y buffalo_s. El OCR funciona igual, un modelo para encontrar el texto y otro para leerlo. Y CLIP en sí es un par de codificadores, uno para imágenes y otro para texto, con muchas variantes intercambiables. No hay ningún modelo de detección de objetos aparte: reconocer que una foto contiene un perro o una playa lo gestiona CLIP, no un modelo de etiquetado dedicado.

Lo que importa para entenderlos es que las tres tareas comparten un mismo truco subyacente. Entendamos ese truco primero. Después, las diferencias cobran sentido.

Detección y reconocimiento facial en dos etapas


CLIP: buscar por significado, no por etiquetas

La antigua búsqueda de fotos funcionaba con nombres de archivo y etiquetas manuales. Si no habías escrito «playa» en un pie de foto, buscar «playa» no encontraba nada. CLIP, un modelo publicado originalmente por OpenAI (artículo aquí), elimina esa limitación. Mira el contenido real de una imagen.

Aquí está la parte que confunde a la gente, explicada con sencillez. CLIP no guarda una lista de palabras para cada foto. Convierte cada foto en un vector: una larga lista de números, unos cuantos cientos, que en conjunto describen el significado de la imagen. Una foto de un husky en la nieve fresca y una foto de otro perro en la nieve acaban con listas de números similares, porque significan cosas similares. Esa lista se llama embedding.

Qué es realmente la búsqueda vectorial

Una vez que cada foto de tu biblioteca es un vector, guardamos todos esos vectores en una base de datos. La búsqueda funciona así:

  1. Escribes «perro en la nieve».
  2. El mismo modelo convierte tus palabras en un vector, con el mismo sistema de números que las fotos.
  3. La base de datos compara tu vector de búsqueda con los vectores de foto almacenados y mide cuán cerca está cada uno.
  4. Las coincidencias más cercanas vuelven primero.

«Cerca» aquí es matemática. Cada vector es un punto en el espacio, y el sistema mide la distancia entre tu consulta y cada foto. En su forma más simple, esto es fuerza bruta: comprobar la distancia a cada foto, una a una, ordenar por la más cercana. En ese proceso no hay en ningún momento coincidencia de etiquetas ni búsqueda por palabra clave. Una foto sin pie de foto, sin nombre de archivo y sin descripción aparece igualmente, porque su significado vive en los números.

Cómo la búsqueda vectorial encuentra las fotos más cercanas a tu consulta

Esa comparación por fuerza bruta es la versión honesta, y para una biblioteca normal funciona bien. También nombra el coste. Comparar una consulta con millones de vectores, uno a uno, se vuelve lento. A gran escala se pasa a índices más inteligentes, la búsqueda aproximada de vecinos más cercanos, que se saltan la mayoría de las comparaciones y aun así encuentran los resultados correctos. Qué enfoque necesitas depende del tamaño de la biblioteca, pero el principio es el mismo: convertir todo en vectores y luego encontrar los más cercanos.

Una cosa más que importa en Europa. El modelo CLIP por defecto maneja bien el inglés y mal otros idiomas. Existen variantes multilingües, e Immich te permite sustituirlas, como describe su guía de selección de modelo. El equilibrio es real: los mejores modelos multilingües son más grandes y necesitan más memoria para funcionar. Esa presión sobre la memoria es una de las razones por las que la elección del hardware empieza a contar, y a ello vamos.


buffalo_l: encontrar a la misma persona a lo largo de tus fotos

El reconocimiento facial en Immich usa buffalo_l, un paquete de modelos del proyecto InsightFace, alojado para Immich en Hugging Face. Funciona en dos etapas, y ambas vale la pena entenderlas, porque a menudo se supone que hace algo que no hace.

La primera etapa es la detección. El modelo escanea la imagen y determina dónde están las caras. Piensa en el cuadro de enfoque que una cámara dibuja alrededor de una cara, salvo que el modelo lo hace después, en cada foto. El resultado es un conjunto de recuadros: aquí hay una cara, aquí hay otra.

La segunda etapa es el reconocimiento. Para cada cara encontrada, el modelo produce un vector, la misma idea que CLIP pero ajustada a las caras. Puedes verlo como una huella numérica de esa cara. Dos fotos de la misma persona, con distinta luz y desde distintos ángulos, producen vectores que quedan cerca uno del otro. Dos personas distintas quedan lejos.

Ese es todo el mecanismo detrás de «personas» en tu biblioteca. No buscamos tu cara en ninguna base de datos externa, y nada lleva un nombre hasta que decides etiquetar a una persona tú mismo. El modelo mide la geometría de una cara y la convierte en números, y luego agrupa los números que están cerca. La propia guía sobre clústeres faciales de Immich describe cómo se puede afinar esa agrupación. Las huellas permanecen en nuestro sistema, en nuestro hardware. Nunca son el producto.


PP-OCRv5: leer el texto dentro de tus imágenes

La más reciente de las tres es el OCR, reconocimiento óptico de caracteres, añadido en Immich versión 2.2. Usa PP-OCRv5, un modelo del proyecto PaddleOCR de Baidu. El OCR es lo que te permite buscar palabras que aparecen dentro de una foto: un letrero de calle, la fachada de una tienda, una pizarra, la etiqueta de una botella.

También funciona en dos etapas, y la división refleja el reconocimiento facial.

Primero detecta el texto. El modelo encuentra las regiones de la imagen que contienen escritura y dibuja recuadros a su alrededor, igual que el modelo de caras enmarca las caras. Una foto de una calle puede tener texto en cinco sitios: un letrero, una matrícula, un cartel, un menú, un autobús. Cada uno se convierte en un recuadro.

Luego lee. Para cada recuadro, un segundo modelo determina qué caracteres hay realmente y los convierte en texto real, legible por máquina. Ese texto va al índice de búsqueda, de modo que después puedes buscar «pizzería» y encontrar la foto de la fachada del restaurante, aunque nunca escribieras un pie de foto.

El equilibrio es uno de esos detalles típicos de Marc que conviene señalar: el OCR es bueno con texto impreso nítido en escrituras compatibles, y mucho más débil con letra manuscrita o tipografías muy estilizadas. Immich admite oficialmente inglés, chino y japonés, y los idiomas de escritura latina en general funcionan con algo menos de precisión, como se comenta en el hilo sobre idiomas de OCR del proyecto. Es una función realmente útil, no mágica.


Por qué todo esto funciona mucho mejor en una GPU

Cada modelo anterior hace por debajo el mismo tipo de aritmética: cantidades enormes de pequeñas multiplicaciones y sumas, organizadas como cálculo matricial. Convertir una foto en un vector son millones de esas operaciones. Ese solo hecho explica toda la historia del hardware.

Una CPU tiene un número reducido de núcleos muy capaces, de un puñado a un par de docenas. Cada núcleo es flexible y rápido, y procesa las tareas en gran medida en secuencia. Ese diseño es excelente para el trabajo variado y ramificado que un servidor realiza todo el día. Encaja mal con hacer la misma multiplicación sencilla unos cuantos millones de veces seguidas.

Una GPU es lo contrario. Tiene miles de núcleos más sencillos, construidos para ejecutar la misma operación a la vez sobre enormes lotes de números, en paralelo. Las tarjetas gráficas se diseñaron para sombrear millones de píxeles simultáneamente, y resulta que la inferencia de machine learning es el mismo tipo de problema: las mismas matemáticas, repetidas sobre muchos datos. Así, en lugar de que los millones de operaciones de una foto goteen ola tras ola por unos pocos núcleos de CPU, se reparten juntas entre miles de núcleos de GPU.

Una CPU con pocos núcleos grandes frente a una GPU con muchos núcleos pequeños

El resultado no es una pequeña mejora, es un orden de magnitud de velocidad distinto para esta carga de trabajo concreta. Immich ofrece exactamente esto en su documentación sobre aceleración por hardware, que permite ejecutar el servicio de machine learning en CUDA, ROCm u OpenVINO en lugar de en la CPU. Los informes de la comunidad dan una idea de la escala. En CPU, la búsqueda inteligente es sistemáticamente la más lenta de las tareas de machine learning, y los usuarios la describen como el cuello de botella al indexar una biblioteca grande. En hardware de GPU modesto, un artículo documenta el embedding de unas 300.000 fotos en menos de una noche. Son cifras externas de instalaciones de otras personas, no nuestras, pero la dirección es coherente en todas partes: la GPU despeja el atasco en una fracción del tiempo.

Las tarjetas que elegimos para esto son tarjetas gráficas de consumo antiguas, no aceleradores nuevos de centro de datos. Es una elección deliberada, y trae consigo equilibrios que conviene nombrar. Una tarjeta así todavía tiene miles de núcleos paralelos y suficiente memoria integrada para alojar estos modelos con holgura, y eso es todo lo que necesita esta carga de trabajo. Los modelos no son grandes según los estándares actuales. CLIP es el más pesado de los tres, mientras que los modelos de cara y de OCR son comparativamente ligeros. Reutilizar hardware antiguo pero capaz mantiene buen silicio en servicio en lugar de mandarlo a un estante, y mantiene toda la cadena en equipos que nos pertenecen por completo.

Hay un coste real al otro lado de la balanza, y pretender lo contrario sería deshonesto. Una GPU consume más energía bajo carga que una CPU inactiva, y ejecutar tu propio hardware significa que nosotros cargamos con el mantenimiento, los controladores y la electricidad. Creemos que es el equilibrio correcto. Por foto procesada, la GPU hace el trabajo con mucha mejor eficiencia, y significa que la IA que lee tus recuerdos funciona en máquinas que nosotros controlamos, bajo derecho europeo, en lugar de enviarse a la nube de otro para su procesamiento.

Por ahora ejecutamos los modelos por defecto de Immich, los mismos que cualquier usuario de Immich obtiene de fábrica. La razón por la que este paso de hardware va más allá de la velocidad es el margen. Los modelos más grandes suelen necesitar más cómputo y más memoria para funcionar a un ritmo usable, precisamente lo que una CPU no podía proporcionar. Con nuestras propias GPU en su sitio, ejecutar una variante de CLIP más grande para una búsqueda más fina, o un modelo de cara más pesado para una mejor agrupación, se convierte en una opción práctica en lugar de en algo inviable. No hacemos aquí promesas sobre modelos concretos. La cuestión es que este paso abre la puerta, y mejores resultados para nuestros clientes son la razón para cruzarla.

Hay una trampa al cambiar a un modelo más grande, y conviene ser franco al respecto. Un modelo distinto produce vectores distintos. Los números que un modelo CLIP asigna a una foto no significan nada para otro modelo CLIP, así que no puedes mezclar lo viejo y lo nuevo. Si algún día pasamos a un modelo más grande, tendríamos que recalcular los embeddings de cada foto en la biblioteca de cada usuario desde cero, en nuestras propias GPU. Para una base de usuarios grande eso es una cantidad enorme de cálculo, y es exactamente el tipo de tarea que en CPU es inviable y en GPU es solo grande. Este paso nos acerca a estar listos para eso, pero aún no estamos ahí. Cuando lo estemos, merecerá su propio artículo.


Por qué lo hacemos nosotros mismos

Ninguno de estos modelos es exótico, y ninguno es secreto. Esa es la naturaleza de construir sobre código abierto: puedes leer exactamente qué hacen CLIP, buffalo_l y PP-OCRv5, y nosotros también. La decisión que de verdad configura tu privacidad no es qué modelo se ejecuta, sino dónde se ejecuta y quién lo opera.

Los ejecutamos en nuestras propias GPU, en nuestro propio entorno, en suelo europeo. Tus fotos las leen máquinas de las que somos responsables, y los vectores y huellas que salen de ese proceso se quedan con nosotros y nunca se venden. Esa es la parte que Big Tech no te ofrecerá, porque para ellos leer tus fotos es el modelo de negocio, no una función.

Para ser claros sobre dónde estamos: este es un primer paso, no el cuadro terminado. Los modelos de machine learning ahora funcionan en nuestras propias GPU, pero todavía no toda nuestra plataforma funciona en hardware que poseemos. Construimos infraestructura operada por nosotros mismos pieza a pieza, y la IA que lee tus fotos fue un punto de partida deliberado, porque es la parte más sensible. Preferimos decirte exactamente qué se ejecuta y dónde hoy que dar a entender que estamos más avanzados de lo que estamos. Cuenta con que ampliaremos esto en futuros artículos a medida que más partes del sistema se trasladen a nuestro propio hardware.

Si quieres una biblioteca de fotos con una búsqueda tan capaz, sin entregar los datos subyacentes a una empresa que los monetiza, eso es exactamente lo que estamos construyendo.

Descubre lo que ofrecemos →


Una nota sobre las imágenes: las infografías de este artículo se generaron con IA. Creemos que se ganan su lugar al hacer estas ideas más fáciles de visualizar.