Phase 08: Generative AI

Autodécodateurs et Autodécodateurs variatifs (VAE)

Un simple autoencodeur comprime puis reconstruit. Il mémore. Il ne génère pas. Ajoutez une astuce forcez le code à regarder Gaussian et vous obtenez un échantillonneur. Cette astuce unique, la réparamétrisation de z = μ + σ·εC'est pourquoi chaque modèle d'image de diffusion latente et de correspondance de flux que vous utilisez en 2026 a un VAE à l'entrée.

Type: Build

Languages: Python

Prerequisites: Phase 3 · 02 (Backprop), Phase 3 · 07 (CNNs), Phase 8 · 01 (Taxonomy)

Time: ~75 minutes

Le problème

Comprimez un chiffre MNIST de 784 pixels à un code à 16 chiffres, puis reconstruisez. Un autoencodeur simple fera une reconstruction MSE mais l'espace code est un gâchis. Choisissez un point aléatoire dans l'espace code, décodez-le, et vous obtenez du bruit. Il n'a pas de échantillonneur. C'est un modèle de compression habillé.

Ce que vous voulez vraiment, c'est: (a) l'espace de code est une distribution propre et lisse que vous pouvez échantillonner à partir d'un Gaussian isotropeN(0, I)Le codeur et le décodeur comprennent toujours bien. Trois objectifs, une architecture, une perte.

Le VAE 2013 de Kingma résout cette question en formant le codeur à produire une distribution q(z|x) = N(μ(x), σ(x)²), tirant cette distribution vers le priorN(0, I)par une pénalité KL, puis le prélèvement zde q(z|x)Avant de décoder, au moment de l'inférence, laissez tomber le codeur, échantillon z ~ N(0, I)La pénalité KL est ce qui oblige l'espace de code à être structuré.

En 2026, les VAE sont rarement livrés indépendamment ils ont été dépassés par la diffusion pour la qualité d'image brute mais ils sont le codeur de choix pour chaque modèle de diffusion latente (SD 1/2/XL/3, Flux, AudioCraft).

Le concept

!Autoencoder vs VAE: the reparameterization trick

Autoencoder. z = encoder(x)- Je suis là .x̂ = decoder(z), perte = ||x - x̂||²- L'espace de code est non structuré.

VAE encoder.Les sorties sont de deux vecteurs: μ(x)et log σ²(x)- Ils définissent ...q(z|x) = N(μ, diag(σ²))- Je suis désolé .

Reparameterization trick.Prise d' échantillons à partir de q(z|x)L'échantillon est réécrit comme z = μ + σ·εoù ε ~ N(0, I)- Maintenant .zest une fonction déterministe de (μ, σ)+ un bruit non paramétrique des gradients circulent μet σ- Je suis désolé .

Loss.Les preuves de la base de la base (ELBO), deux termes:

loss = reconstruction + β · KL[q(z|x) || N(0, I)]
     = ||x - x̂||²  + β · Σ_i ( σ_i² + μ_i² - log σ_i² - 1 ) / 2

La reconstruction est en train de pousser x̂vers lex- KL pousse .q(z|x)Les données de base de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l'échantillon de l

Sampling.À l' inférence: tirage au sort z ~ N(0, I)Un passage en avant, pas d'échantillonnage itératif comme la diffusion.

Faites-le

code/main.pyIl est utilisé pour la mise en œuvre d'un petit VAE sans numpy ou torche. L'entrée est des données synthétiques 8 dimensions tirées d'un mélange gaussien à 2 composants en 8D. L'encodeur et le décodeur sont des MLP à couche cachée unique.

Étape 1: encodeur vers l'avant

pythondef encode(x, enc):
    h = tanh(add(matmul(enc["W1"], x), enc["b1"]))
    mu = add(matmul(enc["W_mu"], h), enc["b_mu"])
    log_sigma2 = add(matmul(enc["W_sig"], h), enc["b_sig"])
    return mu, log_sigma2

log σ²Au lieu de σAinsi, la sortie du réseau est libre (softplus de σ est un piège gradients meurent à σ ≈ 0).

Étape 2: réparamétrifier et décoder

pythondef reparameterize(mu, log_sigma2, rng):
    eps = [rng.gauss(0, 1) for _ in mu]
    sigma = [math.exp(0.5 * lv) for lv in log_sigma2]
    return [m + s * e for m, s, e in zip(mu, sigma, eps)]

def decode(z, dec):
    h = tanh(add(matmul(dec["W1"], z), dec["b1"]))
    return add(matmul(dec["W_out"], h), dec["b_out"])

Étape 3: l'ELBO

pythondef elbo(x, x_hat, mu, log_sigma2, beta=1.0):
    recon = sum((a - b) ** 2 for a, b in zip(x, x_hat))
    kl = 0.5 * sum(math.exp(lv) + m * m - lv - 1 for m, lv in zip(mu, log_sigma2))
    return recon + beta * kl, recon, kl

Il est vrai que les deux distributions sont gaussiennes, mais ne sont pas intégrées numériquement.

Étape 4: générer

pythondef sample(dec, z_dim, rng):
    z = [rng.gauss(0, 1) for _ in range(z_dim)]
    return decode(z, dec)

C'est le modèle génératif.

Les pièges

  • Posterior collapse.Les lecteurs à terme KL q(z|x) → N(0, I)si agressivement que zne contient aucune information sur x. Réparation: β-annulation (début β=0, rampe à 1), bits libres, ou sauter le KL sur les dimensions inactives.
  • Blurry samples.La probabilité du décodeur gaussien implique la reconstruction de l'ESM, qui est Bayes-optimale pour L2 (la moyenne) la moyenne d'un ensemble de chiffres plausibles est un chiffre flou. Fix: décodeur discrète (VQ-VAE, NVAE), ou utiliser le VAE uniquement comme un encodeur et diffusion en pile sur les latents (c'est ce que fait Stable Diffusion).
  • β too large, too early.Voir l'effondrement postérieur.
  • Latent dim too small.Le 16D fonctionne pour le MNIST, le 256-D pour l'ImageNet 2562, le 2048-D pour l'ImageNet 10242.

Utilisez-le

Le groupe VAE 2026:

SituationPick
Image-latent encoder for diffusionStable Diffusion VAE (sd-vae-ft-ema) or Flux VAE
Audio-latent encoderEncodec (Meta), SoundStream, or DAC (Descript)
Video latentsSora's spatiotemporal patches, Latte VAE, WAN VAE
Disentangled representation learningβ-VAE, FactorVAE, TCVAE
Discrete latents (for transformer modelling)VQ-VAE, RVQ (ResidualVQ)
Continuous latents for generationPlain VAE, then condition a flow/diffusion model in that latent space

Un modèle de diffusion latente est un modèle de diffusion VAE avec un modèle de diffusion vivant entre un encodeur et un décodeur. Le modèle de diffusion fait la compression grossière, le modèle de diffusion fait le travail lourd.

La faire partir

  • Ça va .outputs/skill-vae-trainer.md- Je suis désolé .

Les compétences requises: profil de l'ensemble de données + cible latente-dim + utilisation en aval (reconstruction, échantillonnage ou entrée de diffusion latente) et les résultats: choix d'architecture (plain/β/VQ/RVQ), horaire β, latente dim, probabilité de décoder (Gaussian vs catégorique), et plan d'évaluation (recon MSE, KL par dim, distance Fréchet entre q(z|x)et N(0, I))

Exercices

  1. Easy.Le changementβdans code/main.pyà 0.01- Je suis là .0.1- Je suis là .1.0- Je suis là .5.0Enregistrer la reconstruction finale de MSE et KL. Quel β est le meilleur pareto pour vos données synthétiques ?
  2. Medium.Remplacez la probabilité du décodeur gaussien par une probabilité de Bernoulli (perte de croisée entropie).
  3. Hard.Extension code/main.pyen mini VQ-VAE: remplacez le continu zComparer la reconstruction MSE et indiquer le nombre d'entrées utilisées (l'effondrement du codebook est réel).

Les termes clés

TermWhat people sayWhat it actually means
AutoencoderEncode-decode networkx → z → x̂, learn MSE. Not generative.
VAEAE with a samplerEncoder outputs a distribution, KL penalty shapes code space.
ELBOEvidence lower boundlog p(x) ≥ recon - KL[q(z|x) || p(z)]; tight when q = p(z|x).
Reparameterizationz = μ + σ·εRewrites stochastic node as deterministic + pure noise. Enables backprop through sampling.
Priorp(z)Target distribution for the latent, typically N(0, I).
Posterior collapse"KL term wins"Encoder ignores x, outputs the prior; decoder must hallucinate.
β-VAETunable KL weightloss = recon + β·KL. Higher β = more disentangled but blurrier.
VQ-VAEDiscrete latentReplace continuous z with nearest codebook vector; enables transformer modelling.

Note de production: le VAE est le chemin le plus chaud dans un serveur de diffusion

Dans un pipeline Stable Diffusion / Flux / SD3, le VAE est appelé deux fois par demande une fois pour encoder (si vous faites img2img / inpainting) et une fois pour décoder.128×128×16Les latents sont de retour à 1024×1024×3- Deux conséquences pratiques:

  • Slice or tile the decode. diffusersexposés pipe.vae.enable_slicing()et pipe.vae.enable_tiling()- Le Tiling négocie un petit artefact de couture pourO(tile²)mémoire au lieu de O(H·W)- Essentiel pour 10242+ sur les GPU de consommation.
  • bf16 decoder, fp32 numerics for the final resize.Le SD 1.x VAE a été libéré en fp32 et produit silencieusement des NaNs lorsqu'il est jeté à fp16 à 10242+.madebyollin/sdxl-vae-fp16-fix préférer toujours la variante fp16-fix ou utiliser bf16.

Pour en savoir plus

This free lesson is part of the AI Engineering from Scratch curriculum. Read the full explanation, run the lesson code, and verify the result in the interactive reader or from the repository source.

Browse the complete course catalog or open this lesson on GitHub.