📖 Teoría

Modelos de Difusión

Destruir para crear: del ruido gaussiano a las imágenes fotorrealistas. Fundamentos matemáticos (forward process, reverse process, ELBO, score matching), entrenamiento práctico con código PyTorch y TensorFlow, samplers (DDPM, DDIM, DPM-Solver), Stable Diffusion, DALL-E, DiT, aplicaciones en vídeo, ciencia y arte, y la comparativa definitiva con las GANs.

¿Qué son los modelos de difusión?

Los modelos de difusión (Diffusion Probabilistic Models) son una familia de modelos generativos que aprenden a crear datos revirtiendo un proceso gradual de destrucción. La idea es conceptualmente elegante: primero destruyes los datos añadiendo ruido poco a poco hasta convertirlos en ruido puro; luego entrenas una red neuronal para que aprenda a deshacer cada paso de ruido, reconstruyendo los datos originales desde la nada.

💡 Intuición rápida: Imagina que tienes una gota de tinta cayendo en un vaso de agua. Con el tiempo, la tinta se dispersa uniformemente (proceso forward). Un modelo de difusión aprende a rebobinar la película: partiendo del agua coloreada uniformemente, reconstruye la gota original. Esto es el proceso inverso (reverse process).

📐 Definición formal

Un modelo de difusión define dos procesos de Markov:

  1. Proceso forward \(q(\mathbf{x}_t | \mathbf{x}_{t-1})\): añade ruido gaussiano gradualmente hasta destruir toda la estructura en los datos.
  2. Proceso reverse \(p_\theta(\mathbf{x}_{t-1} | \mathbf{x}_t)\): una red neuronal parametrizada por \(\theta\) que aprende a eliminar el ruido paso a paso.
$$q(\mathbf{x}_t | \mathbf{x}_{t-1}) = \mathcal{N}\!\left(\mathbf{x}_t;\, \sqrt{1-\beta_t}\,\mathbf{x}_{t-1},\; \beta_t \mathbf{I}\right)$$

donde \(\beta_t\) es un noise schedule que controla cuánto ruido se añade en cada paso \(t\).

A diferencia de las GANs, que usan un entrenamiento adversarial (generador vs discriminador), y los Autoencoders Variacionales (VAEs), que optimizan una ELBO, los modelos de difusión optimizan una suma ponderada de términos de denoising, lo que resulta en un entrenamiento más estable y una calidad de generación superior.

Historia de los modelos de difusión

Aunque los modelos de difusión conquistaron la IA generativa a partir de 2020, sus raíces se remontan a la termodinámica y la física estadística. El camino hasta la generación de imágenes fotorrealistas fue largo y multidisciplinar.

2015
Deep Unsupervised Learning using Nonequilibrium Thermodynamics — Sohl-Dickstein et al. proponen por primera vez la idea de usar un proceso de difusión termodinámico para modelar distribuciones de datos complejas. 📄 arXiv:1503.03585
2019
Generative Modeling by Estimating Gradients of the Data Distribution — Song & Ermon introducen score matching con Langevin dynamics (NCSN), conectando la estimación de gradientes con la generación. 📄 arXiv:1907.05600
2020
DDPM — Denoising Diffusion Probabilistic Models — Ho, Jain & Abbeel demuestran que los modelos de difusión pueden generar imágenes con calidad comparable a GANs. El paper que lo cambió todo. 📄 arXiv:2006.11239 · GitHub: hojonathanho/diffusion
2021 (enero)
DDIM — Denoising Diffusion Implicit Models — Song et al. proponen un sampler determinista que permite generar con muchos menos pasos (50× más rápido que DDPM). 📄 arXiv:2010.02502
2021 (feb)
Improved DDPM — Nichol & Dhariwal (OpenAI) mejoran DDPM con learned variance, cosine schedule, y classifier guidance. 📄 arXiv:2102.09672
2021 (mayo)
Diffusion Models Beat GANs on Image Synthesis — Dhariwal & Nichol demuestran que los modelos de difusión superan a las GANs en FID en ImageNet, marcando un punto de inflexión histórico. 📄 arXiv:2105.05233
2021 (dic)
Classifier-Free Diffusion Guidance — Ho & Salimans proponen guiar la generación sin clasificador externo, simplificando enormemente la generación condicional. 📄 arXiv:2207.12598
2022 (abr)
DALL-E 2 — OpenAI combina CLIP + difusión para text-to-image. Imagen — Google usa T5 como text encoder + cascaded diffusion. 📄 arXiv:2204.06125 (DALL-E 2) · arXiv:2205.11487 (Imagen)
2022 (ago)
Stable Diffusion — Rombach et al. (Stability AI / CompVis / Runway) publican Latent Diffusion Models: difusión en espacio latente comprimido con un VAE encoder, reduciendo coste computacional ×50. Open source. 📄 arXiv:2112.10752 · GitHub: CompVis/stable-diffusion
2023
SDXL, Consistency Models, DALL-E 3 — Mejoras en calidad, velocidad de sampling (modelos de consistencia de Song et al.), y mejor alineamiento texto-imagen. 📄 arXiv:2307.01952 (SDXL) · arXiv:2303.01469 (Consistency)
2024+
Sora, Flux, SD3, DiT — Difusión + Transformers (DiT) para vídeo (Sora), flow matching (Flux, SD3), y modelos multimodales. La difusión se convierte en la base de la IA generativa moderna. 📄 arXiv:2212.09748 (DiT) · arXiv:2403.03206 (SD3)

Intuición: destruir para crear

La idea central de los modelos de difusión se puede entender con una analogía visual. El proceso forward destruye la imagen original añadiendo ruido gaussiano en \(T\) pasos hasta obtener ruido puro. El proceso reverse es una red neuronal que aprende a revertir cada paso, reconstruyendo la imagen desde el ruido.

FORWARD PROCESS q(x_t | x_{t-1}) — Añadir ruido 🖼️ nítida x₀ 🖼️ algo de ruido x₁ ··· T pasos 🌫️ casi ruido x_{T-1} 🎲 ruido puro x_T ~ N(0,I) REVERSE PROCESS p_θ(x_{t-1} | x_t) — Eliminar ruido (aprendido) ε_θ(x_t, t) ··· ε_θ(x_t, t) x_T ruido x₀ ¡generada! La red ε_θ predice el ruido añadido en cada paso t → se resta para obtener x_{t-1}

Lo elegante es que la red neuronal \(\epsilon_\theta\) se entrena con un objetivo muy simple: predecir el ruido que se añadió en cada paso. Durante la generación, empezamos con ruido puro \(\mathbf{x}_T \sim \mathcal{N}(0, \mathbf{I})\) y aplicamos el modelo \(T\) veces para obtener una imagen limpia.

Relación con otros modelos generativos

Los modelos de difusión no surgieron en el vacío. Son parte de un ecosistema más amplio de modelos generativos, y tienen conexiones profundas con otros enfoques que hemos estudiado en este curso.

Aspecto VAEs GANs Difusión
Mecanismo Encoder-Decoder + KL Generador vs Discriminador Denoising iterativo
Espacio latente Explícito, estructurado Implícito (z → G) Cadena de Markov (T pasos)
Estabilidad ⭐⭐⭐ Muy estable ⭐ Mode collapse, inestable ⭐⭐⭐ Muy estable
Calidad visual ⭐⭐ Borrosa ⭐⭐⭐ Nítida ⭐⭐⭐ Excelente
Diversidad ⭐⭐⭐ Alta ⭐⭐ Limitada (mode collapse) ⭐⭐⭐ Alta
Velocidad ⭐⭐⭐ Un paso ⭐⭐⭐ Un paso ⭐ Lento (T pasos)
Likelihood ELBO tractable Implícita Tractable (via ELBO)
Paper seminal Kingma 2014 Goodfellow 2014 Ho et al. 2020
🔗
Difusión + VAEs
Stable Diffusion usa un VAE encoder para comprimir imágenes a un espacio latente donde opera la difusión. → Ver submódulo de Autoencoders
⚔️
Difusión vs GANs
En 2021, los modelos de difusión superaron a las GANs en FID. Hoy dominan la generación de imágenes, aunque las GANs siguen siendo más rápidas. → Ver submódulo de GANs
🏗️
U-Net como backbone
La arquitectura U-Net (del mundo de la segmentación) es la red neuronal más usada para predecir ruido en modelos de difusión. → Ver submódulo de Segmentación (U-Net)
🧠
Score Matching
La formulación de score matching (Song & Ermon, 2019) unifica difusión con SDEs estocásticas y conecta con la física estadística.
🔬 Score-Based vs DDPM: Existen dos formulaciones equivalentes de los modelos de difusión: la denoising score matching de Song & Ermon (2019) y la variational de Ho et al. (2020). Song et al. (2021) unificaron ambas con Score SDEs (arXiv:2011.13456), mostrando que son dos caras de la misma moneda.

Inspiración termodinámica

El nombre «difusión» no es casual. El proceso se inspira directamente en la termodinámica de no-equilibrio: así como las moléculas de un gas se difunden hasta alcanzar el equilibrio térmico (entropía máxima), el proceso forward lleva los datos hacia una distribución de máxima entropía (ruido gaussiano).

Baja entropía Datos (estructura) difusión Entropía media difusión Máxima entropía Ruido gaussiano

El paper original de Sohl-Dickstein et al. (2015) se titula literalmente «Deep Unsupervised Learning using Nonequilibrium Thermodynamics». La clave es que, mientras el proceso de «equilibrio» (forward) es fácil de definir matemáticamente, el proceso inverso (reverse) necesita una red neuronal para aprenderlo. Esta asimetría es lo que hace poderoso al modelo.

En termodinámica, la segunda ley dice que la entropía de un sistema aislado siempre aumenta. El proceso forward sigue esta ley: cada paso de ruido aumenta la entropía. Pero la termodinámica de no-equilibrio también nos dice que, si conocemos la dinámica del sistema, podemos invertir el proceso — al menos en teoría.

Sohl-Dickstein et al. mostraron que, bajo ciertas condiciones, el proceso reverse tiene la misma forma funcional que el forward (una gaussiana), lo que permite parametrizarlo con una red neuronal que solo necesita predecir la media y/o la varianza de cada paso reverse.

$$p_\theta(\mathbf{x}_{t-1} | \mathbf{x}_t) = \mathcal{N}\!\left(\mathbf{x}_{t-1};\; \boldsymbol{\mu}_\theta(\mathbf{x}_t, t),\; \sigma_t^2\mathbf{I}\right)$$

Taxonomía de los modelos de difusión

El campo ha evolucionado rápidamente, y hoy existen múltiples formulaciones y variantes. Estas son las familias principales:

Familia Idea clave Ejemplos Referencia
DDPM Proceso discreto de Markov, predecir ruido \(\epsilon\) DDPM, Improved DDPM Ho et al. 2020
Score-Based (NCSN) Estimar el gradiente del log-probability (score) NCSN, NCSNv2 Song & Ermon 2019
Score SDE Unificación continua via SDEs estocásticas VP-SDE, VE-SDE, sub-VP Song et al. 2021
Latent Diffusion Difusión en espacio latente comprimido (VAE) Stable Diffusion, SDXL Rombach et al. 2022
Flow Matching Campos vectoriales en lugar de score; paths rectas Flux, SD3, SiT Lipman et al. 2023
Consistency Models Mapeo directo de cualquier punto ruidoso a x₀ CM, LCM Song et al. 2023
🧭 Hoja de ruta: En las siguientes secciones cubriremos los fundamentos matemáticos (forward/reverse process), el entrenamiento práctico con código, las aplicaciones más relevantes, los modelos más influyentes (Stable Diffusion, DALL-E, etc.), y una comparación detallada con las GANs.

Proceso Forward: destruir los datos

El proceso forward es la parte «fácil»: definimos una cadena de Markov que añade ruido gaussiano gradualmente a lo largo de \(T\) pasos. No hay parámetros que aprender aquí — todo está predefinido por un noise schedule \(\{\beta_1, \beta_2, \ldots, \beta_T\}\).

📐 Transición forward

En cada paso \(t\), añadimos ruido según:

$$q(\mathbf{x}_t | \mathbf{x}_{t-1}) = \mathcal{N}\!\left(\mathbf{x}_t;\; \sqrt{1-\beta_t}\,\mathbf{x}_{t-1},\; \beta_t\,\mathbf{I}\right)$$

donde \(\beta_t \in (0, 1)\) es pequeño (típicamente entre 0.0001 y 0.02). Cada paso encoge ligeramente la señal (\(\sqrt{1-\beta_t}\)) y le suma un poco de ruido (\(\beta_t\)).

El truco de la reparametrización

Una propiedad crucial: no necesitamos simular los \(T\) pasos secuencialmente. Podemos saltar directamente a cualquier paso \(t\) desde \(\mathbf{x}_0\):

$$q(\mathbf{x}_t | \mathbf{x}_0) = \mathcal{N}\!\left(\mathbf{x}_t;\; \sqrt{\bar\alpha_t}\,\mathbf{x}_0,\; (1-\bar\alpha_t)\,\mathbf{I}\right)$$

donde definimos:

1
\(\alpha_t = 1 - \beta_t\) — fracción de señal preservada en paso \(t\)
2
\(\bar\alpha_t = \prod_{s=1}^{t} \alpha_s\) — fracción acumulada de señal original
3
\(\mathbf{x}_t = \sqrt{\bar\alpha_t}\,\mathbf{x}_0 + \sqrt{1-\bar\alpha_t}\,\boldsymbol{\epsilon}\), con \(\boldsymbol{\epsilon} \sim \mathcal{N}(0, \mathbf{I})\)
💡 ¿Por qué es tan útil? Esto permite entrenar el modelo muestreando cualquier \(t\) aleatorio y calculando \(\mathbf{x}_t\) en un solo paso. Sin esta propiedad, el entrenamiento sería prohibitivamente lento (habría que simular toda la cadena cada vez).

Noise Schedules

La elección de \(\beta_t\) determina cuán rápido se destruyen los datos. Se han propuesto varios tipos de schedule:

Schedule Fórmula Propiedades Usado en
Linear \(\beta_t\) crece linealmente de \(\beta_1\) a \(\beta_T\) Simple, destruye señal rápido al final DDPM original
Cosine \(\bar\alpha_t = \cos^2\!\left(\frac{t/T + s}{1+s}\cdot\frac{\pi}{2}\right)\) Más suave, preserva estructura más tiempo Improved DDPM
Sigmoid Sigmoide escalada sobre \([0, T]\) Compromiso entre linear y cosine Algunos LDMs
Learned La red aprende \(\beta_t\) durante el entrenamiento Adaptativo, más complejo Improved DDPM

🧪 Visualizador de Noise Schedule

Compara cómo diferentes schedules destruyen la señal original a lo largo de \(T\) pasos.

Proceso Reverse: aprender a denoizar

El corazón del modelo de difusión es el proceso reverse: una cadena de Markov paramétrica que aprende a revertir cada paso de ruido.

📐 Transición reverse

$$p_\theta(\mathbf{x}_{t-1} | \mathbf{x}_t) = \mathcal{N}\!\left(\mathbf{x}_{t-1};\; \boldsymbol{\mu}_\theta(\mathbf{x}_t, t),\; \sigma_t^2\mathbf{I}\right)$$

La red neuronal \(\boldsymbol{\mu}_\theta\) recibe la imagen ruidosa \(\mathbf{x}_t\) y el timestep \(t\) (codificado con embeddings sinusoidales), y predice la media del paso anterior.

La parametrización \(\epsilon\)

Ho et al. (2020) descubrieron que es más eficiente parametrizar la red para que prediga el ruido \(\boldsymbol{\epsilon}\) en lugar de la media \(\boldsymbol{\mu}\). La relación es:

$$\boldsymbol{\mu}_\theta(\mathbf{x}_t, t) = \frac{1}{\sqrt{\alpha_t}}\left(\mathbf{x}_t - \frac{\beta_t}{\sqrt{1-\bar\alpha_t}}\,\boldsymbol{\epsilon}_\theta(\mathbf{x}_t, t)\right)$$

Así, la red \(\boldsymbol{\epsilon}_\theta\) simplemente predice «¿qué ruido se añadió?» — un objetivo intuitivo y fácil de entrenar.

Existen tres parametrizaciones principales:

  • ε-prediction (DDPM): la red predice el ruido \(\boldsymbol{\epsilon}\). La más común.
  • x₀-prediction: la red predice directamente la imagen limpia \(\mathbf{x}_0\). Usada en algunos modelos latentes.
  • v-prediction (Salimans & Ho, 2022): la red predice \(\mathbf{v} = \sqrt{\bar\alpha_t}\boldsymbol{\epsilon} - \sqrt{1-\bar\alpha_t}\mathbf{x}_0\). Mejora la estabilidad numérica, usada en SDXL.

Las tres son matemáticamente equivalentes — se puede convertir entre ellas. La elección afecta la estabilidad del entrenamiento y la calidad de las muestras.

La arquitectura: U-Net para difusión

La red \(\boldsymbol{\epsilon}_\theta\) necesita una arquitectura que reciba una imagen ruidosa y devuelva un tensor del mismo tamaño (el ruido predicho). La elección natural es la U-Net, originalmente diseñada para segmentación de imágenes.

U-Net para Difusión (con time embedding + attention) Conv + GN ResBlock 64×64×C ↓ 2× ResBlock 32×32 Res 16×16 Self-Attention + ResBlock · 8×8 Res 16×16 ↑ 2× ResBlock 32×32 ↑ 2× Conv + GN ResBlock 64×64×C skip connection (concat) Time Embedding sinusoidal + MLP t → emb(t) → +ResBlock (inyectado en cada bloque) Cross-Attention texto/clase → K,V (condicionamiento) x_t (entrada ruidosa) ε_θ (ruido predicho) LEYENDA Encoder (downsampling) Decoder (upsampling) Attention (bottleneck)

La U-Net de difusión tiene tres modificaciones clave respecto a la U-Net clásica de segmentación:

Time Embedding
El timestep \(t\) se codifica con embeddings sinusoidales (tipo Transformer) y se inyecta en cada ResBlock via AdaGN (Adaptive Group Normalization).
🔍
Self-Attention
Se añaden capas de self-attention en las resoluciones bajas (16×16, 8×8) para capturar dependencias globales.
📝
Cross-Attention
Para generación condicional (texto→imagen), las representaciones del texto se inyectan via cross-attention: imagen=Q, texto=K,V.
🔄
ResBlocks + GroupNorm
Bloques residuales con Group Normalization (en lugar de BatchNorm) para estabilidad con batch sizes pequeños.

La ELBO y la función de pérdida

¿Cómo entrenamos un modelo de difusión? La conexión con los VAEs es profunda: ambos optimizan una Evidence Lower Bound (ELBO) sobre la log-verosimilitud de los datos.

📐 ELBO para difusión

$$\log p(\mathbf{x}_0) \geq \mathbb{E}_q\!\left[-\log\frac{q(\mathbf{x}_{1:T}|\mathbf{x}_0)}{p_\theta(\mathbf{x}_{0:T})}\right] = \text{ELBO}$$

Descomponiendo la ELBO obtenemos una suma de términos de KL:

$$L = \underbrace{D_\text{KL}(q(\mathbf{x}_T|\mathbf{x}_0)\|p(\mathbf{x}_T))}_{L_T\;\text{(prior matching)}} + \sum_{t=2}^{T}\underbrace{D_\text{KL}(q(\mathbf{x}_{t-1}|\mathbf{x}_t,\mathbf{x}_0)\|p_\theta(\mathbf{x}_{t-1}|\mathbf{x}_t))}_{L_{t-1}\;\text{(denoising matching)}} - \underbrace{\log p_\theta(\mathbf{x}_0|\mathbf{x}_1)}_{L_0\;\text{(reconstruction)}}$$
  • \(L_T\) (Prior matching): asegura que al final del forward process obtengamos ruido puro \(\mathcal{N}(0,I)\). Es constante (no depende de \(\theta\)), así que se ignora durante el entrenamiento.
  • \(L_{t-1}\) (Denoising matching): mide cuán bien nuestro modelo reverse \(p_\theta(\mathbf{x}_{t-1}|\mathbf{x}_t)\) aproxima el verdadero reverse \(q(\mathbf{x}_{t-1}|\mathbf{x}_t,\mathbf{x}_0)\). Este es el término clave.
  • \(L_0\) (Reconstruction): calidad de la reconstrucción final.

El posterior \(q(\mathbf{x}_{t-1}|\mathbf{x}_t, \mathbf{x}_0)\) es tractable — tiene forma gaussiana con media y varianza cerradas. Esto hace que cada \(L_{t-1}\) sea simplemente la distancia KL entre dos gaussianas (también cerrada).

La pérdida simplificada

Ho et al. (2020) demostraron que podemos simplificar toda la ELBO a una pérdida de predicción de ruido increíblemente simple:

$$L_\text{simple} = \mathbb{E}_{t,\,\mathbf{x}_0,\,\boldsymbol{\epsilon}}\left[\left\|\boldsymbol{\epsilon} - \boldsymbol{\epsilon}_\theta\!\left(\sqrt{\bar\alpha_t}\,\mathbf{x}_0 + \sqrt{1-\bar\alpha_t}\,\boldsymbol{\epsilon},\; t\right)\right\|^2\right]$$

En palabras:

1
Toma una imagen limpia \(\mathbf{x}_0\) del dataset
2
Muestrea un timestep \(t \sim \text{Uniform}(1, T)\)
3
Muestrea ruido \(\boldsymbol{\epsilon} \sim \mathcal{N}(0, \mathbf{I})\)
4
Crea la versión ruidosa: \(\mathbf{x}_t = \sqrt{\bar\alpha_t}\,\mathbf{x}_0 + \sqrt{1-\bar\alpha_t}\,\boldsymbol{\epsilon}\)
5
Entrena la red para predecir \(\boldsymbol{\epsilon}\): minimiza \(\|\boldsymbol{\epsilon} - \boldsymbol{\epsilon}_\theta(\mathbf{x}_t, t)\|^2\)
✨ Belleza del resultado: A pesar de toda la maquinaria matemática (cadenas de Markov, ELBO, KL entre gaussianas), la función de pérdida final es simplemente un MSE entre el ruido real y el ruido predicho. Esto la hace extremadamente estable de entrenar — una de las grandes ventajas sobre las GANs.

Score Matching: la otra cara de la moneda

Existe una formulación equivalente de los modelos de difusión basada en estimación de scores (gradientes de la log-densidad).

📐 El score function

Para una distribución \(p(\mathbf{x})\), el score es el gradiente del log-likelihood respecto a los datos:

$$\mathbf{s}(\mathbf{x}) = \nabla_{\mathbf{x}} \log p(\mathbf{x})$$

Intuitivamente, el score apunta hacia donde la densidad de probabilidad aumenta. Si seguimos el score iterativamente (Langevin dynamics), nos movemos hacia regiones de alta probabilidad = datos reales.

Langevin dynamics es un algoritmo MCMC que genera muestras de una distribución usando solo su score:

$$\mathbf{x}_{i+1} = \mathbf{x}_i + \frac{\delta}{2}\nabla_{\mathbf{x}}\log p(\mathbf{x}_i) + \sqrt{\delta}\,\boldsymbol{\eta}_i, \quad \boldsymbol{\eta}_i \sim \mathcal{N}(0, \mathbf{I})$$

Para \(\delta \to 0\) e infinitas iteraciones, \(\mathbf{x}_i\) converge a una muestra de \(p(\mathbf{x})\). En la práctica, Song & Ermon (2019) propusieron usar múltiples niveles de ruido (annealed Langevin) para mejorar la convergencia.

La conexión elegante es que predecir ruido ≡ estimar el score:

$$\boldsymbol{\epsilon}_\theta(\mathbf{x}_t, t) = -\sqrt{1-\bar\alpha_t}\;\nabla_{\mathbf{x}_t}\log q(\mathbf{x}_t)$$

Song et al. (2021) unificaron ambas visiones en un marco continuo basado en Stochastic Differential Equations (SDEs), donde el proceso forward es una SDE y el reverse es otra SDE con el score aprendido.

🧩 La unificación de Song et al.: Forward SDE: \(d\mathbf{x} = \mathbf{f}(\mathbf{x},t)\,dt + g(t)\,d\mathbf{w}\)
Reverse SDE: \(d\mathbf{x} = [\mathbf{f}(\mathbf{x},t) - g(t)^2\nabla_\mathbf{x}\log p_t(\mathbf{x})]\,dt + g(t)\,d\bar{\mathbf{w}}\)
📄 Score-Based Generative Modeling through SDEs — arXiv:2011.13456

Algoritmo de entrenamiento

El entrenamiento de un modelo de difusión es sorprendentemente simple comparado con las GANs: no hay juego adversarial, no hay mode collapse, y la función de pérdida es un simple MSE.

Training Loop — DDPM 1. Sample x₀ x₀ ~ dataset 2. Sample t t ~ U(1, T) 3. Sample ε ε ~ N(0, I) 4. Make x_t x_t = √ᾱ_t·x₀ + √(1-ᾱ_t)·ε 5. Gradient step L = ‖ε - ε_θ(x_t, t)‖² θ ← θ - η∇_θ L repeat
🎯 Comparación con GANs: Mientras las GANs requieren alternar entre actualizar D y G, con riesgo de desequilibrio y mode collapse, el entrenamiento de difusión es un simple bucle de regresión. No hay adversario, no hay inestabilidad inherente. Ver el submódulo de GANs para más detalle.

Sampling: DDPM (estocástico)

Una vez entrenado el modelo, ¿cómo generamos imágenes nuevas? El sampling de DDPM sigue el proceso reverse estocástico:

1
Muestrea \(\mathbf{x}_T \sim \mathcal{N}(0, \mathbf{I})\) — ruido puro
2
Para \(t = T, T-1, \ldots, 1\):
$$\mathbf{x}_{t-1} = \frac{1}{\sqrt{\alpha_t}}\left(\mathbf{x}_t - \frac{1-\alpha_t}{\sqrt{1-\bar\alpha_t}}\boldsymbol{\epsilon}_\theta(\mathbf{x}_t, t)\right) + \sigma_t\,\mathbf{z}$$
donde \(\mathbf{z} \sim \mathcal{N}(0, \mathbf{I})\) si \(t > 1\), sino \(\mathbf{z} = 0\).
3
Devuelve \(\mathbf{x}_0\) — ¡la imagen generada!
⚠️ Problema: Si \(T = 1000\), necesitamos 1000 evaluaciones de la red neuronal para generar una sola imagen. Esto es muy lento (∼60 segundos en una GPU). La solución: samplers acelerados.

DDIM y samplers acelerados

Song et al. (2021) descubrieron que se puede hacer el sampling determinista, saltando pasos sin perder calidad. Esto dio lugar a una familia de samplers rápidos.

Sampler Pasos típicos Tipo Calidad Velocidad
DDPM 1000 Estocástico ⭐⭐⭐ Referencia ⭐ Muy lento
DDIM 50-100 Determinista ⭐⭐⭐ Comparable ⭐⭐ 10-20× más rápido
DPM-Solver 20-50 ODE solver ⭐⭐⭐ Excelente ⭐⭐⭐ Rápido
DPM-Solver++ 15-25 ODE solver (2do orden) ⭐⭐⭐ Excelente ⭐⭐⭐ Muy rápido
Euler 20-50 ODE (1er orden) ⭐⭐ Buena ⭐⭐⭐ Rápido
LCM 2-8 Consistency distillation ⭐⭐ Buena-Muy buena ⭐⭐⭐⭐ Casi real-time

DDIM redefine el proceso forward como no-markoviano, permitiendo una fórmula de sampling que no requiere ruido en cada paso:

$$\mathbf{x}_{t-1} = \sqrt{\bar\alpha_{t-1}}\underbrace{\left(\frac{\mathbf{x}_t - \sqrt{1-\bar\alpha_t}\,\boldsymbol{\epsilon}_\theta(\mathbf{x}_t,t)}{\sqrt{\bar\alpha_t}}\right)}_{\text{«predicción de }\mathbf{x}_0\text{»}} + \sqrt{1-\bar\alpha_{t-1} - \sigma_t^2}\cdot\boldsymbol{\epsilon}_\theta(\mathbf{x}_t,t) + \sigma_t\boldsymbol{\epsilon}_t$$

Si \(\sigma_t = 0\), el sampling es completamente determinista: mismo ruido inicial → misma imagen final. Además, podemos usar un subconjunto de pasos (e.g., \(t \in \{T, T-\Delta, T-2\Delta, \ldots, 0\}\)) para acelerar.

Guidance: generación condicional

En la práctica, queremos controlar qué genera el modelo (e.g., «un gato en la nieve»). Existen dos enfoques principales:

🎯 Classifier Guidance
Usa un clasificador externo \(p(y|\mathbf{x}_t)\) entrenado sobre datos ruidosos. El gradiente del clasificador empuja las muestras hacia la clase deseada:
$$\hat{\boldsymbol{\epsilon}} = \boldsymbol{\epsilon}_\theta(\mathbf{x}_t,t) - s\cdot\sqrt{1-\bar\alpha_t}\,\nabla_{\mathbf{x}_t}\log p(y|\mathbf{x}_t)$$
Desventaja: necesita entrenar un clasificador separado sobre datos ruidosos.
📄 Dhariwal & Nichol, 2021
✨ Classifier-Free Guidance (CFG)
Entrena el mismo modelo con y sin condición (dropout del prompt). Durante sampling, interpola entre ambos:
$$\hat{\boldsymbol{\epsilon}} = \boldsymbol{\epsilon}_\theta(\mathbf{x}_t, \varnothing) + w\!\left[\boldsymbol{\epsilon}_\theta(\mathbf{x}_t, c) - \boldsymbol{\epsilon}_\theta(\mathbf{x}_t, \varnothing)\right]$$
\(w > 1\) amplifica el efecto del prompt. Método dominante en la práctica.
📄 Ho & Salimans, 2022
🎨 El parámetro CFG scale (w): Un valor de \(w=1\) da la distribución original; \(w=7.5\) es típico para texto-a-imagen; valores altos (\(w>15\)) dan imágenes más fieles al prompt pero menos diversas y con artefactos de saturación. Es el equivalente moderno del temperature en LLMs.

Widget: simulador de denoising

Explora cómo el proceso de denoising reconstruye una señal a partir de ruido puro. Ajusta el número de pasos y el noise schedule para ver el efecto.

🧪 Simulador de Denoising

Implementación: DDPM simplificado

Veamos una implementación completa de un modelo de difusión simplificado. El código incluye el noise schedule, la U-Net simplificada, el loop de entrenamiento y el sampling.

import torch
import torch.nn as nn
import torch.nn.functional as F
import math

# ─── Noise Schedule ───
def linear_beta_schedule(T, beta_start=1e-4, beta_end=0.02):
    return torch.linspace(beta_start, beta_end, T)

def cosine_beta_schedule(T, s=0.008):
    steps = torch.arange(T + 1, dtype=torch.float64)
    alphas_cumprod = torch.cos(((steps / T) + s) / (1 + s) * math.pi * 0.5) ** 2
    alphas_cumprod = alphas_cumprod / alphas_cumprod[0]
    betas = 1 - (alphas_cumprod[1:] / alphas_cumprod[:-1])
    return torch.clip(betas, 0.0001, 0.9999).float()

# ─── Sinusoidal Time Embedding ───
class SinusoidalPosEmb(nn.Module):
    def __init__(self, dim):
        super().__init__()
        self.dim = dim

    def forward(self, t):
        device = t.device
        half_dim = self.dim // 2
        emb = math.log(10000) / (half_dim - 1)
        emb = torch.exp(torch.arange(half_dim, device=device) * -emb)
        emb = t[:, None] * emb[None, :]
        return torch.cat([emb.sin(), emb.cos()], dim=-1)

# ─── Simple U-Net Block ───
class Block(nn.Module):
    def __init__(self, in_ch, out_ch, time_dim):
        super().__init__()
        self.conv1 = nn.Conv2d(in_ch, out_ch, 3, padding=1)
        self.conv2 = nn.Conv2d(out_ch, out_ch, 3, padding=1)
        self.gn1 = nn.GroupNorm(8, out_ch)
        self.gn2 = nn.GroupNorm(8, out_ch)
        self.time_mlp = nn.Linear(time_dim, out_ch)
        self.res_conv = nn.Conv2d(in_ch, out_ch, 1) if in_ch != out_ch else nn.Identity()

    def forward(self, x, t_emb):
        h = self.gn1(F.silu(self.conv1(x)))
        # Inject time embedding
        h = h + self.time_mlp(F.silu(t_emb))[:, :, None, None]
        h = self.gn2(F.silu(self.conv2(h)))
        return h + self.res_conv(x)

# ─── Simplified U-Net ───
class SimpleUNet(nn.Module):
    def __init__(self, in_channels=1, base_channels=64, time_dim=256):
        super().__init__()
        self.time_mlp = nn.Sequential(
            SinusoidalPosEmb(time_dim),
            nn.Linear(time_dim, time_dim),
            nn.SiLU(),
        )
        # Encoder
        self.enc1 = Block(in_channels, base_channels, time_dim)
        self.enc2 = Block(base_channels, base_channels * 2, time_dim)
        self.pool = nn.MaxPool2d(2)

        # Bottleneck
        self.bot = Block(base_channels * 2, base_channels * 2, time_dim)

        # Decoder
        self.up = nn.Upsample(scale_factor=2)
        self.dec2 = Block(base_channels * 4, base_channels, time_dim)  # skip concat
        self.dec1 = Block(base_channels * 2, base_channels, time_dim)

        self.out = nn.Conv2d(base_channels, in_channels, 1)

    def forward(self, x, t):
        t_emb = self.time_mlp(t)
        # Encoder
        e1 = self.enc1(x, t_emb)
        e2 = self.enc2(self.pool(e1), t_emb)
        # Bottleneck
        b = self.bot(self.pool(e2), t_emb)
        # Decoder + skip connections
        d2 = self.dec2(torch.cat([self.up(b), e2], dim=1), t_emb)
        d1 = self.dec1(torch.cat([self.up(d2), e1], dim=1), t_emb)
        return self.out(d1)

# ─── Diffusion Model ───
class DDPM:
    def __init__(self, model, T=1000, device='cuda'):
        self.model = model.to(device)
        self.T = T
        self.device = device

        # Precompute schedule
        betas = cosine_beta_schedule(T).to(device)
        alphas = 1.0 - betas
        alphas_cumprod = torch.cumprod(alphas, dim=0)

        self.betas = betas
        self.sqrt_alphas = torch.sqrt(alphas)
        self.sqrt_alphas_cumprod = torch.sqrt(alphas_cumprod)
        self.sqrt_one_minus_alphas_cumprod = torch.sqrt(1.0 - alphas_cumprod)
        self.posterior_variance = betas * (1.0 - torch.cat([torch.tensor([1.0], device=device), alphas_cumprod[:-1]])) / (1.0 - alphas_cumprod)

    def q_sample(self, x_0, t, noise=None):
        """Forward process: add noise to x_0 at timestep t"""
        if noise is None:
            noise = torch.randn_like(x_0)
        return (self.sqrt_alphas_cumprod[t][:, None, None, None] * x_0 +
                self.sqrt_one_minus_alphas_cumprod[t][:, None, None, None] * noise)

    def train_loss(self, x_0):
        """Compute training loss: simple MSE on noise prediction"""
        t = torch.randint(0, self.T, (x_0.shape[0],), device=self.device)
        noise = torch.randn_like(x_0)
        x_t = self.q_sample(x_0, t, noise)
        predicted_noise = self.model(x_t, t.float())
        return F.mse_loss(predicted_noise, noise)

    @torch.no_grad()
    def sample(self, shape):
        """Generate samples via reverse process (DDPM sampling)"""
        x = torch.randn(shape, device=self.device)
        for t in reversed(range(self.T)):
            t_batch = torch.full((shape[0],), t, device=self.device, dtype=torch.float)
            predicted_noise = self.model(x, t_batch)

            # Compute x_{t-1}
            coef1 = 1.0 / self.sqrt_alphas[t]
            coef2 = (1 - self.betas[t] / self.sqrt_one_minus_alphas_cumprod[t])
            mean = coef1 * (x - coef2 * predicted_noise)

            if t > 0:
                noise = torch.randn_like(x)
                x = mean + torch.sqrt(self.posterior_variance[t]) * noise
            else:
                x = mean
        return x

# ─── Training Loop ───
# model = SimpleUNet(in_channels=1)
# ddpm = DDPM(model, T=1000)
# optimizer = torch.optim.Adam(model.parameters(), lr=2e-4)
#
# for epoch in range(100):
#     for batch in dataloader:
#         x_0 = batch.to('cuda')  # Normalize to [-1, 1]
#         loss = ddpm.train_loss(x_0)
#         optimizer.zero_grad()
#         loss.backward()
#         optimizer.step()
#
#     # Generate samples
#     samples = ddpm.sample((16, 1, 28, 28))  # e.g., MNIST
import tensorflow as tf
import numpy as np
import math

# ─── Noise Schedule ───
def cosine_beta_schedule(T, s=0.008):
    steps = np.arange(T + 1, dtype=np.float64)
    alphas_cumprod = np.cos(((steps / T) + s) / (1 + s) * math.pi * 0.5) ** 2
    alphas_cumprod = alphas_cumprod / alphas_cumprod[0]
    betas = 1 - (alphas_cumprod[1:] / alphas_cumprod[:-1])
    return tf.constant(np.clip(betas, 1e-4, 0.9999), dtype=tf.float32)

# ─── Sinusoidal Time Embedding ───
class SinusoidalPosEmb(tf.keras.layers.Layer):
    def __init__(self, dim):
        super().__init__()
        self.dim = dim

    def call(self, t):
        half_dim = self.dim // 2
        emb = math.log(10000) / (half_dim - 1)
        emb = tf.exp(tf.range(half_dim, dtype=tf.float32) * -emb)
        emb = t[:, None] * emb[None, :]
        return tf.concat([tf.sin(emb), tf.cos(emb)], axis=-1)

# ─── Simple U-Net (Keras) ───
def build_unet(image_size=28, channels=1, base_ch=64, time_dim=256):
    # Inputs
    x_input = tf.keras.Input(shape=(image_size, image_size, channels))
    t_input = tf.keras.Input(shape=())

    # Time embedding
    t_emb = SinusoidalPosEmb(time_dim)(t_input)
    t_emb = tf.keras.layers.Dense(time_dim, activation='swish')(t_emb)

    # Encoder
    h = tf.keras.layers.Conv2D(base_ch, 3, padding='same', activation='swish')(x_input)
    t_proj = tf.keras.layers.Dense(base_ch)(t_emb)
    h = h + t_proj[:, None, None, :]
    skip1 = h

    h = tf.keras.layers.MaxPooling2D(2)(h)
    h = tf.keras.layers.Conv2D(base_ch * 2, 3, padding='same', activation='swish')(h)
    t_proj2 = tf.keras.layers.Dense(base_ch * 2)(t_emb)
    h = h + t_proj2[:, None, None, :]
    skip2 = h

    # Bottleneck
    h = tf.keras.layers.MaxPooling2D(2)(h)
    h = tf.keras.layers.Conv2D(base_ch * 2, 3, padding='same', activation='swish')(h)

    # Decoder
    h = tf.keras.layers.UpSampling2D(2)(h)
    h = tf.keras.layers.Concatenate()([h, skip2])
    h = tf.keras.layers.Conv2D(base_ch, 3, padding='same', activation='swish')(h)

    h = tf.keras.layers.UpSampling2D(2)(h)
    h = tf.keras.layers.Concatenate()([h, skip1])
    h = tf.keras.layers.Conv2D(base_ch, 3, padding='same', activation='swish')(h)

    output = tf.keras.layers.Conv2D(channels, 1)(h)
    return tf.keras.Model([x_input, t_input], output)

# ─── DDPM Training ───
class DDPMTrainer:
    def __init__(self, model, T=1000):
        self.model = model
        self.T = T
        betas = cosine_beta_schedule(T)
        alphas = 1.0 - betas
        self.alphas_cumprod = tf.math.cumprod(alphas)
        self.sqrt_alphas_cumprod = tf.sqrt(self.alphas_cumprod)
        self.sqrt_one_minus_alphas_cumprod = tf.sqrt(1.0 - self.alphas_cumprod)

    @tf.function
    def train_step(self, x_0, optimizer):
        batch_size = tf.shape(x_0)[0]
        t = tf.random.uniform((batch_size,), 0, self.T, dtype=tf.int32)
        noise = tf.random.normal(tf.shape(x_0))

        sqrt_alpha = tf.gather(self.sqrt_alphas_cumprod, t)
        sqrt_one_minus = tf.gather(self.sqrt_one_minus_alphas_cumprod, t)
        x_t = sqrt_alpha[:, None, None, None] * x_0 + sqrt_one_minus[:, None, None, None] * noise

        with tf.GradientTape() as tape:
            pred_noise = self.model([x_t, tf.cast(t, tf.float32)], training=True)
            loss = tf.reduce_mean(tf.square(noise - pred_noise))

        grads = tape.gradient(loss, self.model.trainable_variables)
        optimizer.apply_gradients(zip(grads, self.model.trainable_variables))
        return loss

# model = build_unet()
# trainer = DDPMTrainer(model, T=1000)
# optimizer = tf.keras.optimizers.Adam(2e-4)
# for epoch in range(100):
#     for batch in dataset:
#         loss = trainer.train_step(batch, optimizer)
📦 En la práctica: Para entrenar modelos de difusión serios, se recomienda usar librerías como 🤗 Diffusers (HuggingFace), que incluye DDPM, DDIM, Stable Diffusion y cientos de modelos preentrenados con una API elegante y pipelines listas para usar.

Trucos de entrenamiento

Aunque el entrenamiento de difusión es más estable que el de GANs, hay varias prácticas que mejoran significativamente los resultados:

Truco Descripción Efecto
EMA (Exponential Moving Average) Mantener una copia promediada exponencialmente de los pesos para sampling Muestras más suaves y estables
Cosine schedule Usar schedule coseno en lugar de lineal Mejor preservación de estructura en pasos tempranos
v-prediction Predecir \(\mathbf{v}\) en lugar de \(\boldsymbol{\epsilon}\) Mejor estabilidad numérica, especialmente para high-resolution
Min-SNR weighting Ponderar la pérdida según el SNR de cada timestep Balancear contribución de diferentes niveles de ruido
Offset noise Añadir ruido con media no-cero Permite generar imágenes muy oscuras o muy claras
Mixed precision (fp16/bf16) Entrenamiento en precisión mixta 2× más rápido, menos VRAM
Gradient accumulation Acumular gradientes sobre múltiples mini-batches Simular batch sizes grandes en GPUs limitadas

Aplicaciones en generación de imágenes

Los modelos de difusión se han convertido en el estándar para la generación de imágenes, superando a las GANs tanto en calidad como en diversidad. Estas son las aplicaciones principales:

🎨
Text-to-Image
Generar imágenes a partir de texto. La aplicación estrella.
"un gato astronauta" 🖼️ imagen
🖌️
Inpainting
Rellenar regiones borradas de una imagen de forma coherente.
imagen + máscara imagen completa
🔍
Super-resolución
Aumentar la resolución preservando detalles realistas.
64×64 512×512
✏️
Image Editing
Editar imágenes con instrucciones textuales (InstructPix2Pix).
imagen + "hazlo invierno" imagen editada
🔄
Image-to-Image
Transformar bocetos, mapas de segmentación o poses en imágenes realistas.
boceto + prompt imagen detallada
🪄
Outpainting
Extender una imagen más allá de sus bordes originales.
imagen parcial imagen expandida

Text-to-Image: la pipeline completa

La generación texto-a-imagen es la aplicación más impactante de los modelos de difusión. Veamos cómo funciona la pipeline completa, tomando Stable Diffusion como ejemplo:

Text Encoder CLIP / T5 "a cat in space" → tokens z_T ~ N(0,I) latent noise 64×64×4 U-Net Denoiser T steps × (self-attn + cross-attn + time) + classifier-free guidance (w=7.5) z₀ (latente) denoised latent 64×64×4 VAE Decoder latent → pixel 64×64 → 512×512 🖼️ 512×512 Condicionamiento Difusión en espacio latente Decodificación Pipeline de Latent Diffusion Model (Stable Diffusion) — Rombach et al. 2022
🔗 Conexión con Autoencoders: El VAE Encoder/Decoder de Stable Diffusion está directamente inspirado en los Autoencoders Variacionales que estudiamos en el submódulo anterior. El encoder comprime imágenes 512×512 a latentes 64×64×4 (compresión 48×), y la difusión opera en este espacio comprimido, haciéndola ∼50× más eficiente que operar en píxeles directamente.

Más allá de las imágenes

Los modelos de difusión no se limitan a imágenes. El mismo principio (destruir con ruido + reconstruir) se ha aplicado con éxito a una variedad sorprendente de dominios:

Dominio Descripción Modelos / Papers Impacto
🎬 Vídeo Generación y edición de vídeos a partir de texto Sora (OpenAI), Runway Gen-3, Pika, Kling ⭐⭐⭐ Revolucionario
🎵 Audio / Música Generación de audio, voz y música AudioLDM, MusicLDM, Riffusion, Stable Audio ⭐⭐⭐ Creciente
🧊 3D Generación de objetos y escenas 3D DreamFusion, Magic3D, Point-E, Shap-E ⭐⭐ Emergente
🧬 Proteínas Diseño de nuevas estructuras proteicas RFdiffusion (Baker Lab), FrameDiff ⭐⭐⭐ Impacto médico
💊 Moléculas Descubrimiento de fármacos y materiales DiffDock, GeoDiff, EDM ⭐⭐⭐ Farmacéutica
🏥 Imágenes médicas Aumento de datos, reconstrucción, segmentación MedSegDiff, DiffusionMBIR ⭐⭐ Diagnóstico
🤖 Robótica Planificación de trayectorias y políticas Diffusion Policy, DALL-E-Bot ⭐⭐ Innovador
📊 Datos tabulares Generación de datos sintéticos tabulares TabDDPM, STaSy ⭐⭐ Privacidad + ML

Diffusion Transformers (DiT)

Una de las evoluciones más importantes del campo: reemplazar la U-Net por un Transformer como backbone de denoising. Esto combina la potencia de la difusión con la escalabilidad de los Transformers.

Diffusion Transformer (DiT) — Peebles & Xie, 2023 Noisy Latent z_t (32×32×4) ↓ Patchify 2×2 → 256 tokens + Pos Emb + t embedding + class/text adaLN-Zero condicionamiento N × DiT Blocks Multi-Head Self-Attention Pointwise FFN (MLP) N = 12-28 bloques Unpatchify → ε_θ o v_θ noise prediction 🖼️ DiT reemplaza la U-Net por un Vision Transformer (ViT) estándar Usado en: Sora (OpenAI), Stable Diffusion 3, Flux, HunyuanDiT · 📄 arXiv:2212.09748

🔑 ¿Por qué DiT?

  • Escalabilidad: Los Transformers escalan mejor con más parámetros y datos que las U-Nets (leyes de escala tipo GPT).
  • Simplicidad: Sin las complejidades de U-Net (skip connections, upsampling/downsampling). Es un ViT estándar con patches.
  • Condicionamiento flexible: adaLN-Zero permite inyectar timestep y condición de forma uniforme.
  • Unificación: El mismo backbone puede manejar imágenes, vídeo, y otros datos tokenizados.
🧠 Conexión con Transformers: Si quieres profundizar en la arquitectura Transformer (attention, multi-head, positional encoding), visita el submódulo de Transformers. DiT aplica exactamente esa arquitectura al problema de denoising.

Generación de vídeo con difusión

La extensión de difusión a vídeo es uno de los avances más impresionantes del campo. El principio es el mismo: añadir ruido a secuencias de frames y aprender a denoizarlas, pero con atención temporal adicional para mantener la coherencia.

🎬
Sora
OpenAI. DiT escalado a vídeo de hasta 60s. Entiende física y 3D. 2024 · Modelo cerrado
🎥
Runway Gen-3
Vídeo de alta calidad con control de cámara y estilo. 2024 · Comercial
🎞️
Stable Video
Stability AI. Difusión latente temporal. Open-weight. arXiv:2311.15127
📽️
Kling / Pika
Modelos asiáticos y startups compitiendo con calidad comparable. 2024

El enfoque general extiende la difusión de imágenes de dos formas:

  • Atención temporal: Además de la self-attention espacial (dentro de un frame), se añade atención a lo largo del eje temporal (entre frames). Esto asegura coherencia de movimiento.
  • 3D patches: En los modelos DiT para vídeo (como Sora), se usan patches espacio-temporales 2×2×n, donde n es el número de frames. El Transformer procesa todos los tokens espacio-temporales conjuntamente.
  • Cascaded generation: Generar primero a baja resolución y luego super-resolver con un segundo modelo de difusión (usado en Imagen Video).

El reto principal: consistencia temporal (evitar flickering y cambios bruscos entre frames).

Difusión en ciencia y medicina

Los modelos de difusión han encontrado aplicaciones transformadoras en la ciencia, especialmente en biología y química computacional:

🧬 RFdiffusion — Diseño de proteínas
El laboratorio de David Baker (Nobel de Química 2024) usa difusión sobre estructuras 3D de proteínas. El modelo genera nuevas secuencias de aminoácidos con estructuras funcionales nunca vistas en la naturaleza.
📄 Watson et al. 2023 · Nature · RFdiffusion
💊 DiffDock — Acoplamiento molecular
Difusión sobre las poses de acoplamiento fármaco-proteína (molecular docking). El modelo genera la pose óptima de un fármaco dentro del sitio activo de una proteína, acelerando el descubrimiento de medicamentos.
📄 Corso et al. 2023 · ICLR 2023

DDPM y DDIM: los fundadores

DDPM (Ho et al., 2020) demostró que los modelos de difusión pueden generar imágenes con calidad comparable a las GANs. DDIM (Song et al., 2021) resolvió el principal problema práctico: la velocidad de sampling.

DDPM
  • 1000 pasos de sampling estocástico
  • Pérdida simplificada: MSE sobre ruido
  • Linear noise schedule
  • FID 3.17 en CIFAR-10
📄 arXiv:2006.11239 · Ho, Jain & Abbeel
DDIM
  • Sampling determinista (η=0) o estocástico
  • 50-100 pasos ≈ misma calidad que 1000 en DDPM
  • Permite interpolación en el espacio latente
  • Inversión: imagen → ruido → edición
📄 arXiv:2010.02502 · Song et al.

Stable Diffusion: la revolución open-source

Stable Diffusion (Rombach et al., 2022) es posiblemente el modelo de difusión más influyente de la historia. Su innovación clave: operar la difusión en un espacio latente comprimido (Latent Diffusion Model, LDM), reduciendo el coste computacional en un factor de ∼50×.

Arquitectura de Stable Diffusion (Latent Diffusion Model) VAE Encoder Imagen 512×512×3 Latente 64×64×4 compresión 48× (KL-reg VAE) ─── ESPACIO LATENTE (64×64×4) ─── Forward z₀ → z_t (+noise) U-Net (ε_θ) ResBlocks + Self-Attn + Cross-Attn (text) Reverse: z_T → z_{T-1} → ··· → z₀ (sampling con DDIM/DPM-Solver) Text Encoder CLIP ViT-L/14 77 tokens × 768 dims (frozen, no se entrena) "a cat in space" cross-attention CFG ε̂ = ε_∅ + w·(ε_c - ε_∅) w = 7.5 típico classifier-free VAE Decoder Latente 64×64×4 Imagen 512×512×3 descompresión (decoder fijo) 🖼️ 512×512 SD 1.5: ~860M params (U-Net) + 123M (CLIP) + 83M (VAE)

🧩 Componentes de Stable Diffusion

Componente Función Entrenado? Parámetros
VAE Encoder Comprime imagen 512² a latente 64²×4 Pre-entrenado, fijo ~34M
U-Net Predice ruido en espacio latente ✅ Se entrena ~860M
CLIP Text Encoder Codifica texto → embeddings Pre-entrenado, fijo ~123M
VAE Decoder Reconstruye latente → imagen Pre-entrenado, fijo ~49M
Scheduler DDIM, DPM-Solver++, Euler, etc. No (algorítmico)
Versión Fecha Innovación principal Resolución
SD 1.5 Oct 2022 LDM con CLIP ViT-L/14. Modelo base. 512×512
SD 2.0/2.1 Nov 2022 OpenCLIP ViT-H, 768px, depth2img 768×768
SDXL Jul 2023 Dual text encoder, UNet 2.6B, micro-conditioning, refiner 1024×1024
SD3 Feb 2024 DiT (MMDiT), flow matching, triple text encoder (CLIP×2 + T5) 1024×1024
Flux Ago 2024 Black Forest Labs. Flow matching + DiT. Muy alta calidad de texto. Hasta 2048²

Tendencia: La evolución va de U-Net → DiT, de noise prediction → flow matching, y de CLIP solo → múltiples text encoders (CLIP + T5) para mejor comprensión del prompt.

DALL-E 2/3 e Imagen

Mientras Stable Diffusion dominó el espacio open-source, OpenAI y Google desarrollaron sus propios modelos text-to-image con enfoques ligeramente diferentes.

DALL-E 2
Enfoque: CLIP text/image embeddings → prior (difusión) → decoder (difusión)
  • Text → CLIP text embedding
  • Prior: text emb → image emb (difusión)
  • Decoder: image emb → imagen 64² → 256² → 1024²
  • Cascaded super-resolution
📄 arXiv:2204.06125 · Ramesh et al. 2022
DALL-E 3
Innovación: Mejora del prompt adherence con recaptioning automático.
  • Re-caption: describe imágenes con captions detallados
  • Entrena con captions mejorados (no los originales)
  • Mucho mejor seguimiento de instrucciones
  • Integrado en ChatGPT
📄 arXiv:2309.16671 · Betker et al. 2023
Imagen
Innovación: Usar T5-XXL (text encoder de LLM) en lugar de CLIP.
  • T5-XXL (11B params) como text encoder
  • Difusión en píxeles (no latente)
  • Cascaded: 64² → 256² → 1024²
  • Dynamic thresholding para CFG alto
📄 arXiv:2205.11487 · Saharia et al. 2022

Consistency Models: difusión en un paso

El principal problema de los modelos de difusión sigue siendo la velocidad: incluso con DDIM, necesitamos ∼20-50 pasos. Los Consistency Models (Song et al., 2023) proponen una solución radical: generar en un solo paso.

📐 Idea clave

Un consistency model aprende una función \(f_\theta(\mathbf{x}_t, t)\) que mapea cualquier punto de la trayectoria de difusión directamente a la imagen limpia \(\mathbf{x}_0\):

$$f_\theta(\mathbf{x}_t, t) = \mathbf{x}_0 \quad \forall\, t \in [0, T]$$

La propiedad de auto-consistencia: para dos puntos \(\mathbf{x}_t\) y \(\mathbf{x}_{t'}\) en la misma trayectoria, \(f_\theta(\mathbf{x}_t, t) = f_\theta(\mathbf{x}_{t'}, t')\).

Consistency Training (CT)
Entrenar desde cero con un objetivo de consistencia. No necesita un modelo de difusión pre-entrenado.
Consistency Distillation (CD)
Destilar un modelo de difusión pre-entrenado en un consistency model. LCM (Latent Consistency Model) aplica esto a Stable Diffusion, generando imágenes de calidad en solo 2-8 pasos.
⚡ Impacto práctico: LCM permite generar imágenes 512×512 en menos de 1 segundo en una GPU consumer. Esto abre la puerta a aplicaciones en tiempo real como generación interactiva, gaming, y edición en vivo.
📄 arXiv:2303.01469 (Consistency Models) · arXiv:2310.04378 (LCM)

Panorama completo de modelos

El ecosistema de modelos de difusión ha crecido rápidamente. Aquí tienes un resumen de los modelos más importantes:

Modelo Organización Año Innovación clave Open?
DDPM UC Berkeley 2020 Primer modelo de difusión competitivo
GLIDE OpenAI 2021 Text-guided diffusion con classifier-free guidance Parcial
DALL-E 2 OpenAI 2022 CLIP prior + cascaded diffusion
Imagen Google 2022 T5-XXL text encoder + pixel diffusion
Stable Diffusion Stability AI / CompVis 2022 Latent Diffusion Model. Open source.
Midjourney Midjourney 2022 Enfoque en estética artística
SDXL Stability AI 2023 Dual text encoder, 1024px, refiner
DALL-E 3 OpenAI 2023 Recaptioning para mejor prompt adherence
DiT Meta / UC Berkeley 2023 Transformer reemplaza U-Net
SD3 Stability AI 2024 MMDiT + flow matching + triple text enc.
Flux Black Forest Labs 2024 Flow matching, excelente texto en imágenes
Sora OpenAI 2024 DiT escalado a vídeo, comprensión 3D
📊 Tendencia clara: El campo se mueve hacia DiT + Flow Matching (Flux, SD3) como la combinación dominante, reemplazando gradualmente la U-Net + noise prediction original de DDPM. La clave: los Transformers escalan mejor que las U-Nets con más datos y computación.

GANs vs Modelos de difusión: la gran comparativa

La rivalidad entre GANs y modelos de difusión es uno de los debates más interesantes del deep learning moderno. En 2021, Dhariwal & Nichol demostraron que los modelos de difusión superaban a las GANs en FID en ImageNet, marcando un punto de inflexión. Pero la historia no es tan simple: cada paradigma tiene fortalezas únicas.

Criterio GANs Modelos de difusión Veredicto
Calidad de imagen Excelente (StyleGAN3) Excelente (SDXL, Imagen) ≈ Empate
Diversidad ⭐⭐ Mode collapse común ⭐⭐⭐ Alta diversidad Difusión
Estabilidad de entrenamiento ⭐ Frágil, requiere trucos ⭐⭐⭐ Muy estable Difusión
Velocidad de inferencia ⭐⭐⭐ Un solo paso forward ⭐ Múltiples pasos (20-1000) GANs
Controlabilidad ⭐⭐ Limitada (latent space) ⭐⭐⭐ Guidance, ControlNet, etc. Difusión
Text-to-Image ⭐ Resultados limitados ⭐⭐⭐ Estado del arte Difusión
Likelihood tractable ✗ Implícita ✓ Via ELBO Difusión
Coste de entrenamiento ⭐⭐ Moderado ⭐ Alto (muchos pasos) GANs
Aplicaciones en tiempo real ⭐⭐⭐ Ideal ⭐⭐ Mejorando (LCM, SDXL Turbo) GANs
Super-resolución ⭐⭐⭐ ESRGAN, Real-ESRGAN ⭐⭐ StableSR, SwinIR+diff GANs (aún)
Comunidad / Ecosistema ⭐⭐ Maduro pero estancado ⭐⭐⭐ Enorme y creciendo Difusión
💡 En resumen: Los modelos de difusión dominan en calidad, diversidad, estabilidad y controlabilidad. Las GANs siguen siendo superiores en velocidad de inferencia y aplicaciones en tiempo real. El futuro parece apuntar a modelos híbridos y a la aceleración de la difusión (Consistency Models, LCM).

El problema de la velocidad

El principal inconveniente de los modelos de difusión es su lentitud. Mientras una GAN genera una imagen en un solo paso forward (~20ms), un modelo de difusión necesita múltiples pasos de denoising:

Método Pasos Tiempo (512×512) Calidad
DDPM original 1000 ~60s ⭐⭐⭐ Excelente
DDIM 50-100 ~3-6s ⭐⭐⭐ Muy buena
DPM-Solver++ 20-25 ~1.5s ⭐⭐⭐ Muy buena
LCM (Latent Consistency) 4-8 ~0.3s ⭐⭐ Buena
SDXL Turbo 1-4 ~0.1s ⭐⭐ Aceptable
Consistency Model 1-2 ~0.05s ⭐⭐ Buena
GAN (StyleGAN3) 1 ~0.02s ⭐⭐⭐ Excelente

La brecha se está cerrando rápidamente. Técnicas como destilación (progressive distillation), consistency training, y flow matching están acercando la velocidad de difusión a la de las GANs, sin sacrificar demasiada calidad.

La idea de Salimans & Ho (2022) es simple y elegante: entrenar un modelo «estudiante» que aprende a hacer en un paso lo que el modelo «profesor» hace en dos pasos. Repitiendo este proceso se puede reducir de 1024 pasos a solo 4.

1
Entrenar el modelo DDPM profesor con \(T = 1024\) pasos.
2
Entrenar un estudiante que predice en 1 paso lo que el profesor hace en 2: \(\hat{\mathbf{x}}_{t-2}^{\text{student}} \approx \text{DDPM}_{2 \text{ steps}}(\mathbf{x}_t)\).
3
Repetir: el estudiante se convierte en profesor, y se entrena un nuevo estudiante. 1024 → 512 → 256 → 128 → 64 → 32 → 16 → 8 → 4 pasos.

📄 Salimans & Ho (2022) — Progressive Distillation for Fast Sampling — arXiv:2202.00512

Modelos híbridos: lo mejor de ambos mundos

Una tendencia creciente es combinar las fortalezas de GANs y difusión en arquitecturas híbridas:

Diffusion-GAN
Usa un proceso de difusión para estabilizar el entrenamiento del discriminador GAN. Combina la velocidad de las GANs con la estabilidad de la difusión.
arXiv:2206.02262
🔄
Consistency Models
Destilan un modelo de difusión a un único paso. Calidad de difusión con la velocidad de una GAN.
Song et al. 2023
🎯
SDXL Turbo
Adversarial Diffusion Distillation: usa un loss adversarial (GAN) para destilar SDXL a 1-4 pasos.
Stability AI 2023
🧬
UFOGen
Un-paso generation combinando difusión con discriminador GAN para text-to-image en tiempo real.
arXiv:2311.09257
🔮 Tendencia: El futuro de la IA generativa probablemente no será «GANs vs difusión» sino «GANs + difusión». Las técnicas se complementan y convergen hacia modelos que combinan la calidad y estabilidad de la difusión con la velocidad de las GANs.

Papers fundamentales

Una selección curada de los artículos más importantes que han definido el campo de los modelos de difusión:

Paper Autores Año Contribución clave Ref
Nonequilibrium Thermodynamics Sohl-Dickstein et al. 2015 Primera propuesta de difusión generativa arXiv:1503.03585
NCSN (Score Matching) Song & Ermon 2019 Score matching + Langevin dynamics arXiv:1907.05600
DDPM Ho, Jain & Abbeel 2020 Difusión práctica con calidad GAN arXiv:2006.11239
DDIM Song, Meng & Ermon 2021 Sampling determinista acelerado arXiv:2010.02502
Score SDE Song et al. 2021 Unificación DDPM + score matching via SDEs arXiv:2011.13456
Classifier-Free Guidance Ho & Salimans 2022 Guiar generación sin clasificador externo arXiv:2207.12598
Latent Diffusion / LDM Rombach et al. 2022 Difusión en espacio latente (→ Stable Diffusion) arXiv:2112.10752
DiT Peebles & Xie 2023 Reemplazar U-Net por Transformer en difusión arXiv:2212.09748
Consistency Models Song et al. 2023 Mapeo directo a \(x_0\) en un solo paso arXiv:2303.01469
Flow Matching Lipman et al. 2023 Optimal transport paths, simplifica difusión arXiv:2210.02747
SD3 / MM-DiT Esser et al. 2024 Flow matching + multi-modal DiT arXiv:2403.03206

Repositorios y herramientas

El ecosistema open-source es una de las grandes fortalezas de los modelos de difusión. Estas son las herramientas imprescindibles:

🤗
diffusers
Librería oficial de Hugging Face para modelos de difusión. Pipelines, schedulers, modelos preentrenados.
huggingface/diffusers
🎨
ComfyUI
Interfaz basada en nodos para Stable Diffusion. Workflows visuales, altamente personalizable.
comfyanonymous/ComfyUI
🖌️
AUTOMATIC1111
WebUI para Stable Diffusion con Gradio. La interfaz más popular de la comunidad.
AUTOMATIC1111/stable-diffusion-webui
📐
k-diffusion
Implementación de samplers y modelos de difusión por Katherine Crowson. Base de muchos schedulers.
crowsonkb/k-diffusion
🧪
denoising-diffusion-pytorch
Implementación educativa limpia de DDPM en PyTorch por Phil Wang (lucidrains).
lucidrains/denoising-diffusion-pytorch
🏗️
CompVis/stable-diffusion
Repositorio original de Stable Diffusion por CompVis (Uni Heidelberg). Paper Latent Diffusion.
CompVis/stable-diffusion

El ecosistema generativo: VAE → GAN → Difusión

Los modelos de difusión no son un reemplazo de las GANs ni de los VAEs, sino una evolución que se construye sobre los hombros de todos los enfoques anteriores. El ecosistema generativo moderno es una red de conexiones:

ECOSISTEMA DE MODELOS GENERATIVOS VAEs Kingma 2014 Encoder + Decoder + KL Espacio latente estructurado GANs Goodfellow 2014 Generador vs Discriminador Entrenamiento adversarial Difusión Ho et al. 2020 Denoising iterativo Score matching / DDPM VAE encoder en Latent Diffusion compiten Stable Diffusion (LDM) VAE encoder + U-Net denoiser + CLIP text encoder Rombach et al. 2022 · arXiv:2112.10752 VAE Difusión latente DiT + Flow Matching Flux, SD3, Sora, SiT Consistency Models CM, LCM, SDXL Turbo Híbridos GAN+Diff Diffusion-GAN, UFOGen, ADD → Ver submódulo de Transformers

Como muestra el diagrama, Stable Diffusion es un ejemplo perfecto de convergencia: usa un VAE para comprimir, un modelo de difusión para generar, y compite con (y se inspira de) las GANs. Las últimas generaciones (SD3, Flux) reemplazan la U-Net por un Transformer, cerrando el círculo con la otra gran revolución del deep learning.

Resumen: el legado de los modelos de difusión

🏆
Calidad SOTA
Superaron a las GANs en FID (2021) y dominan la generación de imágenes.
📐
Elegancia matemática
Fundamentos sólidos en termodinámica, score matching y SDEs.
🎨
Text-to-Image
Habilitaron DALL-E, Stable Diffusion, Midjourney y la revolución creativa.
🎬
Multimodal
De imágenes a vídeo (Sora), audio, 3D, proteínas y más.
🌐
Open Source
Stable Diffusion democratizó la IA generativa con código abierto.
🚀
Evolución rápida
De 1000 pasos (2020) a 1 paso (2024). La velocidad ya no es un problema.
🎓 Para profundizar: Los modelos de difusión se conectan con prácticamente todos los temas de este curso:
  • Autoencoders — El VAE encoder es fundamental en Latent Diffusion.
  • GANs — La comparativa directa y los modelos híbridos GAN+Difusión.
  • Transformers — DiT reemplaza U-Net por Transformers; CLIP conecta texto e imagen.
  • Segmentación (U-Net) — La arquitectura U-Net es el backbone clásico de los modelos de difusión.
🧪 Herramientas interactivas