Phase 08: Generative AI

Autoencodadores y autoencodadores variativos (VAE)

Un autoencoder simple comprime y luego reconstruye. Memora. No genera. Añade un truco fuerza el código para que parezca gaussiano y obtienes un muestreo. Ese truco único, la reparameterización de z = μ + σ·ε, es por eso que cada modelo de difusión latente y de coincidencia de flujo de imagen que utilices en 2026 tiene un VAE en la entrada.

Type: Build

Languages: Python

Prerequisites: Phase 3 · 02 (Backprop), Phase 3 · 07 (CNNs), Phase 8 · 01 (Taxonomy)

Time: ~75 minutes

El problema

Comprimir un dígito MNIST de 784 píxeles a un código de 16 números, luego reconstruir. Un autoencoder simple hará la reconstrucción de MSE pero el espacio de código es un lío agudo. Elige un punto aleatorio en el espacio de código, decodifica, y obtienes ruido. No tiene muestreo. Es un modelo de compresión disfrazado.

Lo que realmente quieres es: (a) el espacio de código es una distribución limpia y suave que puedes tomar de un isotrópico gaussianoN(0, I), (b) la descifrada de cualquier muestra produce un dígito plausible, y (c) el codificador y el decodificador todavía comprimen bien.

El VAE de Kingma 2013 resuelve esto entrenando al codificador para emitir una distribución q(z|x) = N(μ(x), σ(x)²), tirando esa distribución hacia el priorN(0, I)a través de una penalización KL, y luego muestreo zde laq(z|x)En el momento de la inferencia, deja caer el codificador, muestraz ~ N(0, I)La pena KL es lo que obliga a estructurar el espacio de código.

En 2026 los VAEs rara vez envían de forma independiente han sido superados por difusión por calidad de imagen en bruto pero son el codificador de elección para cada modelo de difusión latente (SD 1/2/XL/3, Flux, AudioCraft). Aprende el VAE y aprendes la primera capa invisible de cada pipeline de imágenes que utilizas.

El concepto

!Autoencoder vs VAE: the reparameterization trick

Autoencoder. z = encoder(x)¿ Qué ?x̂ = decoder(z), pérdida = ||x - x̂||²- El espacio de código no está estructurado.

VAE encoder.Salidas de dos vectores: μ(x)y log σ²(x)- Estos definen .q(z|x) = N(μ, diag(σ²))¿ Qué ?

Reparameterization trick.Muestreo de q(z|x)No es diferenciable.z = μ + σ·εdondeε ~ N(0, I)Ahora .zes una función determinista de (μ, σ)más un ruido no parámetro flujo de gradientes μy σ¿ Qué ?

Loss.Evidencia Bando inferior (ELBO), dos términos:

loss = reconstruction + β · KL[q(z|x) || N(0, I)]
     = ||x - x̂||²  + β · Σ_i ( σ_i² + μ_i² - log σ_i² - 1 ) / 2

La reconstrucción impulsax̂haciaxKL empuja .q(z|x)El primer tipo de muestras de desintegración de los átomos de la base de datos de la base de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos de datos

Sampling.En la inferencia: dibujar z ~ N(0, I)Una pasada hacia adelante, sin muestreo iterativo como la difusión.

Construye el mismo

code/main.pyImplementa una pequeña VAE sin numpy o antorcha. La entrada es un dato sintético de 8 dimensiones extraído de una mezcla gaussiana de 2 componentes en 8D. El codificador y el decodificador son MLPs de capa oculta única. Implementamos activación tanh, pase hacia adelante, pérdida y un pase hacia atrás escrito a mano. No la producción pedagogía.

Paso 1: codificador hacia adelante

pythondef encode(x, enc):
    h = tanh(add(matmul(enc["W1"], x), enc["b1"]))
    mu = add(matmul(enc["W_mu"], h), enc["b_mu"])
    log_sigma2 = add(matmul(enc["W_sig"], h), enc["b_sig"])
    return mu, log_sigma2

log σ²en lugar deσAsí que la salida de la red no está limitada (softplus de σ es una trampa los gradientes mueren en σ ≈ 0).

Paso 2: reparametrizar y decodificar

pythondef reparameterize(mu, log_sigma2, rng):
    eps = [rng.gauss(0, 1) for _ in mu]
    sigma = [math.exp(0.5 * lv) for lv in log_sigma2]
    return [m + s * e for m, s, e in zip(mu, sigma, eps)]

def decode(z, dec):
    h = tanh(add(matmul(dec["W1"], z), dec["b1"]))
    return add(matmul(dec["W_out"], h), dec["b_out"])

Paso 3: El ELBO

pythondef elbo(x, x_hat, mu, log_sigma2, beta=1.0):
    recon = sum((a - b) ** 2 for a, b in zip(x, x_hat))
    kl = 0.5 * sum(math.exp(lv) + m * m - lv - 1 for m, lv in zip(mu, log_sigma2))
    return recon + beta * kl, recon, kl

La gente todavía envía código con las estimaciones de Monte-Carlo KL en 2026 es 3 veces más lento sin razón.

Paso 4: generar

pythondef sample(dec, z_dim, rng):
    z = [rng.gauss(0, 1) for _ in range(z_dim)]
    return decode(z, dec)

Es el modelo generativo. Cinco líneas.

Las trampas

  • Posterior collapse.Dispositivos de término KL q(z|x) → N(0, I)tan agresivamente quezNo lleva información sobre x. Corrección: β-annealing (inicio β=0, rampa a 1), bits libres, o saltar el KL en dimensiones inactivas.
  • Blurry samples.La probabilidad del decodificador gaussiano implica la reconstrucción de MSE, que es Bayes-óptima para L2 (la media) la media de un conjunto de dígitos plausibles es un dígito borroso.
  • β too large, too early.Ver colapso posterior. Comienza en β≈0.01 y rampa.
  • Latent dim too small.16-D funciona para MNIST, 256-D para ImageNet 2562, 2048-D para ImageNet 10242. La VAE de la difusión estable comprime 512×512×3 → 64×64×4 (32x factor de muestra baja en área espacial, 32x en canales).

Usalo

La pila de VAE 2026:

SituationPick
Image-latent encoder for diffusionStable Diffusion VAE (sd-vae-ft-ema) or Flux VAE
Audio-latent encoderEncodec (Meta), SoundStream, or DAC (Descript)
Video latentsSora's spatiotemporal patches, Latte VAE, WAN VAE
Disentangled representation learningβ-VAE, FactorVAE, TCVAE
Discrete latents (for transformer modelling)VQ-VAE, RVQ (ResidualVQ)
Continuous latents for generationPlain VAE, then condition a flow/diffusion model in that latent space

Un modelo de difusión latente es un modelo de difusión que vive entre un codificador y un decodificador. El modelo de difusión hace la compresión gruesa, el modelo de difusión hace el levantamiento pesado.

Envío

Salva .outputs/skill-vae-trainer.md¿ Qué ?

Tome habilidades: perfil de conjunto de datos + objetivo latente-dim + uso en aguas subterráneas (reconstrucción, muestreo o entrada de difusión latente) y resultados: elección de arquitectura (plan/β/VQ/RVQ), programa β, latente dim, probabilidad de decodificación (Gaussian vs categorical), y plan de evaluación (recon MSE, KL por dim, distancia Fréchet entre q(z|x)y N(0, I)¿Qué es lo que se hace?

Los ejercicios

  1. Easy.CambiarβEn elcode/main.py¿ Qué ?0.01¿ Qué ?0.1¿ Qué ?1.0¿ Qué ?5.0. Graba la reconstrucción final de MSE y KL. ¿Cuál β es mejor para sus datos sintéticos?
  2. Medium.Reemplazar la probabilidad de descodificación gaussiana con una probabilidad de Bernoulli (pérdida de entropía cruzada). Comparar la calidad de la muestra en una versión binaria de los mismos datos sintéticos.
  3. Hard.Extendersecode/main.pyen un mini VQ-VAE: sustituir el continuo zComparar la reconstrucción de MSE y informar cuántas entradas de código se utilizan (el colapso del código es real).

Términos clave

TermWhat people sayWhat it actually means
AutoencoderEncode-decode networkx → z → x̂, learn MSE. Not generative.
VAEAE with a samplerEncoder outputs a distribution, KL penalty shapes code space.
ELBOEvidence lower boundlog p(x) ≥ recon - KL[q(z|x) || p(z)]; tight when q = p(z|x).
Reparameterizationz = μ + σ·εRewrites stochastic node as deterministic + pure noise. Enables backprop through sampling.
Priorp(z)Target distribution for the latent, typically N(0, I).
Posterior collapse"KL term wins"Encoder ignores x, outputs the prior; decoder must hallucinate.
β-VAETunable KL weightloss = recon + β·KL. Higher β = more disentangled but blurrier.
VQ-VAEDiscrete latentReplace continuous z with nearest codebook vector; enables transformer modelling.

Nota de producción: el VAE es el camino más caliente en un servidor de difusión

En una línea de flujo / flujo / SD3 estable, el VAE se llama dos veces por solicitud una vez para codificar (si se hace img2img / inpainting) y una vez para decodificar. En 10242 el pase de decodificador es a menudo el pico de memoria de activación más grande en toda la línea porque muestra128×128×16Los latentes de vuelta a 1024×1024×3Dos consecuencias prácticas:

  • Slice or tile the decode. diffusersexpone pipe.vae.enable_slicing()y pipe.vae.enable_tiling(). Tiling comercializa un pequeño artefacto de costura paraO(tile²)memoria en lugar de O(H·W)Es esencial para 10242+ en GPUs de consumo.
  • bf16 decoder, fp32 numerics for the final resize.El SD 1.x VAE fue lanzado en fp32 y produce silenciosamente NaNs cuando se lanza a fp16 en 10242+. buques SDXL madebyollin/sdxl-vae-fp16-fix siempre prefiere la variante fp16-fix o utilizar bf16.

Leer más

This free lesson is part of the AI Engineering from Scratch curriculum. Read the full explanation, run the lesson code, and verify the result in the interactive reader or from the repository source.

Browse the complete course catalog or open this lesson on GitHub.