Generative Adversarial Networks

Demonstrações interativas da aula de GANs

Quatro visualizações que acompanham os slides: o jogo adversarial no exemplo toy 1D, em que o gerador x* = g[z, θ] = z + θ tem um único parâmetro e o discriminador σ(f[x, ϕ]) é treinado em alternância; o discriminador ótimo D*(x) = P(x) / (P(x) + P*(x)) e a divergência de Jensen-Shannon; a decomposição da DJS em qualidade e cobertura, que explica o colapso de moda; e a comparação entre DJS e a distância de Wasserstein quando as distribuições se afastam. Notação dos slides: P(x) real, P*(x) gerada, M = ½(P + P*), DJS ≤ ln 2 ≈ 0.693 nats.

1 · O jogo adversarial em 1D

O exemplo toy dos slides: os dados reais vêm de 𝒩(7, 1), o latente de z ~ 𝒩(0, 1) e o gerador tem um único parâmetro de translação, x* = z + θ, então P*(x) = 𝒩(θ, 1). O discriminador σ(f[x, ϕ]) usa um logit linear f[x, ϕ] = a·x + b e minimiza a entropia cruzada (reais com y = 1, geradas com y = 0). O treino alterna k passos do discriminador e um passo do gerador. Para o gerador, compare a loss original L[θ] = Σ ln[1 − σ(f[x*, ϕ])] com a non-saturating LNS[θ] = Σ −ln[σ(f[x*, ϕ])]: quando o discriminador vence (σ ≈ 0), a original quase não gera gradiente.

P(x) real, P*(x) gerada, amostras do minibatch e a sigmóide σ(f[x, ϕ]) (eixo da direita, 0 a 1); arraste no gráfico para mover θ

θ por passo de gerador (tracejado: alvo θ = 7)

💡 Comece com θ0 = 3 e a loss non-saturating: θ sobe até 7 e a sigmóide achata em 0.5, como no painel (c) dos slides. Agora reinicie com θ0 = −3, k = 10 e a loss original: o discriminador fica perto do ótimo, σ(f[x*, ϕ]) ≈ 0, |∂L/∂θ| no medidor despenca e o gerador quase não se move. Troque para non-saturating sem reiniciar e veja o gradiente voltar com força. Perto do equilíbrio θ oscila em vez de assentar: gerador e discriminador continuam reagindo um ao outro, a instabilidade típica do treino de GANs.

2 · O discriminador ótimo e a divergência de Jensen-Shannon

Pela regra de Bayes com P(real) = P(gen) = ½, o discriminador ótimo depende só das densidades: D*(x) = P(x) / (P(x) + P*(x)). Substituindo D* na loss, cada termo vira uma KL contra a mistura M = ½(P + P*) e o resultado da aula aparece: L[ϕ] = 2·DJS[P* ‖ P] − 2 ln 2. Aqui P(x) = 𝒩(7, 1) é fixa e você controla a gerada P*(x) = 𝒩(μ*, σ*²). Onde P domina, D* → 1; onde P* domina, D* → 0; onde as densidades coincidem, D* = ½.

P(x), P*(x), mistura M(x) e D*(x) (eixo da direita, 0 a 1); arraste para mover μ*

DJS[P* ‖ P] em função de μ* (tracejado: ln 2)

💡 Com μ* = 7 e σ* = 1 as densidades coincidem, D* fica plano em 0.5 e DJS = 0 (gerador perfeito). Arraste μ* para 14: D* vira um degrau e a curva da direita satura em ln 2 ≈ 0.693 nats, com derivada |∂DJS/∂μ*| quase nula no medidor, é o platô que vai causar o vanishing gradient. Diminua σ* para 0.4 e note que mesmo com μ* = 7 a divergência não zera: a forma também conta.

3 · Colapso de moda: qualidade vs cobertura

A decomposição vista em aula separa a divergência em dois termos: DJS[P* ‖ P] = ½·DKL[P* ‖ M] (qualidade, penaliza amostras geradas implausíveis) + ½·DKL[P ‖ M] (cobertura, penaliza modas reais ignoradas). Quando P*(x) ≪ P(x) numa região, o integrando da cobertura satura em ½·P(x)·ln 2, independente do gerador: deixar uma moda de fora custa um valor fixo que o gerador não consegue reduzir aos poucos. Abaixo, P(x) é bimodal (modas em −1.5 e 4, como na figura dos slides) e o gerador é unimodal, P*(x) = 𝒩(μ*, σ*²). O botão ▶ treina μ* por descida de gradiente sobre a própria DJS (σ* fica fixo no valor do slider, como o gerador de um parâmetro da seção 1).

P(x) bimodal, P*(x) gerada e mistura M(x); arraste para mover μ*

DJS em função de μ* (σ* atual): dois vales, um por moda

Integrandos: ½·P*·ln(P*/M) em laranja (qualidade) e ½·P·ln(P/M) em ciano (cobertura); área líquida = cada termo

💡 Treine partindo de μ* = 1: o gerador desliza para a moda em −1.5 e para. O termo de qualidade despenca, mas o lombo ciano em torno de x = 4 não se move: a moda ignorada contribui ½·0.5·ln 2 ≈ 0.17 nats de cobertura, independentes de μ*. Reinicie com μ* = 3 e ele colapsa para a outra moda: a curva DJS(μ*) tem dois mínimos locais, um por moda, e o gradiente nunca cruza a barreira entre eles. Aumente σ* para 1.5 e veja a barreira amolecer (o gerador largo cobre as duas modas, mas com qualidade pior); reduza o peso da moda em 4 para 0.05 e compare quanto a cobertura presa diminui.

4 · Vanishing gradient: Jensen-Shannon vs Wasserstein

Em alta dimensão, P e P* vivem em manifolds que quase nunca se cruzam: suportes praticamente disjuntos são a regra, não a exceção. Nesse regime DJS trava em ln 2 e o gradiente do gerador desaparece. A distância de Wasserstein mede o trabalho de transportar massa (massa × distância movida) e cresce linearmente com a separação: para P = 𝒩(0, 1) e P* = 𝒩(d, 1), vale W = d. Na forma dual de Kantorovich-Rubinstein, o crítico f é 1-Lipschitz (|∂f/∂x| ≤ 1, imposto por weight clipping ou gradient penalty) e o ótimo aqui é uma reta de inclinação constante: gradiente informativo em toda parte, ao contrário da sigmóide saturada.

P(x), P*(x), discriminador ótimo D*(x) saturado e crítico 1-Lipschitz f(x) (reta, escala própria); arraste para mudar d

DJS(d) satura em ln 2; W(d) = d cresce sem teto (escala à direita)

Sinal de gradiente |∂/∂d|: JS some, Wasserstein é constante

💡 Com d = 8 e a aba DJS, aperte ▶: o gerador fica congelado, o medidor mostra |∂DJS/∂d| na casa de 10⁻⁵, é o vanishing gradient do experimento de Arjovsky visto em aula. Troque para a aba Wasserstein e o mesmo ponto desliza até d = 0 em velocidade constante, pois |∂W/∂d| = 1 sempre. Com d ≈ 2 (suportes ainda sobrepostos) a JS também funciona: o problema aparece justamente quando o discriminador fica bom demais.