18. GANs
Durante sete anos, GAN era como se gerava uma imagem. Então, em cerca de dezoito meses, deixou de ser — a difusão tomou a tarefa de manchete e não a devolveu. Um capítulo que apresentasse GANs como estado da arte estaria ensinando 2019.
Então este capítulo faz algo mais útil. A arquitetura perdeu; a ideia, não. Uma perda adversarial — aprenda o que "realista" significa em vez de especificar — está rodando agora mesmo dentro do decodificador do autoencoder do Stable Diffusion, dentro do vocoder que transforma sua saída de texto-para-fala em áudio e dentro da destilação que torna possível um gerador de imagens de um passo. A GAN deixou de ser o modelo. Ela virou uma função de perda e está em toda parte.
Slides
Clique nos slides e use as setas ← → para navegar; F abre em tela cheia e P abre a visão do apresentador, com as notas. Os dois simuladores desta página rodam dentro dos slides. Abrir os slides numa aba nova
Simulador: NetLab · GAN nas luas
Esta aula tem o seu próprio cenário no NetLab, o laboratório de redes do curso: o grafo já vem montado, com uma nota do que experimentar e um link de volta para cá. Treine, mude, quebre. Um grafo que você tinha no simulador não se perde: fica a um Ctrl+Z.
A ideia: uma perda que você não consegue escrever
Suponha que você queira gerar rostos. Qual é a perda?
A perda \(\ell_2\) (o erro quadrático \(\lVert G(z) - x \rVert_2^2\) entre a saída e uma imagem-alvo, pixel a pixel) não funciona: não há alvo e fazer média sobre rostos plausíveis dá o borrão do capítulo 17. Medidas de "realismo" projetadas à mão falham de imediato: qualquer uma que alguém já tenha escrito é trivialmente satisfeita por algo que não se parece nem um pouco com um rosto.
A resposta de Goodfellow1 é parar de escrever a perda e aprendê-la. Treine uma segunda rede — um discriminador — cujo único trabalho é distinguir dados reais de dados gerados. Aquilo que ele encontrar para distingui-los é a medida de realismo e ela se atualiza conforme o gerador melhora.
O gerador leva ruído a dados; o discriminador julga. Nenhum dos dois recebe uma descrição do que "realista" significa. Uma introdução com o mesmo desenho: 4.
Dois jogadores, uma função de valor:
Aqui \(p_{\text{data}}\) é a distribuição dos dados reais, \(p_z\) a do ruído (\(\mathcal{N}(0, I)\) no diagrama) e \(p_G\) a das amostras geradas \(G(z)\). O ruído \(z\) é um vetor de \(\mathbb{R}^k\) e o tamanho \(k\) é a dimensão latente. Ela não vem dos dados: é uma escolha de projeto, como a largura de uma camada (100 na DCGAN, 512 no StyleGAN). O discriminador maximiza \(V\) — empurrando \(D(x) \to 1\) nos dados reais e \(D(G(z)) \to 0\) nos falsos. O gerador a minimiza. No ótimo teórico \(p_G = p_{\text{data}}\) e \(D \equiv 1/2\): o discriminador não consegue fazer melhor que cara ou coroa.
A perda do gerador que está no artigo não é a que se usa
Escreva a saída do discriminador como \(D = \sigma(\ell)\), uma sigmoide de um logit \(\ell\). Minimizar \(\log(1 - D(G(z)))\), o termo de \(V\) que cabe ao gerador (a perda minimax), dá um gradiente em relação a \(\ell\) de \(-D(G(z))\), que some exatamente quando o discriminador está ganhando — ou seja, cedo no treino, quando o gerador mais precisa de sinal. Em \(D(G(z)) = 0{,}01\) ele vale \(-0{,}01\). A correção, no mesmo artigo: maximize \(\log D(G(z))\), ou seja, minimize \(-\log D(G(z))\), cujo gradiente é \(D(G(z)) - 1 = -0{,}99\) no mesmo ponto. Mesmo ponto fixo, gradiente forte quando você está perdendo. Essa é a perda não saturante e é o que quase toda implementação contém. O laboratório mede a diferença numa rede de verdade: na GAN de MNIST dele, depois de uma pequena vantagem inicial para o discriminador, o gradiente não saturante é cerca de 1 900 vezes maior.
Um passo de treino do laço do laboratório, linha a linha (um passo do discriminador, depois um do gerador), com um \(D\) de uma unidade e um \(G\) que é uma reta, em dados 1-D, para que cada número possa ser conferido à mão. O caso inicial é o exemplo acima (\(D(G(z)) = 0{,}01\)); troque a perda do gerador para ver o \(-0{,}99\) virar \(-0{,}01\):
O que o discriminador aprende
Fixe o gerador e pergunte qual discriminador maximiza \(V\). Ponto a ponto, \(D(x)\) deve maximizar \(p_{\text{data}}(x)\log D + p_G(x)\log(1 - D)\) e igualar a derivada a zero dá
O discriminador é um estimador de razão de densidades. Onde os dados são três vezes mais densos que as amostras do gerador, \(D^* = 3/(3+1) = 0{,}75\); onde as duas densidades são iguais, \(D^* = 1/2\); onde o gerador põe massa e os dados não têm nenhuma, \(D^* = 0\). O gradiente dele, portanto, aponta o gerador para as regiões onde falta massa.
Substituindo \(D^*\) de volta em \(V\):
Então, contra um discriminador ótimo, o gerador minimiza a divergência de Jensen–Shannon e a melhor perda do discriminador (a entropia cruzada binária, \(-V\)) é \(2\log 2 - 2\,\mathrm{JS}\). Daí saem os valores de referência para ler um treino. No equilíbrio, a perda do discriminador fica em \(2\log 2 \approx 1{,}39\) e a perda não saturante do gerador em \(\log 2 \approx 0{,}69\). Uma perda do discriminador perto de zero não é progresso: significa que o discriminador separa reais de falsos perfeitamente.
Treinando uma e olhando o que não dá para ver
Abaixo há uma GAN de verdade — dois MLPs, retropropagação escrita à mão, Adam — treinada no seu navegador sobre oito gaussianas dispostas em anel. Cada gaussiana é um modo da distribuição: um pico de densidade, um aglomerado onde os dados se concentram. Um bom gerador põe amostras nos oito. Um gerador que se contenta com alguns sofre colapso de modos.
O painel da esquerda já vale por si: a superfície de decisão do discriminador não se assenta, porque não existe alvo fixo. Ela se remodela em volta de onde quer que o gerador esteja colocando massa e o gerador a persegue. Isto é um jogo de dois jogadores e não uma otimização: um jogo não tem um valor que precise descer.
Agora o terceiro painel, que é o ponto do exercício inteiro. A linha laranja é \(D(G(z))\) — o que o laço de treino vê e aquilo a partir do qual as duas perdas são calculadas. Ela fica perto de 0,5 e ali permanece. A linha verde é a cobertura de modos, medida à parte, por código que o laço de treino nunca roda.
Ponha a dimensão latente em 1 e retreine. Agora o gerador é uma função contínua de um único número, então todas as amostras dele ficam sobre uma curva. Na nossa primeira execução com esse ajuste ele cobriu 2 dos 8 modos e 57% das amostras caíram fora dos dados — e a linha laranja não se mexeu. Com um latente 2-D, de 18% a 52% das amostras ainda caíram fora dos dados nas nossas execuções: um gerador contínuo leva um espaço latente conexo a um conjunto conexo, então precisa esticar pontes finas entre modos separados.
Os outros dois controles valem uma execução cada. Com três passos do discriminador por passo do gerador, nossa execução chegou aos 8 modos. A perda minimax também treina aqui, porque neste painel o discriminador nunca abre muita vantagem (onde \(D(G(z))\) fica perto de 0,5, os dois gradientes têm o mesmo tamanho). Ela falha quando o discriminador vence os primeiros passos, como acontece com imagens; o laboratório mede esse caso.
Este é o problema real das GANs e não é instabilidade
Uma GAN não tem perda que se possa ler. Uma perda que cai não significa nada. Não há critério fundamentado de early stopping, não há como comparar duas execuções pelas curvas, não há como saber se um checkpoint é melhor que o anterior sem gerar amostras e avaliá-las com uma métrica separada que você mesmo teve de escolher.
Retreine o painel algumas vezes com os mesmos ajustes e veja a linha verde parar em lugares diferentes a cada vez (nossas oito execuções com os ajustes padrão terminaram em 7, 5, 8, 6, 6, 8, 8 e 8 modos). Essa variância — invisível ao laço de treino — é o que tornou GANs caras de colocar em produção e é uma das principais razões pelas quais a difusão as substituiu. A difusão tem uma perda de regressão comum, que desce.
Os modos de falha, nomeados
| Falha | Como aparece | Por que acontece |
|---|---|---|
| Colapso de modos | O gerador produz poucas saídas, independentemente de \(z\) | Nada no objetivo premia diversidade. Se uma saída engana o discriminador atual, produzir só aquela saída é uma jogada perfeitamente boa. Comportamento tipo KL reversa2 (capítulo 16). |
| Gradiente do gerador some | O treino trava, \(D(G(z)) \to 0\) | O discriminador venceu completo demais. A perda não saturante ajuda; equilibrar os dois jogadores (taxas de aprendizado, passos do discriminador por passo do gerador) também ajuda. |
| Oscilação | A qualidade sobe, cai, sobe | Os dois jogadores entram em ciclo. Não há razão para um jogo convergir e muitas vezes ele não converge. |
| Overfitting do discriminador | A qualidade das amostras melhora e depois piora | O discriminador decora o conjunto de treino (confiante nas imagens de treino, não nas reais que ele não viu) e o gradiente dele deixa de descrever a distribuição. Foi isso que limitou GANs em conjuntos pequenos até a augmentation adaptativa. |
O colapso não precisa de nada exótico. No laboratório, a mesma GAN pequena sobre o anel cobre 7–8 modos com as duas taxas de aprendizado em \(10^{-3}\). Corte só a taxa do discriminador para \(2 \times 10^{-4}\) e as três sementes terminam com 0 modos cobertos: o gerador junta todas as amostras num aglomerado entre dois modos e o arrasta pelo anel conforme a fronteira lenta se move. O \(D(G(z))\) dele fica entre 0,48 e 0,51 e a perda do discriminador entre 1,32 e 1,43 — as curvas parecem mais equilibradas que nas execuções que funcionam. Cinco passos do discriminador por passo do gerador trazem a cobertura de volta a 6–8 modos.
As mitigações que ficaram: WGAN-GP157 (troque a divergência JS por uma distância de Wasserstein e restrinja o gradiente do crítico, como a WGAN chama o discriminador — quando as duas distribuições não se sobrepõem, a JS fica presa em \(\log 2\) por mais longe que elas estejam, então não dá direção, enquanto a distância de Wasserstein continua crescendo com a distância), normalização espectral8 (limite a constante de Lipschitz do discriminador, o máximo que a saída dele pode variar por unidade de variação da entrada; uma linha de código), regularização R19 (penalize o gradiente do discriminador nos dados reais) e augmentation adaptativa do discriminador (ADA)10 (aumente o que o discriminador vê para que ele não decore). Cada uma é, no fundo, o mesmo movimento: impedir o discriminador de ficar afiado demais, porque um discriminador perfeitamente confiante entrega ao gerador um gradiente que não aponta para lugar nenhum.
GAN Lab: o mesmo jogo, com todos os botões
O GAN Lab13 mostra mais da maquinaria que o painel acima e deixa você mudar os hiperparâmetros enquanto o modelo treina.
Simulador: GAN Lab
Uma GAN interativa da Georgia Tech e do Google, treinada ao vivo no navegador com TensorFlow.js sobre distribuições 2-D. Ele pede uma tela larga: abra numa aba própria e mantenha esta página ao lado.
A linhagem, em resumo
| Modelo | A contribuição |
|---|---|
| DCGAN (2015)3 Deep Convolutional GAN: GAN convolucional profunda | Gerador e discriminador convolucionais e um conjunto de regras empíricas que tornaram o treino de GANs reprodutível. |
| GAN condicional (2014)14 GAN: Generative Adversarial Network, rede adversarial generativa | Alimente um rótulo nas duas redes. Ancestral de todo modelo generativo condicionado, este curso incluído. |
| pix2pix / CycleGAN (2017)1617 pix2pix: de pixels para pixels · CycleGAN: GAN com consistência de ciclo | Tradução imagem-para-imagem e — com consistência de ciclo — sem dados pareados. |
| WGAN / WGAN-GP (2017)157 Wasserstein GAN · GP: gradient penalty, penalidade de gradiente | Uma divergência diferente e uma perda que ao menos correlaciona com qualidade. |
| StyleGAN 1–3 (2019–2021)5 GAN de gerador baseado em estilo (style-based) | Ainda os rostos mais bonitos produzidos por uma GAN e a origem do espaço latente \(\mathcal{W}\) desemaranhado que fez a edição semântica funcionar. |
| GigaGAN (2023)6 giga: cerca de 1 bilhão de parâmetros | Texto-para-imagem com qualidade competitiva com difusão e ordens de grandeza mais rápido na inferência (0,13 s para uma imagem de 512 px). Chegou depois de a área ter migrado para a difusão. |
Simulador: This Person Does Not Exist
A cada recarga da página um StyleGAN treinado em fotos de rostos gera uma pessoa que não existe. Recarregue algumas vezes e procure os defeitos típicos: brincos diferentes nas duas orelhas, fundos sem sentido, dentes e armações de óculos deformados.
O StyleGAN ainda vale a leitura
Não pela arquitetura, mas pelo espaço \(\mathcal{W}\): um latente em que direções correspondem a atributos interpretáveis — idade, pose, expressão — de modo que editar é aritmética de vetores. Nada em difusão é tão limpo assim e edição latente é área de pesquisa ativa precisamente porque essa propriedade se perdeu.
Onde a perda adversarial de fato vive hoje
Esta é a parte para lembrar, porque você vai usá-la sem nunca treinar uma GAN de ponta a ponta.
| Onde | O que o discriminador faz |
|---|---|
| O decodificador do VAE em todo modelo de difusão latente | Só perda de reconstrução dá borrão. Um discriminador sobre a saída do decodificador pune exatamente essa suavidade — é a receita do VQGAN11 e é por isso que o decodificador do Stable Diffusion produz textura nítida. É o uso mais amplamente implantado de perda adversarial hoje. |
| Super-resolução | Ampliar é um problema um-para-muitos, então o \(\ell_2\) devolve a média e você fica com papa. O Real-ESRGAN18 e seus descendentes são treinados adversarialmente. |
| Vocoders neurais | O HiFi-GAN19 e seus sucessores transformam espectrogramas em formas de onda em muitos dos sistemas de texto-para-fala em produção. |
| Destilação de um e dois passos | Comprimir um modelo de difusão de 50 passos em 1–4 exige uma perda que diga "isto parece real", não "isto casa com a média do professor". A destilação adversarial de difusão12 é como o SDXL-Turbo e parentes chegam a tempo real. |
| Adaptação de domínio | Um classificador adversarial que não consegue distinguir origem de destino força features invariantes ao domínio20. |
O padrão, enunciado uma vez
Use uma perda adversarial quando o alvo é uma entre muitas respostas válidas e fazer média delas é errado. Isso descreve ampliar, decodificar, vocodificar e destilar em um passo. Não descreve classificação, onde média está tudo bem — e é por isso que a ideia adversarial sobreviveu exatamente onde o \(\ell_2\) falha.
Laboratório: o jogo, medido
Cada afirmação desta página é medida num notebook no Colab: primeiro no anel de oito gaussianas (na CPU, poucos minutos), depois com uma GAN convolucional pequena no MNIST (escolha uma GPU T4 no Colab). Nove seções, cada uma terminando num checkpoint com um valor de verificação:
- o anel e um medidor de cobertura que o laço de treino nunca vê;
- o discriminador ótimo: um \(D\) treinado contra a fórmula \(p_{\text{data}}/(p_{\text{data}} + p_G)\) e a melhor perda contra \(2\log 2 - 2\,\mathrm{JS}\);
- uma GAN no anel e como ler as curvas de perda dela;
- minimax contra não saturante: o gradiente em \(D = 0{,}01\), o gradiente depois de uma vantagem inicial do discriminador e o que o SGD e o Adam fazem com ele;
- colapso de modos provocado por um discriminador lento (invisível em \(D(G(z))\)) e corrigido com mais passos do discriminador;
- uma DCGAN no MNIST (ampliar + convoluir), treinada por três épocas;
- quais dígitos ela faz, medido com um classificador;
- a saturação de novo, em imagens;
- sua vez: quebre a DCGAN, conserte e confira o que as curvas diziam.
Abrir o laboratório no Colab — salve uma cópia no seu Drive (Arquivo → Salvar uma cópia no Drive) para rodar e editar.
Pontos-chave
- Uma GAN aprende a própria perda. O trabalho do discriminador é descobrir o que "realista" significa para que você não precise especificar. Contra um gerador fixo, o ótimo dele é a razão de densidades \(p_{\text{data}}/(p_{\text{data}} + p_G)\).
- A perda do gerador do artigo original satura; todo mundo usa a forma não saturante \(-\log D(G(z))\). Mesmo ponto fixo, um gradiente que é grande quando o gerador está perdendo.
- O problema real não é instabilidade, é impossibilidade de medir: \(D(G(z))\) fica perto de 0,5 tanto com um modelo excelente quanto com um colapsado. Não há perda em que fazer early stopping. No equilíbrio as perdas ficam em \(2\log 2\) e \(\log 2\); elas não descem.
- Colapso de modos é o que o objetivo permite, não um acidente — nada nele premia diversidade. Um par de jogadores desequilibrado basta para provocá-lo.
- Toda estabilização que ficou faz a mesma coisa: impedir o discriminador de ficar afiado demais (WGAN-GP, norma espectral, R1, ADA).
- A difusão venceu porque tem uma perda de regressão comum, que desce, é estável e cobre modos. As GANs ainda vencem em velocidade de inferência — uma passagem direta.
- A perda adversarial está em toda parte: em decodificadores de autoencoders latentes, super-resolução, vocoders e destilação de poucos passos. Use-a quando a resposta é uma entre muitas e fazer média é errado.
-
Goodfellow, I., et al. (2014). Generative Adversarial Networks — NeurIPS. O problema da saturação e a correção não saturante estão os dois na seção 3; o discriminador ótimo e a divergência JS, na seção 4. ↩
-
Radford, A., Metz, L., & Chintala, S. (2016). Unsupervised Representation Learning with Deep Convolutional Generative Adversarial Networks — ICLR. DCGAN. ↩
-
Silva, T. — A Short Introduction to Generative Adversarial Networks. ↩
-
Karras, T., Laine, S., & Aila, T. (2019). A Style-Based Generator Architecture for Generative Adversarial Networks — CVPR. StyleGAN e o espaço latente \(\mathcal{W}\). ↩
-
Kang, M., et al. (2023). Scaling up GANs for Text-to-Image Synthesis — CVPR. GigaGAN: qualidade competitiva, ordens de grandeza mais rápido na inferência, publicado depois de a área ter ido para a difusão. ↩
-
Gulrajani, I., et al. (2017). Improved Training of Wasserstein GANs — NeurIPS. WGAN-GP. ↩↩
-
Miyato, T., et al. (2018). Spectral Normalization for Generative Adversarial Networks — ICLR. Uma linha, efeito grande. ↩
-
Mescheder, L., Geiger, A., & Nowozin, S. (2018). Which Training Methods for GANs do actually Converge? — ICML. De onde vem o R1, com a análise de convergência. ↩
-
Karras, T., et al. (2020). Training Generative Adversarial Networks with Limited Data — NeurIPS. Augmentation adaptativa do discriminador. ↩
-
Esser, P., Rombach, R., & Ommer, B. (2021). Taming Transformers for High-Resolution Image Synthesis — CVPR. VQGAN: o decodificador adversarial + perceptual que todo modelo de difusão latente herdou. ↩
-
Sauer, A., Lorenz, D., Blattmann, A., & Rombach, R. (2024). Adversarial Diffusion Distillation — ECCV. SDXL-Turbo; um discriminador é o que faz a amostragem de um passo parecer real. ↩
-
Kahng, M., Thorat, N., Chau, D. H., Viégas, F. B., & Wattenberg, M. (2019). GAN Lab: Understanding Complex Deep Generative Models using Interactive Visual Experimentation — IEEE TVCG 25(1) (VIS 2018). Ferramenta e código-fonte. ↩
-
Mirza, M., & Osindero, S. (2014). Conditional Generative Adversarial Nets. arXiv. ↩
-
Arjovsky, M., Chintala, S., & Bottou, L. (2017). Wasserstein Generative Adversarial Networks — ICML. Por que a JS não dá gradiente quando os suportes não se sobrepõem e a distância do transportador de terra (earth mover's) no lugar dela. ↩↩
-
Isola, P., Zhu, J.-Y., Zhou, T., & Efros, A. A. (2017). Image-to-Image Translation with Conditional Adversarial Networks — CVPR. pix2pix. ↩
-
Zhu, J.-Y., Park, T., Isola, P., & Efros, A. A. (2017). Unpaired Image-to-Image Translation using Cycle-Consistent Adversarial Networks — ICCV. CycleGAN. ↩
-
Wang, X., Xie, L., Dong, C., & Shan, Y. (2021). Real-ESRGAN: Training Real-World Blind Super-Resolution with Pure Synthetic Data — ICCV Workshops. ↩
-
Kong, J., Kim, J., & Bae, J. (2020). HiFi-GAN: Generative Adversarial Networks for Efficient and High Fidelity Speech Synthesis — NeurIPS. ↩
-
Ganin, Y., & Lempitsky, V. (2015). Unsupervised Domain Adaptation by Backpropagation — ICML. A camada de inversão de gradiente. ↩