Phase 08 - Lesson 04

Conditional GANs & Pix2Pix

La GAN Condicional (Mirza & Osindero, 2014) agrega una condición c como entrada tanto para G como para D. Pix2Pix (Isola et al., 2017) especializó esto: la condición es una imagen de entrada completa, el generador es una U-Net, el discriminador es un clasificador basado en parches (PatchGAN) y la pérdida es adversarial + L1. Esa receta supera a los modelos de texto a imagen desde cero en dominios reducidos de imagen a imagen incluso en 2026 porque se entrena con datos emparejados, por lo que tienes exactamente la señal que necesitas.

El Concepto

Pix2Pix: generador U-Net, discriminador PatchGAN

G Condicional. G(x, z) → y. En Pix2Pix, z es dropout dentro de G (sin ruido de entrada; Isola descubrió que el ruido explícito se ignoraba).

D Condicional. D(x, y) → [0, 1]. La entrada es el par (condición, salida). Esta es la diferencia clave: D debe juzgar si y es consistente con x, no solo si y parece real.

Generador U-Net. Encoder-decoder con conexiones de salto (skip connections) a través del cuello de botella (bottleneck). Crítico para tareas donde la entrada y la salida comparten una estructura de bajo nivel (bordes, silueta). Sin los saltos, los detalles de alta frecuencia desaparecen.

Discriminador PatchGAN. En lugar de devolver una única puntuación de real/falso, D devuelve una cuadrícula de N×N donde cada celda juzga un campo receptivo de ~70×70 píxeles. Promediado. Esta es una suposición de campo aleatorio de Markov: el realismo es local. Mucho más rápido de entrenar, menos parámetros, salida más nítida.

Pérdida.

loss_G = -log D(x, G(x)) + λ · ||y - G(x)||_1
loss_D = -log D(x, y) - log (1 - D(x, G(x)))

El término L1 estabiliza el entrenamiento y empuja a G hacia el objetivo conocido. L1 genera bordes más nítidos que L2 (medianas, no medias). λ = 100 era el valor predeterminado de Pix2Pix.

CycleGAN — cuando no tienes parejas

Pix2Pix necesita datos emparejados (x, y). CycleGAN (Zhu et al., 2017) elimina este requisito a costa de una pérdida adicional: la pérdida de consistencia de ciclo (cycle consistency). Dos generadores G: X → Y and F: Y → X. Se entrenan de manera que F(G(x)) ≈ x y G(F(y)) ≈ y. Esto te permite traducir caballos en cebras, verano en invierno, sin ejemplos emparejados.

En 2026, la traducción de imagen a imagen no emparejada se realiza principalmente mediante difusión (ControlNet, IP-Adapter) en lugar de CycleGAN, pero la idea de consistencia de ciclo sobrevive en casi todos los artículos de adaptación de dominios no emparejados.

Constrúyelo

code/main.py implementa una GAN condicional pequeña en datos 1-D. La condición c es una etiqueta de clase (0 o 1). La tarea: producir una muestra de la distribución condicional para la clase dada.

Paso 1: agregar la condición a las entradas de G y D

def G(z, c, params):
    return mlp(concat([z, one_hot(c)]), params)

def D(x, c, params):
    return mlp(concat([x, one_hot(c)]), params)

La codificación one-hot es la forma más sencilla. Los modelos más grandes utilizan embeddings aprendidos, modulación FiLM o atención cruzada (cross-attention).

Paso 2: entrenar condicional

for step in range(steps):
    x, c = sample_real_conditional()
    noise = sample_noise()
    update_D(x_real=x, x_fake=G(noise, c), c=c)
    update_G(noise, c)

El generador debe coincidir con la distribución real para la condición dada, no con la marginal.

Paso 3: verificar la salida por clase

for c in [0, 1]:
    samples = [G(noise, c) for noise in batch]
    mean_c = mean(samples)
    assert_near(mean_c, real_mean_for_class_c)

Dificultades

  • Condición ignorada. G aprende a marginalizar, D nunca penaliza porque la señal de la condición es débil. Solución: condicionar D de manera más agresiva (capa temprana, no solo tardía), usar discriminador de proyección (Miyato & Koyama 2018).
  • Peso L1 demasiado bajo. G se desvía hacia salidas realistas arbitrarias, no fieles. Comienza con λ≈100 para tareas tipo Pix2Pix.
  • Peso L1 demasiado alto. G produce salidas borrosas porque L1 sigue siendo una norma L_p. Reduce gradualmente (anneal down) una vez que el entrenamiento se estabilice.
  • Filtración de ground-truth en D. Concatena (x, y) como entrada de D, no solo y. Sin esto, D no puede verificar la consistencia.
  • Colapso de modo por clase. Cada clase puede colapsar de forma independiente. Realiza comprobaciones de diversidad condicionales por clase.

Úsalo

Estado de las tareas de imagen a imagen en 2026:

Tarea Mejor enfoque
Boceto → foto, mismo dominio, datos emparejados Pix2Pix / Pix2PixHD (sigue siendo rápido, sigue siendo nítido)
Boceto → foto, no emparejado ControlNet con un modelo de condicionamiento Scribble
Seg semántica → foto SPADE / GauGAN2 o SD + ControlNet-Seg
Transferencia de estilo Difusión con IP-Adapter o LoRA; los métodos GAN son legados
Profundidad → foto ControlNet-Depth sobre Stable Diffusion
Superresolución Real-ESRGAN (GAN), ESRGAN-Plus o SD-Upscale (difusión)
Coloración ColTran, colorizadores basados en difusión o Pix2Pix-color
Día → noche, estaciones, clima Basado en CycleGAN o ControlNet

Pix2Pix sigue siendo la herramienta adecuada cuando (a) tienes miles de ejemplos emparejados, (b) la tarea es estrecha y repetible, y (c) necesitas una inferencia rápida. En tareas genéricas de dominio abierto, gana la difusión.

Envíalo

Guarda outputs/skill-img2img-chooser.md. La Skill recibe una descripción de la tarea, disponibilidad de datos (emparejados vs no emparejados, N muestras) y presupuesto de latencia/calidad, luego genera: enfoque (Pix2Pix, CycleGAN, variante de ControlNet, SDXL + IP-Adapter), requisitos de datos de entrenamiento, costo de inferencia y protocolo de evaluación (LPIPS, FID, específico de la tarea).

Ejercicios

  1. Fácil. Modifica code/main.py para agregar una tercera clase. Confirma que G siga mapeando el ruido de cada clase al modo correcto.
  2. Medio. Reemplaza L1 por una pérdida de tipo perceptual en el entorno 1-D (por ejemplo, un D pequeño y congelado que actúe como extractor de características). ¿Cambia la nitidez de la distribución condicional?
  3. Difícil. Dibuja un CycleGAN en el entorno 1-D: dos distribuciones, dos generadores, pérdida de ciclo. Muestra que aprende a mapear entre ellos sin datos emparejados.

Términos Clave

Término Lo que dice la gente Lo que realmente significa
GAN Condicional "GAN con etiquetas" G(z, c), D(x, c). Ambas redes ven la condición.
Pix2Pix "GAN de imagen a imagen" cGAN emparejada con G U-Net y D PatchGAN + pérdida L1.
U-Net "Encoder-decoder con saltos" Red convolucional simétrica; los saltos preservan la alta frecuencia.
PatchGAN "Clasificador de realismo local" D genera una puntuación por parche en lugar de una puntuación global.
CycleGAN "Traducción de imágenes no emparejadas" Dos G + pérdida de consistencia de ciclo; sin datos emparejados.
SPADE "GauGAN" Normaliza las activaciones intermedias con el mapa semántico; de segmentación a imagen.
FiLM "Modulación lineal por características" Transformación afín por característica a partir de la condición; condicionamiento económico.

Nota de producción: Pix2Pix como línea base limitada por la latencia

Cuando se tienen datos emparejados y una tarea estrecha (boceto → renderizado, mapa semántico → foto, día → noche), la inferencia de un solo disparo (one-shot) de Pix2Pix supera a la difusión por un orden de magnitud en latencia. La comparación en producción suele ser:

Camino Pasos Latencia típica a 512² en una sola L4
Pix2Pix (U-Net forward) 1 ~30 ms
SD-Inpaint o SD-Img2Img 20 ~1.2 s
SDXL-Turbo Img2Img 1-4 ~0.15-0.35 s
ControlNet + SDXL base 20-30 ~3-5 s

Pix2Pix gana en rendimiento en lotes estáticos (cada solicitud consume los mismos FLOPs). La difusión gana en calidad y generalización. La estrategia moderna suele ser lanzar un modelo destilado al estilo Pix2Pix para la tarea estrecha y un respaldo (fallback) de difusión para entradas menos comunes (tail inputs).

Lectura Adicional

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