✨ Generative AI & LLMs · Lecture 2 of 30

Variational Autoencoders: Probabilistic Latent Spaces

VAEs turn autoencoders into generative models by learning a smooth, probabilistic latent space. We derive the evidence lower bound, the reparameterisation trick and the KL term, and discuss blurriness, posterior collapse and β-VAE.

A plain autoencoder compresses data but its latent space is disorganised: decoding a random point gives garbage. Kingma and Welling's Variational Autoencoder (2013) — with the parallel work of Rezende, Mohamed and Wierstra — made the latent space probabilistic and smooth, so we can sample new data by decoding random latent vectors. VAEs introduced ideas central to modern generative modelling, and their autoencoder component lives on inside latent diffusion models.

The generative model#

Assume each data point $\mathbf{x}$ is generated from a latent variable $\mathbf{z}$:

$$ \mathbf{z} \sim p(\mathbf{z}) = \mathcal{N}(\mathbf{0}, \mathbf{I}), \qquad \mathbf{x} \sim p_\theta(\mathbf{x} \mid \mathbf{z}) $$

where the decoder $p_\theta(\mathbf{x} \mid \mathbf{z})$ is a neural network (e.g. outputting pixel means). The marginal likelihood

$$ p_\theta(\mathbf{x}) = \int p_\theta(\mathbf{x} \mid \mathbf{z})\,p(\mathbf{z})\,d\mathbf{z} $$

is intractable: we cannot integrate over all $\mathbf{z}$, and the true posterior $p_\theta(\mathbf{z} \mid \mathbf{x})$ is intractable too.

Amortised variational inference#

Introduce an encoder $q_\phi(\mathbf{z} \mid \mathbf{x})$ — a neural network outputting the mean $\boldsymbol{\mu}$ and (log-)variance $\boldsymbol{\sigma}^2$ of a Gaussian — to approximate the posterior. "Amortised" means one network infers latents for all data points rather than optimising a separate distribution for each.

The Evidence Lower Bound (ELBO)#

For any $q$, the log-likelihood decomposes as

$$ \log p_\theta(\mathbf{x}) = \underbrace{\mathbb{E}_{q_\phi(\mathbf{z} \mid \mathbf{x})}\big[\log p_\theta(\mathbf{x} \mid \mathbf{z})\big] - D_{\text{KL}}\big(q_\phi(\mathbf{z} \mid \mathbf{x})\,\|\,p(\mathbf{z})\big)}_{\text{ELBO}} + D_{\text{KL}}\big(q_\phi(\mathbf{z} \mid \mathbf{x})\,\|\,p_\theta(\mathbf{z} \mid \mathbf{x})\big) $$

The last KL term is non-negative, so the ELBO is a lower bound on $\log p_\theta(\mathbf{x})$. We maximise it jointly over encoder and decoder. Its two terms have clear meanings:

  1. Reconstruction term: decoded samples should reproduce the input.
  2. KL regulariser: each encoding distribution should stay close to the prior $\mathcal{N}(\mathbf{0}, \mathbf{I})$ — packing the latent space densely and smoothly so random prior samples decode to sensible data.

For Gaussian $q$ and standard normal prior, the KL has a closed form:

$$ D_{\text{KL}} = \frac{1}{2}\sum_{j=1}^{d}\left(\mu_j^2 + \sigma_j^2 - \log\sigma_j^2 - 1\right) $$

The reparameterisation trick#

We need gradients of $\mathbb{E}_{q_\phi}[\cdot]$ with respect to $\phi$, but sampling is not differentiable. Rewrite the sample as a deterministic function of $\phi$ and independent noise:

$$ \mathbf{z} = \boldsymbol{\mu}_\phi(\mathbf{x}) + \boldsymbol{\sigma}_\phi(\mathbf{x})\odot\boldsymbol{\epsilon}, \qquad \boldsymbol{\epsilon} \sim \mathcal{N}(\mathbf{0}, \mathbf{I}) $$

Now gradients flow through $\boldsymbol{\mu}$ and $\boldsymbol{\sigma}$; the randomness sits in $\boldsymbol{\epsilon}$. This low-variance gradient estimator is what made VAEs trainable with ordinary backpropagation.

Implementation#

python
import torch
import torch.nn as nn
import torch.nn.functional as F

class VAE(nn.Module):
    def __init__(self, x_dim=784, h=400, z_dim=20):
        super().__init__()
        self.enc = nn.Sequential(nn.Linear(x_dim, h), nn.ReLU())
        self.mu, self.logvar = nn.Linear(h, z_dim), nn.Linear(h, z_dim)
        self.dec = nn.Sequential(nn.Linear(z_dim, h), nn.ReLU(), nn.Linear(h, x_dim))
    def forward(self, x):
        hdn = self.enc(x)
        mu, logvar = self.mu(hdn), self.logvar(hdn)
        z = mu + torch.exp(0.5 * logvar) * torch.randn_like(mu)          # reparameterisation
        return self.dec(z), mu, logvar

def vae_loss(logits, x, mu, logvar, beta=1.0):
    recon = F.binary_cross_entropy_with_logits(logits, x, reduction="sum")
    kl = -0.5 * torch.sum(1 + logvar - mu.pow(2) - logvar.exp())
    return (recon + beta * kl) / x.size(0)

model = VAE()
x = torch.rand(64, 784)                        # e.g. flattened MNIST images in [0, 1]
logits, mu, logvar = model(x)
print(vae_loss(logits, x, mu, logvar).item())

with torch.no_grad():                           # generation: decode samples from the prior
    samples = torch.sigmoid(model.dec(torch.randn(16, 20)))

After training on MNIST, decoding a grid of latent points shows digits morphing smoothly into one another — evidence of a continuous, structured latent space.

Known issues#

  • Blurry samples: with a Gaussian (MSE-like) or per-pixel likelihood, the decoder averages over uncertainty, producing blurry images compared with GANs and diffusion models.
  • Posterior collapse: with powerful decoders (e.g. autoregressive), the model may ignore $\mathbf{z}$, making the KL term zero. Remedies include KL annealing (gradually increasing its weight) and "free bits".
  • The prior hole problem: regions of the prior rarely covered by any encoding decode poorly.

Variants#

  • β-VAE (Higgins et al., 2017): weight the KL by $\beta > 1$ to encourage disentangled latents where individual dimensions capture separate factors (e.g. rotation, scale) — at some cost to reconstruction.
  • Conditional VAE (CVAE): condition encoder and decoder on a label or other input.
  • VQ-VAE (van den Oord et al., 2017): a discrete latent codebook with vector quantisation; paired with an autoregressive prior it generated high-quality images and audio, and discrete codebooks underlie many image and audio tokenisers used by modern multimodal models.
  • Hierarchical VAEs (NVAE, VDVAE): many latent layers; much sharper samples.
  • The autoencoder in Stable Diffusion is a VAE-style model (with perceptual and adversarial losses) that compresses images into a latent space where diffusion operates.
JA
Written by

Janin A Apurba

B.Sc. in CSE, AUST · Advanced ICT Officer, CNRS-UNHCR. Teaching AI, ML and Deep Learning to the next generation of engineers and researchers.

Keep learning

Related lectures

✨ Generative AI & LLMs

Generative vs Discriminative Models: Learning to Create

We open the Generative AI track by contrasting models that draw boundaries with models that learn the data distribution itself, and map the families of deep generative models — autoregressive, VAEs, GANs, flows and diffusion.

Beginner⏱ 5 min#191
✨ Generative AI & LLMs

Generative Adversarial Networks: The Generator–Discriminator Game

GANs train a generator to fool a discriminator in a two-player game. We derive the minimax objective and its optimum, study training dynamics, mode collapse and the non-saturating loss, and build a DCGAN.

Advanced⏱ 5 min#193
✨ Generative AI & LLMs

Diffusion Models: Generating by Learning to Denoise

Diffusion models gradually add noise to data and train a network to reverse the process. We derive the DDPM forward and reverse processes, the simple noise-prediction loss, sampling, the score-based view, and faster samplers like DDIM.

Advanced⏱ 6 min#196