Redes Neurais Artificiais e Deep Learning · Insper

Autoencoders Variacionais

Um compressor com um espaço latente moldado

Dois veredictos sobre o mesmo modelo

Julgado como gerador de imagens, o VAE perdeu: amostras borradas, superado pelas GANs e depois pela difusão.
Julgado pelo uso em produção, toda imagem de difusão latente que você já viu foi decodificada por um deles.
Como as duas coisas podem ser verdade?

  • Um VAE não é bem um gerador. É um compressor com um espaço latente moldado.
  • O borrão é uma escolha de objetivo — e em produção outra coisa (uma perda perceptual e uma adversarial) o corrige adiante.

Comece por um autoencoder

Um autoencoder: a imagem de entrada passa por um encoder até um código pequeno (o gargalo) e um decoder transforma o código de volta numa imagem que a perda compara com a entrada. x imagem de entrada E encoder GARGALO código z poucos números D decoder o = D(E(x)) reconstrução L = ‖x − o‖²compara a saída com a entrada

Um encoder espreme num código pequeno, o gargalo; um decoder traz de volta e a perda compara a reconstrução com . O gargalo é o mecanismo inteiro: a rede só reconstrói se o código guardar o que importa.

Decodifique um ponto aleatório

Treine, escolha um ponto aleatório do espaço latente e decodifique. O que sai?

  • Lixo, em geral. A reconstrução só pede que cada entrada vá para algum código que o decoder consiga inverter.
  • Os códigos se espalham para onde o treino os empurrou, com buracos entre eles onde o decoder nunca foi treinado.
  • Para amostrar é preciso uma distribuição de onde amostrar. Um autoencoder te dá pontos.

O VAE: codifique uma distribuição, não um ponto

Um VAE: o encoder produz uma média e uma log-variância, o código é z = μ + σ ⊙ ε com ruído ε sorteado de N(0, I) e o decoder reconstrói x̂. A perda tem um termo de reconstrução entre x e x̂ e um termo de KL que puxa cada gaussiana para o prior. x E qφ(z | x) μ(x) média log σ²(x) log-variância KL( q(z | x) ‖ 𝒩(0, I) ) puxa cada gaussiana para o prior z z = μ + σ ⊙ ε ε ~ 𝒩(0, I) o ruído entra como dado D pθ(x | z) x̂ reconstrução: ‖x − x̂‖²

O encoder produz e : uma gaussiana por entrada, . Um código é sorteado dela e decodificado; o termo de KL puxa cada gaussiana na direção de um prior do qual se sabe amostrar, . : os pesos do encoder · : os do decoder · : média 0 e variância 1 em cada dimensão do latente.

Pontos contra nuvens

Dois espaços latentes. À esquerda, um autoencoder: grupos apertados de códigos longe uns dos outros e amostras de N(0, I) caindo no espaço vazio entre eles. À direita, um VAE: uma gaussiana por entrada, todas sobrepostas dentro do prior. As mesmas amostras caem dentro das nuvens. AUTOENCODER · um ponto por entrada 𝒩(0, I) Os códigos vão para onde o treino empurrou: as amostras × caem nos buracos. VAE · uma gaussiana por entrada 𝒩(0, I) As nuvens se sobrepõem dentro do prior: todo × cai onde o decoder foi treinado. uma amostra de 𝒩(0, I): nenhum código esteve aqui a mesma amostra, dentro de uma nuvem

As gaussianas de entradas vizinhas se sobrepõem. A sobreposição preenche o espaço entre os exemplos de treino e é o que faz uma amostra de cair onde o decoder conhece. Por que essa perda e não outra? Os próximos slides a deduzem em cinco passos.

Passo 1 · O que gostaríamos de maximizar

Uma história generativa: sorteie e depois . A máxima verossimilhança pede a evidência

O quanto o modelo acredita em : o E de ELBO.

  • Estimar sorteando do prior? Quase todo assim decodifica em outra imagem: a média fica decidida por poucos sorteios sortudos.
  • Os códigos que importam para são os que a posterior aponta…
  • …e calcular a posterior exige . O problema é circular.

Passo 2 · Chute a posterior e depois meça o chute

O encoder chuta , uma média e uma variância por dimensão. Então, só com igualdades:

  1. Uma KL nunca é negativa, então o ELBO é um limite inferior da evidência: em inglês, Evidence Lower BOund.
  2. A folga é exatamente o quanto o chute do encoder está errado.
  3. Subir o ELBO diminui a folga (encoder) e sobe o próprio (decoder): um objetivo treina as duas redes.

Como sai: (não depende de ) (Bayes); multiplique e divida por dentro do log. (apêndice).

Passo 3 · Os dois termos que você vai programar

Ponha dentro do ELBO do passo 2 e ele se separa em dois termos:

termo se fosse o único
reconstrução , códigos em qualquer lugar: um autoencoder
KL até o prior para todo , o código não diz nada: colapso do posterior

Duas KLs diferentes. A perda tem a KL até o prior (conhecida, em forma fechada). A KL até a posterior é a folga — ninguém a calcula e o ELBO nunca precisa dela.

Mapa dos termos

Um mapa dos termos do ELBO. À esquerda, o caminho de uma imagem: x, o encoder q(z | x), o código z, o decoder p(x | z) e a reconstrução x̂. À direita, a KL até o prior, o termo de reconstrução e o ELBO, que é um menos o outro. Embaixo, a evidência e a posterior, que são do modelo mas não dá para calcular. q · a aproximação que se treina p · o modelo generativo TAMBÉM DO MODELO, MAS INTRATÁVEIS usado ao gerar folga = KL(q ‖ p(z | x)) ≥ 0 x imagem real Encoder qφ(z | x) chute da posterior: μ, σ z · código latente z = μ + σ · ε Decoder pθ(x | z) verossimilhança x̂ imagem reconstruída KL( qφ(z | x) ‖ p(z) ) termo 2 · ficar perto do prior Prior p(z) 𝒩(0, I) 𝔼q[ log pθ(x | z) ] termo 1 · reconstruir a entrada ELBO = termo 1 − termo 2 no passo 5 o termo 2 ganha um peso β Posterior p(z | x) o q tenta imitá-la Evidência log pθ(x) o ELBO fica abaixo dela

Passo 4 · Um ELBO que dá para calcular na mão

, decoder , uma observação . Aqui : média , variância .

  • Evidência: í é gaussiano com variância , então .
  • Posterior (Bayes com gaussianas): .
  • Para um chute os dois termos têm forma fechada:

O 4v vem de 𝔼q[(x − 2z)²] = (x − 2m)² + 4v. É o cabo de guerra num símbolo só: a reconstrução quer v → 0 e a KL quer v → 1.

Exercício · uma linha por extenso

Calcule o ELBO do chute , isto é, e . Quanto abaixo de ele fica?

termo fórmula, com valor
reconstrução ?
KL até o prior ?
ELBO reconstrução − KL ?
folga ?
KL até a posterior ?

Ajuda: · · entre gaussianas, (apêndice)

Uma linha por extenso · resposta

termo conta valor
reconstrução
KL até o prior
ELBO
folga
KL até a posterior

As duas últimas linhas são o mesmo número: a folga é a distância do chute até a posterior, como o passo 2 dizia.

Quatro chutes lado a lado

Cada linha com as fórmulas do passo 4; folga .

chute reconstrução KL até o prior ELBO folga
= prior −7.4189 0.0000 −7.4189 4.7953
= ponto −0.9389 2.9326 −3.8715 1.2479
= chute −1.9189 0.8181 −2.7371 0.1134
= posterior −1.4989 1.1247 −2.6237 0.0000
  • O prior não paga KL e não explica nada: o colapso em miniatura.
  • O ponto, em (decodifica exatamente em ), reconstrói melhor — é o autoencoder — e paga 2.93 nats de KL por isso.
  • A posterior não vence nenhuma coluna e tem o melhor ELBO, igual a : o ELBO premia a melhor troca, não a melhor reconstrução.

nat: a unidade de um log natural (base e) · 1 nat ≈ 1.44 bit · todo log deste deck é natural, então KL, ELBO e log p saem em nats

Passo 5 · Do ELBO à perda que você programa

  1. A esperança vira uma amostra: por imagem.
  2. vira uma perda conhecida: decoder gaussiano → erro quadrático; decoder de Bernoulli → entropia cruzada binária.
  3. A KL é escrita em forma fechada, somada sobre as dimensões latentes.
  4. A KL ganha um peso, o . O ELBO é ; deixar o livre é o β-VAE (Higgins et al., 2017).

Com ela é o ELBO negativo a menos de uma constante (decoder gaussiano de variância , cujo é ). Abaixo de 1 a reconstrução manda; acima, o prior. É onde mora o comportamento.

x̂: a saída do decoder · i percorre as dimensões do latente · σ²i = exp(logvari), a saída da segunda cabeça

Em código: formatos e um bug clássico

Um lote de imagens achatadas em pixels, um latente de dimensões.

tensor formato
x, x_hat entrada e reconstrução
mu, logvar, eps, z uma gaussiana por imagem, um novo por imagem e dimensão
reconstrução, KL somadas sobre os pixels e sobre as dimensões latentes
perda escalar média sobre o lote

reduction="mean" na reconstrução tira a média também sobre os 784 pixels — e multiplica o por 784 sem avisar.

Simulador · o ELBO em código, amostra por amostra

chute q = 𝒩(m, v)
m  v
eps · sorteios de 𝒩(0, 1)

O truque da reparametrização

é sorteado ao acaso. Quanto vale ?

  • Do jeito que está, nada: amostrar não tem derivada e o encoder não receberia gradiente nenhum da reconstrução.
  • Tire a aleatoriedade do caminho: , (: produto elemento a elemento).
  • Agora e, com (o que a cabeça produz) e , . O ruído entra como dado.

Kingma & Welling, Auto-Encoding Variational Bayes (arXiv 2013, ICLR 2014); de forma independente, Rezende, Mohamed & Wierstra (ICML 2014). Encoder, decoder e limite variacional já existiam na máquina de Helmholtz (1995): o que essa linha trouxe foi um gradiente com pouco ruído.

O truque é necessário? Medido

A função escore (REINFORCE) estima o mesmo gradiente sem derivar através de : .

Gradiente de , , no chute (, , ): uma amostra por estimativa, 100 000 estimativas, dp = desvio padrão de uma estimativa (laboratório, seção 2).

estimador média de dp média de dp
exato — —
reparametrizado 2.001 2.009 −0.505 0.878
função escore 2.032 7.084 −0.527 3.631
  • Os dois são não viesados. A dispersão de uma média cai como : e — a função escore precisa de 12 a 17× mais amostras para o mesmo ruído, em uma dimensão.
  • Ela só vê quão bom foi o . O truque vê também para que lado movê-lo, por meio de .

Simulador · uma passagem de VAE, ida e volta

O cabo de guerra, numa rede treinada

Um sorteio de pode empurrar o para qualquer lado. O que faz a média — e o que ela deveria fazer depois que o treino convergiu?

  • A parte KL é a derivada de em . Laboratório, seção 4: um VAE treinado no Fashion-MNIST, 256 imagens de teste × 16 dimensões = 4 096 entradas.
  • Parte da reconstrução: positiva em 71% das entradas e negativa no resto; média +0.311 — o ruído custa reconstrução, encolha o .
  • Parte da KL: média −0.335 — alargue o na direção de 1. As duas quase se cancelam: um encoder treinado é onde o cabo de guerra empata.

O β é a história inteira

Gire o de 0 até um valor muito grande. O que acontece com a reconstrução, com a KL — e com as amostras de ?

  • β → 0: um autoencoder. Reconstrução quase perfeita, códigos em qualquer lugar, amostras do prior caem nos buracos.
  • β numa faixa boa: o latente casa com o prior o bastante para amostrar e ainda carrega o suficiente para reconstruir.
  • β grande demais: colapso do posterior. O encoder devolve para todo , a KL vai a zero e o decoder emite a média do conjunto. A perda ainda parece estar caindo.

Como reconhecer o colapso: KL perto de zero e reconstrução perto do valor da "imagem média". Registre sempre os dois termos separadamente.

Simulador · o β, treinado no seu navegador

Medido no laboratório: o β no Fashion-MNIST

Latente de 16 dimensões, 5 épocas cada. Um classificador julga 2 000 amostras do prior decodificadas (imagens reais de teste: confiança 0.86, 6.72 classes efetivas).

β rec KL dims ativas confiança classes ef.
0 219.7 254.5 16 0.49 1.88
0.25 222.4 31.7 16 0.62 3.27
1 230.6 15.8 14 0.67 3.86
4 248.0 6.8 7 0.70 4.34
16 279.4 2.7 3 0.66 4.02
64 365.0 0.3 1 0.43 1.63
256 385.4 0.0 0 0.33 1.00

rec e KL em nats por imagem (rec: entropia cruzada somada nos 784 pixels; a imagem média para tudo dá 385.0) · dims ativas: com KL > 0.1 nat · confiança: a maior probabilidade do classificador · classes ef.: de 1 (toda amostra igual) a 10 · −ELBO = rec + KL é o menor em β = 1: 230.6 + 15.8 = 246.4.

Colapso com β = 1: um decoder forte

Dê ao decoder uma dica: a própria imagem, reduzida por average pooling, ao lado de . O β continua 1.

dica rec KL
nenhuma 230.6 15.83
4×4 228.5 7.41
7×7 223.0 1.82
14×14 213.2 0.10
28×28 204.8 0.02
  • Quanto mais o decoder faz sozinho, menos o código vale a KL que custa.
  • Com a imagem inteira o prior é o ótimo — nada falhou.
  • Free bits (λ = 0.5 nat: a KL de uma dimensão abaixo de λ não é cobrada) com a dica de 14×14: KL 0.10 → 6.94 e rec 213.2 → 211.9, mas −ELBO = rec + KL vai de 213.3 a 218.9. Eles mantêm o código vivo saindo do ótimo.

A folga, num VAE de verdade

Tire a média dos pesos antes do log, sobre amostras: continua um limite inferior e mais justo (Burda et al., 2016).

nats por imagem (500 imagens de teste)
ELBO −243.72
, amostras de −241.06
, amostras do prior −267.40
ELBO com otimizado por imagem −241.93
  • Vinda do prior, a estimativa é inútil: −267.40 fica 23.7 nats abaixo do próprio ELBO — o problema circular do passo 1, medido.

De onde vem a folga

−244−243−242−241nats por imagemamostras do prior: −267.40−243.72ELBO−241.93ELBO, q por imagem−241.06L1000log p(x): aqui ou à direitaamortização ≥ 1.79aproximação ≈ 0.87folga ≥ 2.66 nats

  • A folga nats.
  • Amortização : um encoder só para todas as imagens; otimizar imagem por imagem recupera isso.
  • Aproximação : nenhuma gaussiana diagonal, por mais bem escolhida, é a posterior verdadeira deste decoder. Uma estimativa, não um limite: as duas pontas dela são limites inferiores.

Por que as amostras são borradas

O decoder é treinado com . Várias imagens nítidas são compatíveis com o mesmo código. Qual é a saída ótima para a perda?

  • A média delas — o ótimo do erro quadrático é a média condicional. Médias de imagens são borradas.
  • O ELBO é máxima verossimilhança, ou seja, KL para frente, que é cobridora de modos: quando o modelo não consegue representar os dados exatamente, ele põe massa entre os modos.
  • Não é bug: o objetivo recebeu exatamente o que pediu. Então mude o objetivo.

A correção que a produção usa

  • Perceptual: compara features profundas ( aqui é uma rede pré-treinada, não o encoder), então uma textura deslocada em um pixel não é punida.
  • Adversarial: um discriminador de GAN sobre a saída do decoder pune exatamente a suavidade que o premia.
  • É a receita do VQGAN e da difusão latente: todo autoencoder latente embaixo de um modelo de difusão é treinado assim.

Um VAE convolucional: o latente é uma imagem pequena

Um autoencoder convolucional: uma imagem 28×28×1 passa por duas convoluções de passo 2 até 14×14×32 e 7×7×64 e depois até um latente 7×7×4, que ainda é uma imagem pequena com canais; convoluções transpostas a trazem de volta a 28×28×1. x · 28×28×1 14×14×32 7×7×64 z · 7×7×4 7×7×64 14×14×32 x̂ · 28×28×1 ENCODER cada camada divide a resolução por 2 e soma canais DECODER convoluções transpostas trazem de volta LATENTE uma imagem pequena com canais O VAE do Stable Diffusion tem a mesma forma: 512×512×3 → 64×64×4, 48× menos números.
  • Todo autoencoder latente de produção é convolucional: cada camada de passo 2 divide a resolução por 2 e soma canais; o decoder espelha isso com convoluções transpostas.
  • O latente guarda o arranjo espacial da imagem, então o modelo generativo roda nele como se fosse uma figura (uma U-Net ou um DiT).

Para que serve um VAE, de fato

A difusão latente roda no espaço comprimido do VAE, nunca nos pixels.

em 512 × 512 pixels latente SD 1.5 / SDXL latente SD 3 / FLUX
formato 512 × 512 × 3 64 × 64 × 4 64 × 64 × 16
números 786.432 16.384 65.536
compressão 1× 48× = 786.432 / 16.384 12× = 786.432 / 65.536
  1. Ele limita a qualidade: o que o encoder descarta, a difusão não gera (texto pequeno, textura fina — daí os 16 canais).
  2. O β dele é minúsculo (~): um compressor, de cujo prior ninguém amostra.
  3. Ele fica congelado: um espaço latente compartilhado por um ecossistema inteiro de fine-tunes.

O outro ramo: latentes discretos

O VQ-VAE encaixa cada vetor latente (a saída do encoder) na entrada mais próxima de um codebook aprendido: .

KL-regularizado (contínuo) VQ (discreto)
latente vetores de valores reais índices de codebook
usado por difusão latente: SD, SDXL, SD3, FLUX autorregressivo e mascarado: VQGAN, MaskGIT, Chameleon
modo de falha borrão; capacidade limitada por canal colapso de codebook
por quê a difusão precisa de onde somar ruído Transformers precisam de tokens para prever

Quando uma imagem vira uma grade de inteiros, ela é uma sequência de tokens — o assunto do capítulo de geração autorregressiva.

Apêndice · a divergência KL

  1. Nunca é negativa e só é zero quando .
  2. Não é simétrica: — não é uma distância.
  3. O integrando pode ser negativo onde — então uma estimativa com uma amostra também pode (laboratório: 8.6% delas para posterior vs prior). É por isso que a perda usa a forma fechada.

Com e : , o termo do VAE.

Simulador · duas gaussianas para arrastar

Laboratório · o ELBO num VAE de verdade

Notebook no Colab, ~2 h, CPU, Fashion-MNIST. Cada seção termina num checkpoint com valor de verificação.

  1. a evidência por amostragem e Jensen
  2. o truque contra o autograd e contra a função escore
  3. a KL de três jeitos
  4. um VAE no Fashion-MNIST e o gradiente nas cabeças dele
  1. o β, medido: reconstrução, KL e amostras
  2. colapso com um decoder forte e free bits
  3. a folga num VAE de verdade: pesos de importância e amortização
  4. sua vez: a melhor verossimilhança dá as melhores amostras?

abrir no Colab →

Para levar

  1. Um autoencoder comprime; ele não gera: pontos, não uma distribuição.
  2. : um limite inferior cuja folga é o erro do encoder. Um objetivo treina as duas redes.
  3. ELBO = reconstrução − KL até o prior. Ele premia a melhor troca.
  4. O truque da reparametrização torna tudo diferenciável — e bem menos ruidoso que a função escore.
  5. O β desliza entre um autoencoder e o colapso do posterior; um decoder forte colapsa até com β = 1. Registre os dois termos.
  6. O borrão é o objetivo: corrigido com perdas perceptual e adversarial.
  7. Em 2026 um VAE é o compressor congelado embaixo da difusão latente; o VQ-VAE é o ramo discreto.

Roteiro: (1) por que um autoencoder não gera; (2) o ELBO em cinco passos, com o exemplo resolvido; (3) o truque e uma passagem à mão; (4) β, colapso e folga, medidos; (5) o borrão e para que serve um VAE em 2026. Fecha com o laboratório no Colab e o apêndice da KL.

No laboratório (seção 7): 1000 amostras do prior dão um limite 23.7 nats pior que o próprio ELBO.

Dedução: E_q[log p(x)] = E_q[log p(x,z)/p(z|x)], multiplique e divida por q. Cada linha é uma igualdade.

Avance pelos cinco passos: a história generativa, o que não dá para calcular, o chute do encoder, os dois termos e a folga. Passe o mouse numa caixa para ver as setas dela. Roxo é o q, que se treina; verde é o modelo p.

No lab da página: uma amostra é não viesada; a dispersão cai como 1/sqrt(K): 1.29, 0.38, 0.12, 0.04 para K = 1, 10, 100, 1000. Um lote de 128 imagens já tira a média de 128 sorteios.

Caso inicial: q_C, a linha do exercício. Avance linha a linha: a coluna exata à direita é a tabela dos slides anteriores (ELBO −2,7371, KL 0,8181, folga 0,1134); os quatro ε dão elbo −2,7455, L_K −2,6401 e folga 0,1219. Depois: "a posterior" (todo log w = −2,6237, folga 0), "a prior" (log w de −1,90 a −16,60, elbo −7,40 mas L_K −2,73: tirar a média de w primeiro salva um q ruim), "o ponto" (q estreita: a reconstrução quase não muda, de −0,92 a −0,95, mas a folga é 1,25). K = 1 deixa L_K igual a elbo.

Use o botão Próximo (as setas avançam o diagrama enquanto ele tem o foco; clique fora dele para ir ao próximo slide). Os passos 2, 3, 5 e 6 são um MLP comum. O passo 4 é a única operação nova. No passo 10, arraste o epsilon: a parte da reconstrução em dL/ds troca de sinal e a média dela sobre epsilon é +0.100.

No exemplo resolvido: beta -> 0 leva ao ponto q_B, beta -> infinito ao prior, beta = 1 à posterior.

Oito grupos num anel, latente 2-D. Rodadas deste painel sem navegador: beta = 0 -> 90% das amostras do prior fora dos dados, KL 10.9 nats; beta = 1 -> 21%, KL 1.85; beta = 7.5 ou mais -> colapso, toda amostra fora dos dados e erro de reconstrução 0.52, a variância dos dados (0.53).

Presets: a posterior do exemplo resolvido contra o prior dá 1.1247, a coluna KL da tabela dele. q estreita dentro de p: 0.318 num sentido e 0.807 no outro. Bem afastadas com larguras iguais: 8 nos dois sentidos. Clique fora do painel antes de usar as setas para trocar de slide.