Cuando aparecieron los primeros modelos de texto a imagen requerían un hardware potente y mucha paciencia para obtener resultados que en esa época eran sorprendentes (actualmente los consideraríamos como «malos resultados»). Esos primeros modelos basados en VQGAN requerían varios minutos usando hardware potente, Google Colab mediante, para lograr generar una imagen. Con los modelos de difusión la cosa mejoró, sin embargo seguíamos necesitando GPUs con gran cantidad de memoria RAM. Pero la comunidad de software libre está haciendo un gran esfuerzo por lograr que se ejecute en hardware cada vez más modesto.
¿Hasta qué punto se ha optimizado Stable Diffusion? ¿Podemos usarlo en un ordenador normalito?.
Primero, uso Stable Diffusion porque al ser código libre ha permitido a la gente «trastear» con él, ventajas del Open Source.
Al empezar a mirar opciones he descubierto que hay muchísimos proyectos que tratan de reducir los recursos necesarios para ejecutar SD. Al final me he decantado por el proyecto stable-diffusion.cpp por los siguientes motivos:
- Es un proyecto real que trata de hacer SD usable con muchas de sus características. Muchos de los otros proyectos son poco más que demos técnicas muy limitadas.
- Esta en continuo desarrollo.
- Busca un equilibrio entre consumo de recursos y usabilidad.
Antes de empezar con las pruebas hemos de entender cómo funciona SD. Para ello usaremos el siguiente esquema:

SD consta principalmente de tres partes:
- Text Encoder: convierte el prompt en embeddings que usa para condicionar el funcionamiento de la Unet
- Unet: es alimentada con una imagen llena de ruido y su trabajo es eliminarlo, condicionado por el text encoder, para obtener la imagen. En este paso SD no trabaja con la imagen final si no con una descripción en el espacio latente de la misma
- V.A.E.: su función es convertir la descripción del paso anterior en una imagen.
Este es el funcionamiento para generar una imagen a partir de un prompt. Si queremos generarla cuando una imagen de partida, además del prompt, lo que se hace es que en lugar de pasar a la Unet una imagen llena de ruido se le pasa la imagen de partida y se le añade ruido. De esta manera la imagen influirá sobre el resultado final.
Sabiendo esto vamos a ver que «trucos» usa stable-diffusion.cpp para conseguir optimizar la ejcución de SD:
- Esta programado en C++ buscando exprimir al máximo el rendimiento del programa
- Usa un versión cuantizada del modelo. En mis pruebas usar la versión Q4_1 que usa unos 4 bits por parámetro. Mientras que el modelo original usa 32 bits.
- Usar la versión mini y nano de SD que generan imágenes mas pequeñas. Este truco lo añado yo después de verlo comentado en el proyecto.
Tenéis un vídeo con detalles de la pruebas y de la tabla de resultados en mi canal de Youtube:
Para las pruebas he usado los siguientes modelos:
El comando usado ha sido:
./bin/sd -m [modelo] -H 768 -W 768 -p «A sheep with sunglasses riding a motorbike»
Se ha probado con diferentes tamaños de imagen según el modelo empleado:
| Modelo | Dim. | Clip | Unet | VAE | Mem. | Tiempo |
|---|---|---|---|---|---|---|
| 1.4 – Q4_1 | 512 | 73.80/87.21 | 1286.35/1857.94 | 94.51/1768.95 | 1952.45 | 199.92 |
| 1.5 – Q4_1 | 512 | 73.80/87.21 | 1286.35/1857.94 | 94.51/1768.95 | 1952.45 | 218.39 |
| 2.1 nano – Q4_1 | 512 | 211.55/226.21 | 1290.15/1669.82 | 94.51/1768.95 | 1768.65 | 254.42 |
| 2.1 – Q4_1 | 512 | 211.55/226.21 | 1290.15/1669.82 | 94.51/1768.95 | 1768.65 | 179.76 |
| 2.1 – Q4_1 | 768 | 211.55/226.21 | 1290.15/3021.54 | 94.51/3848.65 | 3848.65 | 543.88 |
| 1.4 mini – Q4_1 | 256 | 73.80/87.21 | 1286.35/1346.94 | 94.51/520.65 | 1468.07 | 57.44 |
| 2.1 nano – Q4_1 | 128 | 211.55/226.21 | 1290.15/1314.91 | 94.51/208.65 | 1610.88 | 15.62 |
| 2.1 – f32 | 512 | 1346.65/1360.93 | 2179.92/2553.33 | 94.51/1768.65 | 3653.36 | 181.84 |
| 2.1 – f32 | 768 | 1346.65/1360.93 | 2179.92/3897.24 | 94.51/3848.65 | 3991.75 | 566.58 |
Clip, Unet y VAE indican el tamaño de: parámetros / total memoria en ejecución
Dim. indica el tamaño en pixeles de la imagen Dim x Dim
Tiempo indica la duración de la creación en segundos
Las pruebas han sido realizadas en un portátil con un procesador AMD Ryzen 7 5800H con 16 GB de memoria RAM.
Como mención honorifica cabe destacar otro proyecto: OnnxStream que logra ejecutar SD en una Raspberry Pi 2 Zero que solo tiene 512MB (¡Y le sobran casi 200 MB!) de memoria RAM
