Phase 08 - Lesson 03

GANs — Gerador vs Discriminador

O truque de Goodfellow em 2014 foi pular a densidade completamente. Duas redes. Uma cria falsificações. Outra as detecta. Elas lutam até que as falsificações sejam indistinguíveis das reais. Não deveria funcionar. Frequentemente não funciona. Quando funciona, as amostras ainda são as mais nítidas da literatura para domínios específicos.

Tipo: Build Linguagens: Python Pré-requisitos: Fase 3 · 02 (Backprop), Fase 3 · 08 (Optimizers), Fase 8 · 02 (VAE) Tempo: ~75 minutos

O Problema

VAEs produzem amostras borradas porque a perda do decodificador MSE é Bayes-ótima para a imagem média — e a média de muitos dígitos plausíveis é um dígito difuso. Você quer uma perda que recompense a plausibilidade, não a proximidade pixel a pixel de qualquer alvo único. Não há uma forma fechada para plausibilidade. Você tem que aprendê-la.

A ideia de Goodfellow: treinar um classificador D(x) para distinguir imagens reais de falsas. Treinar um gerador G(z) para enganar D. O sinal de perda para G é o que quer que D atualmente pense que faz algo parecer real. Este sinal é atualizado à medida que G melhora, perseguindo um alvo móvel. Se ambas as redes convergirem, G terá aprendido a distribuição dos dados sem nunca precisar escrever log p(x).

Isso é treinamento adversarial. A matemática é um jogo minimax:

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

Em 2026, as GANs não são mais o gerador SOTA (o trono foi tomado por difusão e flow matching). Mas o StyleGAN 2/3 continua sendo o modelo de rostos mais nítido já lançado, os discriminadores de GAN são usados como perdas perceptuais no treinamento de difusão, e o treinamento adversarial alimenta as destilações rápidas de 1 passo (SDXL-Turbo, SD3-Turbo, LCM) que permitem entregar difusão em tempo real.

O Conceito

Treinamento de GAN: gerador e discriminador em minimax

Gerador G(z). Mapeia um vetor de ruído z ~ N(0, I) para uma amostra . Uma rede em formato de decodificador (densa ou convolucional transposta).

Discriminador D(x). Mapeia uma amostra para uma probabilidade escalar (ou pontuação/score). Real → 1, falsa → 0.

Perda. Duas atualizações alternadas:

  • Treinar D: loss_D = -[ log D(x) + log(1 - D(G(z))) ]. Entropia cruzada binária com real=1, falso=0.
  • Treinar G: loss_G = -log D(G(z)). Esta é a forma não saturada (non-saturating) que Goodfellow usou (a original log(1 - D(G(z))) satura e elimina os gradientes quando D está confiante).

Loop de treinamento. Um passo de D, um passo de G. Repita.

Por que funciona. Se G se ajusta perfeitamente a p_data, então D não pode fazer melhor do que o acaso e gera 0.5 em todos os lugares; G não recebe mais gradientes. Equilíbrio.

Por que falha. Colapso de modo (mode collapse — G encontra um modo que D não consegue classificar e o produz para sempre), gradiente evanescente (D aprende rápido demais e log D satura), instabilidade de treinamento (taxas de aprendizado, tamanhos de lote, qualquer coisa).

Variantes que fizeram as GANs funcionarem

Ano Inovação Solução
2015 DCGAN Conv/deconv, batch norm, LeakyReLU — a primeira arquitetura estável.
2017 WGAN, WGAN-GP Substitui a BCE pela distância de Wasserstein + penalidade de gradiente (gradient penalty). Corrige o gradiente evanescente.
2017 Normalização espectral Limita o discriminador por Lipschitz. Ainda usado em discriminadores de 2026.
2018 Progressive GAN Treina primeiro em baixa resolução, adiciona camadas. Primeiros resultados em megapixel.
2019 StyleGAN / StyleGAN2 Rede de mapeamento (mapping network) + normalização de instância adaptativa (adaptive instance norm). Estado da arte para fotorrealismo de domínio fixo.
2021 StyleGAN3 Sem aliasing (alias-free), equivariante a translação — ainda o padrão-ouro para rostos em 2026.
2022 StyleGAN-XL Condicional, ciente de classe (class-aware), escala maior.
2024 R3GAN Rebranding com regularização mais forte; funciona em 1024² sem truques.

Build It

code/main.py treina uma pequena GAN em dados 1-D: uma mistura de duas Gaussianas. O gerador e o discriminador são MLPs de uma única camada oculta. Nós implementamos a passada para frente (forward), para trás (backward) e o loop minimax manualmente. O objetivo é ver os dois principais modos de falha (colapso de modo + gradiente evanescente) à medida que ocorrem.

Passo 1: perda não saturada

A perda clássica de Goodfellow log(1 - D(G(z))) vai para 0 quando D classifica a amostra falsa de G como falsa com alta confiança. Nesse ponto, o gradiente para G é essencialmente zero — G não consegue melhorar. A forma não saturada -log D(G(z)) possui a assíntota oposta: ela explode quando D está confiante, dando a G um sinal forte.

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)

Passo 2: um passo de discriminador por passo de gerador

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)

Amostras falsas frescas para G, caso contrário os gradientes ficam desatualizados.

Passo 3: monitorar o 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")

O sintoma clássico: um dos dois modos reais deixa de ser gerado. O discriminador para de corrigi-lo porque ele nunca é visto como falso.

Armadilhas

  • Discriminador forte demais. Reduza a taxa de aprendizado de D em 2-5x ou adicione ruído de instância/camada. Se D atingir mais de 95% de acurácia, G está morto.
  • Gerador memoriza um modo. Adicione ruído às entradas de D, use uma camada de discriminação de minilote (minibatch-discriminator) ou mude para WGAN-GP.
  • Vazamento de estatísticas no Batch Norm. O fluxo do lote real + lote falso através da mesma camada BN mistura suas estatísticas. Use normalização de instância (instance norm) ou normalização espectral (spectral norm).
  • Manipulação do Inception Score. FID e IS são ruidosos com poucas amostras. Use ≥10k amostras na avaliação.
  • Amostragem em um único passo é uma mentira para tarefas condicionais. Você ainda precisa de escalas CFG, truques de truncamento e reamostragem para obter saídas utilizáveis.

Use It

A pilha de GAN em 2026:

Situação Escolha
Rostos humanos fotorrealistas, pose fixa StyleGAN3 (mais nítido, menor)
Rostos de anime / estilizados StyleGAN-XL ou LoRA de Stable Diffusion
Tradução de imagem para imagem Pix2Pix / CycleGAN (Fase 8 · 04) ou ControlNet (Fase 8 · 08)
Texto para imagem rápido de 1 passo Destilação adversarial de difusão (SDXL-Turbo, SD3-Turbo)
Perda perceptual dentro de um treinador de difusão Discriminador GAN pequeno em recortes de imagem (crops)
Qualquer coisa multimodal e aberta Não use — use difusão ou flow matching

As GANs são nítidas, mas limitadas. Assim que seu domínio se expandir — fotos, prompts de texto arbitrários, vídeo —, mude para difusão. O truque adversarial sobrevive como um componente (perdas perceptuais, destilação), não como um gerador independente.

Ship It

Salve outputs/skill-gan-debugger.md. A Skill analisa uma execução de GAN com falhas (curvas de perda, grade de amostras, tamanho do conjunto de dados) e gera uma lista classificada das causas prováveis, correções de uma única linha e um protocolo de reexecução.

Exercícios

  1. Fácil. Execute code/main.py com as configurações padrão. Em seguida, defina D_LR = 5 * G_LR e execute novamente. Quão rápido a perda de G colapsa para uma constante?
  2. Médio. Substitua a perda clássica BCE de Goodfellow pela perda WGAN: loss_D = E[D(fake)] - E[D(real)], loss_G = -E[D(fake)] e limite os pesos de D no intervalo [-0.01, 0.01]. O treinamento fica mais estável? Compare o tempo de convergência real (tempo de relógio).
  3. Difícil. Estenda o exemplo 1-D para dados 2-D (uma mistura de 8 Gaussianas em um anel). Acompanhe quantos dos 8 modos o gerador captura nos passos 1k, 5k e 10k. Implemente discriminação de minilote (minibatch discrimination) e meça novamente.

Termos-chave

Termo O que dizem O que realmente significa
Gerador "G" Rede de ruído para amostra, G: z → x̂.
Discriminador "D" Classificador D: x → [0, 1], real vs falso.
Minimax "O jogo" min_G max_D of a joint objective.
Perda não saturada "A correção" Usar -log D(G(z)) para G em vez de log(1 - D(G(z))).
Colapso de modo "G memorizou uma coisa" O gerador o produz poucas saídas distintas, apesar dos dados diversos.
WGAN "Wasserstein" Substitui BCE pela distância Earth-Mover + penalidade de gradiente; gradiente mais suave.
Normalização espectral "Truque de Lipschitz" Restringe as normas dos pesos de D para limitar sua inclinação; estabiliza o treinamento.
StyleGAN "A que funciona" Rede de mapeamento + AdaIN; melhor da categoria para rostos, ainda em 2026.

Nota de produção: a inferência em um único passo é a vantagem duradoura das GANs

As GANs não vencem mais em qualidade de amostra para geração de domínio aberto, mas ainda vencem no custo de inferência. No vocabulário da literatura de inferência em produção, uma GAN tem:

  • Sem etapas de prefill ou decode. Uma única passada para a frente de G(z). TTFT ≈ latência total.
  • Sem pressão de KV-cache. O único estado são os pesos. O tamanho do lote é limitado pela memória de ativação, não pelo cache.
  • Loteamento contínuo trivial. Como cada solicitação consome a mesma quantidade de FLOPs fixos, un lote estático na capacidade alvo do servidor geralmente é ideal. Nenhum agendador dinâmico (in-flight scheduler) é necessário.

É por isso que a destilação GAN (SDXL-Turbo, SD3-Turbo, ADD, LCM) é a técnica dominante para texto para imagem rápido em 2026: ela colapsa um pipeline de difusão de 20-50 passos em 1-4 passadas para a frente estilo GAN, mantendo a distribuição de uma base de difusão. A perda adversarial sobrevive como um parâmetro em tempo de treinamento para transformar geradores lentos em rápidos.

Leituras Complementares

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