Phase 08 - Lesson 03

GANs — Generador vs Discriminador

El truco de Goodfellow en 2014 fue omitir la densidad por completo. Dos redes. Una crea falsificaciones. Otra las atrapa. Luchan hasta que las falsificaciones son indistinguibles de las reales. No debería funcionar. A menudo no funciona. Cuando lo hace, las muestras siguen siendo las más nítidas de la literatura para dominios estrechos.

Tipo: Build Lenguajes: Python Requisitos previos: Fase 3 · 02 (Backprop), Fase 3 · 08 (Optimizers), Fase 8 · 02 (VAE) Tiempo: ~75 minutos

El Problema

Los VAE producen muestras borrosas porque la pérdida del decodificador MSE es óptima según Bayes para la imagen promedio, y el promedio de muchos dígitos plausibles es un dígito difuso. Quieres una pérdida que recompense la plausibilidad, no la proximidad píxel por píxel a un objetivo específico. No existe una forma cerrada para la plausibilidad. Tienes que aprenderla.

La idea de Goodfellow: entrenar un clasificador D(x) para distinguir imágenes reales de falsas. Entrenar un generador G(z) para engañar a D. La señal de pérdida para G es lo que D crea actualmente que hace que algo parezca real. Esta señal se actualiza a medida que G mejora, persiguiendo un objetivo en movimiento. Si ambas redes convergen, G habrá aprendido la distribución de datos sin necesidad de escribir log p(x).

Esto es entrenamiento adversarial. La matemática es un juego minimax:

min_G max_D  E_real[log D(x)] + E_fake[log(1 - D(G(z)))]

En 2026, las GAN ya no son el generador SOTA (la difusión y el flow matching se quedaron con esa corona). Pero StyleGAN 2/3 siguen siendo los modelos de rostros más nítidos jamás creados, los discriminadores de GAN se utilizan como pérdidas perceptuales en el entrenamiento de difusión, y el entrenamiento adversarial impulsa las destilaciones rápidas de 1 paso (SDXL-Turbo, SD3-Turbo, LCM) que te permiten implementar difusión en tiempo real.

El Concepto

Entrenamiento de GAN: generador y discriminador en minimax

Generador G(z). Mapea un vector de ruido z ~ N(0, I) a una muestra . Una red con forma de decodificador (densa o convolucional transpuesta).

Discriminador D(x). Mapea una muestra a una probabilidad escalar (o puntuación/score). Real → 1, falsa → 0.

Pérdida. Dos actualizaciones alternas:

  • Entrenar D: loss_D = -[ log D(x) + log(1 - D(G(z))) ]. Entropía cruzada binaria con real=1, falso=0.
  • Entrenar G: loss_G = -log D(G(z)). Esta es la forma no saturada (non-saturating) que usó Goodfellow (la original log(1 - D(G(z))) se satura y elimina los gradientes cuando D tiene confianza).

Bucle de entrenamiento. Un paso de D, un paso de G. Repetir.

Por qué funciona. Si G coincide perfectamente con p_data, entonces D no puede hacerlo mejor que el azar y produce 0.5 en todas partes; G no recibe más gradiente. Equilibrio.

Por qué falla. Colapso de modo (mode collapse — G encuentra un modo que D no puede clasificar y lo produce para siempre), gradiente desvanecido (D aprende demasiado rápido y log D se satura), inestabilidad en el entrenamiento (tasas de aprendizaje, tamaños de lote, lo que sea).

Variantes que hicieron que las GAN funcionaran

Año Innovación Solución
2015 DCGAN Conv/deconv, batch norm, LeakyReLU — la primera arquitectura estable.
2017 WGAN, WGAN-GP Reemplaza BCE con la distancia de Wasserstein + penalización de gradiente (gradient penalty). Corrige el gradiente desvanecido.
2017 Normalización espectral Limita al discriminador por Lipschitz. Aún se usa en discriminadores de 2026.
2018 Progressive GAN Entrena primero en baja resolución, añade capas. Primeros resultados en megapíxeles.
2019 StyleGAN / StyleGAN2 Red de mapeo (mapping network) + normalización de instancia adaptativa (adaptive instance norm). Estado del arte para fotorrealismo de dominio fijo.
2021 StyleGAN3 Libre de aliasing (alias-free), equivariante a traslación — sigue siendo el estándar de oro para rostros en 2026.
2022 StyleGAN-XL Condicional, consciente de la clase (class-aware), escala mayor.
2024 R3GAN Rebranding con regularización más fuerte; funciona en 1024² sin trucos.

Build It

code/main.py entrena una pequeña GAN con datos 1-D: una mezcla de dos gaussianas. El generador y el discriminador son MLP de una sola capa oculta. Implementamos las pasadas hacia adelante (forward), hacia atrás (backward) y el bucle minimax a mano. El objetivo es ver los dos modos de falla clave (colapso de modo + gradiente desvanecido) a medida que ocurren.

Paso 1: pérdida no saturada

La pérdida clásica de Goodfellow log(1 - D(G(z))) tiende a 0 cuando D clasifica la muestra falsa de G como falsa con alta confianza. En ese punto, el gradiente para G es básicamente cero; G no puede mejorar. La forma no saturada -log D(G(z)) tiene la asíntota opuesta: explota cuando D tiene confianza, dando a G una señal fuerte.

def g_loss(d_fake):
    # maximize log D(G(z))  <=>  minimize -log D(G(z))
    return -sum(math.log(max(p, 1e-8)) for p in d_fake) / len(d_fake)

Paso 2: un paso de discriminador por paso de generador

for step in range(steps):
    # train D
    real_batch = sample_real(batch_size)
    fake_batch = [G(z) for z in sample_noise(batch_size)]
    update_D(real_batch, fake_batch)

    # train G
    fake_batch = [G(z) for z in sample_noise(batch_size)]  # fresh fakes
    update_G(fake_batch)

Muestras falsas frescas para G, de lo contrario los gradientes quedan obsoletos.

Paso 3: vigilar el colapso de modo

if step % 200 == 0:
    samples = [G(z) for z in sample_noise(500)]
    mode_a = sum(1 for s in samples if s < 0)
    mode_b = 500 - mode_a
    if min(mode_a, mode_b) < 50:
        print("  [!] mode collapse: one mode is starved")

El síntoma canónico: uno de los dos modos reales deja de generarse. El discriminador deja de corregirlo porque nunca se ve como una falsificación.

Trampas

  • Discriminador demasiado fuerte. Reduce la tasa de aprendizaje de D a 2-5x, o añade ruido de instancia/capa. Si D alcanza una precisión >95%, G está muerto.
  • El generador memoriza un modo. Añade ruido a las entradas de D, usa una capa de discriminador de minilotes (minibatch-discriminator), o cambia a WGAN-GP.
  • Fuga de estadísticas en Batch Norm. El flujo del lote real + lote falso a través de la misma capa de BN mezcla sus estadísticas. En su lugar, usa normalización de instancia (instance norm) o normalización espectral (spectral norm).
  • Manipulación de Inception Score. FID e IS son ruidosos con recuentos de muestras bajos. Usa ≥10k muestras en la evaluación.
  • El muestreo de un solo paso es una mentira para tareas condicionales. Aún necesitas escalas CFG, trucos de truncamiento y remuestreo para obtener salidas útiles.

Use It

La pila de GAN en 2026:

Situación Elección
Rostos humanos fotorrealistas, pose fija StyleGAN3 (más nítido, más pequeño)
Rostros de anime / estilizados StyleGAN-XL o Stable Diffusion LoRA
Traducción de imagen a imagen Pix2Pix / CycleGAN (Fase 8 · 04) o ControlNet (Fase 8 · 08)
Texto a imagen rápido de 1 paso Destilación adversarial de difusión (SDXL-Turbo, SD3-Turbo)
Pérdida perceptual dentro de un entrenador de difusión Discriminador GAN pequeño en recortes de imagen (crops)
Cualquier cosa multimodal o abierta No lo uses — usa difusión o flow matching

Las GAN son nítidas pero estrechas. Una vez que tu dominio se expande (fotos, prompts de texto arbitrarios, video), cambia a la difusión. El truque adversarial sobrevive como un componente (pérdidas perceptuales, destilación), no como un generador independiente.

Ship It

Guarda outputs/skill-gan-debugger.md. La Skill toma una ejecución fallida de GAN (curvas de pérdida, cuadrícula de muestras, tamaño del conjunto de datos) y produce una lista clasificada de causas probables, soluciones de una sola línea y un protocolo de reejecución.

Ejercicios

  1. Fácil. Ejecuta code/main.py con la configuración predeterminada. Luego establece D_LR = 5 * G_LR y vuelve a ejecutar. ¿Qué tan rápido se colapsa la pérdida de G a una constante?
  2. Medio. Reemplaza la pérdida clásica BCE de Goodfellow con la pérdida de WGAN: loss_D = E[D(fake)] - E[D(real)], loss_G = -E[D(fake)], y recorta los pesos de D a [-0.01, 0.01]. ¿Es el entrenamiento más estable? Compara la convergencia en tiempo real.
  3. Difícil. Extiende el ejemplo 1-D a datos 2-D (mezcla de 8 gaussianas en un anillo). Realiza un seguimiento de cuántos de los 8 modos captura el generador en los pasos 1k, 5k y 10k. Implementa la discriminación por minilotes (minibatch discrimination) y vuelve a medir.

Términos Clave

Término Lo que la gente dice Lo que realmente significa
Generador "G" Red de ruido a muestra, G: z → x̂.
Discriminador "D" Clasificador D: x → [0, 1], real vs falsa.
Minimax "El juego" min_G max_D of a joint objective.
Pérdida no saturada "La solución" Usar -log D(G(z)) para G en lugar de log(1 - D(G(z))).
Colapso de modo "G memorizó una cosa" El generador o produce pocas salidas distintas a pesar de la diversidad de datos.
WGAN "Wasserstein" Reemplaza BCE con la distancia Earth-Mover + penalización de gradiente; gradiente más suave.
Normalización espectral "Truco de Lipschitz" Limita las normas de los pesos de D para acotar su pendiente; estabiliza el entrenamiento.
StyleGAN "El que funciona" Red de mapeo + AdaIN; el mejor de su clase para rostros, aún en 2026.

Nota de producción: la inferencia de un solo paso es la ventaja duradera de las GAN

Las GAN ya no ganan en calidad de muestra para la generación de dominio abierto, pero siguen ganando en costo de inferencia. En el vocabulario de la literatura de inferencia en producción, una GAN tiene:

  • Sin etapas de prefill ni decode. Una sola pasada hacia adelante de G(z). TTFT ≈ latência total.
  • Sin presión de KV-cache. El único estado son los pesos. El tamaño del lote está limitado por la memoria de activación, no por la caché.
  • Procesamiento por lotes continuo trivial. Dado que cada solicitud requiere la misma cantidad de FLOP fijos, un lote estático en la ocupación objetivo del servidor suele ser óptimo. No se necesita un programador dinámico (in-flight scheduler).

Por esto la destilación de GAN (SDXL-Turbo, SD3-Turbo, ADD, LCM) es la técnica dominante para texto a imagen rápido en 2026: colapsa un pipeline de difusión de 20-50 pasos en 1-4 pasadas hacia adelante de estilo GAN, mientras mantiene la distribución de una base de difusión. La pérdida adversarial sobrevive como un control en el tiempo de entrenamiento para convertir generadores lentos en rápidos.

Lecturas Adicionales

0 lifetime access. Curriculum based on AI Engineering from Scratch by Rohit Ghumare (MIT, used under attribution).