StudyHub

ML/DL · Deep learning

Variational autoencoder (VAE)

A VAE's encoder doesn't output one code; it outputs a little cloud: mean $\mu = 0.5$ and spread $\sigma = 0.8$. Draw a code from it, $z = 0.5 + 0.8 \cdot 0.5 = 0.9$, and decode. The loss has two parts: the reconstruction error (here 0.05) and a KL penalty (here 0.17) that keeps every cloud close to a standard normal. Total 0.22. Because all codes stay near $\mathcal{N}(0, 1)$, decoding random samples gives new, sensible data. That's a VAE.

Why it matters: it turns an autoencoder into a generator: its code space is smooth and filled in, so you can sample new data, interpolate between examples, and get a principled probabilistic model.

Prerequisites

The analogy

Everyday analogy

A plain autoencoder files each photo at one exact spot on a shelf, leaving empty gaps; pick a random spot and you find nothing.

A VAE files each photo as a fuzzy region, and a rule (the KL term) packs all regions tightly around the middle of the shelf. Now any spot you pick is covered by something, so the decoder can produce a sensible photo from it.

How it works

Loss: $L = \underbrace{\lVert x - \hat x \rVert^2}_{\text{reconstruction}} + \underbrace{\tfrac12 \big(\sigma^2 + \mu^2 - 1 - \ln \sigma^2\big)}_{\text{KL}(\mathcal{N}(\mu, \sigma^2) \,\|\, \mathcal{N}(0, 1))}$ per latent dimension; $z = \mu + \sigma \varepsilon$ with $\varepsilon \sim \mathcal{N}(0, 1)$.

Start with one VAE step by hand

1-D code: the encoder gives $\mu = 0.5$, $\sigma = 0.8$. The random draw is $\varepsilon = 0.5$. The input is $x = [1, 0]$ and the decoder outputs $\hat x = [0.8, 0.1]$. Predict, then open "Check".

Example: predict before you read

Step 1. Sample the code with the reparameterization trick: $z = \mu + \sigma \varepsilon$.

Check

$z = 0.5 + 0.8 \cdot 0.5 = 0.9$.

Step 2. Cover the next line and guess: the reconstruction error $\lVert x - \hat x \rVert^2$.

Check

$0.2^2 + 0.1^2 = 0.04 + 0.01 = 0.05$.

Step 3. The KL term $\tfrac12(\sigma^2 + \mu^2 - 1 - \ln \sigma^2)$ (use $\ln 0.64 \approx -0.446$), and the total loss.

Check

$\tfrac12(0.64 + 0.25 - 1 + 0.446) \approx 0.168$. Total $\approx 0.05 + 0.168 = 0.218$.

VAE diagram: encoder outputs mu 0.5 and sigma 0.8, sample z = mu + sigma times epsilon = 0.9, decoder reconstructs; loss is reconstruction 0.05 plus KL 0.17
What you just computed: the encoder outputs a distribution, a sample from it is decoded, and the loss adds reconstruction error and the KL penalty.

Quick recall: Before reading further, cover the text above and say out loud: what does a VAE's encoder output, compared with a plain autoencoder?

Check your answer

A distribution (a mean and a standard deviation per latent dimension) instead of a single code.

Finish the picture: the two forces

The two loss terms pull in different directions.

  • Reconstruction alone. Predict what the encoder would do to $\sigma$.
    Check

    Shrink $\sigma$ towards 0 and spread the means apart, to make each code precise: the VAE would turn back into a plain autoencoder with gaps.

  • KL alone. Predict the codes.
    Check

    Every input would get $\mu = 0$, $\sigma = 1$: a perfectly regular code space that carries no information about the input. The sum balances precision against regularity.

Quick recall: Without scrolling up, say out loud: what is the KL term when $\mu = 0$ and $\sigma = 1$?

Check your answer

0: the code distribution is exactly the standard normal, so there is no penalty.

Full worked calculation

A VAE with a 2-D latent space. For one input the encoder outputs $\mu = [0.5, -1]$ and $\sigma = [0.8, 0.5]$. We sample a code with the reparameterization trick, compute the KL term per dimension, and assemble the loss.

Latent dim$\mu$$\sigma$$\varepsilon$ (drawn)$z = \mu + \sigma\varepsilon$KL term
10.50.80.50.90.168
2−10.5−1−1.50.818
Total0.986
  1. 1The encoder outputs a distribution

    $$q(z \mid x) = \mathcal N\big([0.5, -1],\; \text{diag}(0.8^2, 0.5^2)\big)$$

    Instead of one code, the encoder describes a small cloud of plausible codes: a centre $\mu$ and a spread $\sigma$ per dimension.

  2. 2Reparameterization: sample

    $$\varepsilon \sim \mathcal N(0, 1) = [0.5, -1] \;\Rightarrow\; z = [0.5 + 0.8 \cdot 0.5,\; -1 + 0.5 \cdot (-1)] = [0.9,\; -1.5]$$

    The randomness is drawn separately, then shifted and scaled. Because $z$ is now a simple formula in $\mu$ and $\sigma$, gradients can flow through the sampling into the encoder.

  3. 3KL term, dimension 1

    $$\tfrac12\big(\mu^2 + \sigma^2 - 1 - \ln\sigma^2\big) = \tfrac12\big(0.25 + 0.64 - 1 + 0.446\big) = 0.168$$

    This measures how different this dimension's cloud is from the standard normal $\mathcal N(0, 1)$. It is 0 only when $\mu = 0$ and $\sigma = 1$.

  4. 4KL term, dimension 2

    $$\tfrac12\big(1 + 0.25 - 1 + 1.386\big) = 0.818$$

    Dimension 2 is penalised much more: its centre is far from 0 ($\mu = -1$) and its cloud is narrow ($\sigma = 0.5$, so $-\ln\sigma^2 = 1.386$). The KL pushes clouds to stay wide and centred.

  5. 5Total loss

    $$L = \underbrace{\lVert x - \hat x \rVert^2}_{\text{reconstruction}} + \underbrace{0.168 + 0.818}_{\text{KL} = 0.986}$$

    The decoder turns $z = [0.9, -1.5]$ into $\hat x$; its error is the first part. With a reconstruction error of 0.05 the total would be 1.036. The two parts pull in opposite directions: precise codes vs. well-organised latent space.

  6. 6Generating new data

    $$z \sim \mathcal N(0, I), \quad \text{e.g. } z = [0.3, -0.2] \;\Rightarrow\; \hat x = \text{decoder}(z)$$

    Because the KL kept every cloud close to $\mathcal N(0, 1)$, codes drawn from it land in regions the decoder knows. That is what a plain autoencoder cannot do.

What the numbers tell us

VAE loss = reconstruction + KL. The KL per dimension is $\tfrac12(\mu^2 + \sigma^2 - 1 - \ln\sigma^2)$: here 0.168 + 0.818 = 0.986.

The reparameterization trick $z = \mu + \sigma\varepsilon$ is what makes the random sampling step trainable with backpropagation.

The rule in plain words

Encode $x$ into $\mu$ and $\sigma$; sample $z = \mu + \sigma \varepsilon$; decode to $\hat x$. Minimise reconstruction error + KL divergence from $\mathcal{N}(0, 1)$.

To generate, sample $z \sim \mathcal{N}(0, 1)$ and decode. Nearby codes give similar outputs, so you can interpolate between examples.

Quick recall: Before you read the code, describe the reparameterization trick in your own words. Then check below.

Check your answer

Instead of sampling $z$ directly, sample a standard normal $\varepsilon$ and compute $z = \mu + \sigma \varepsilon$, so gradients can flow through $\mu$ and $\sigma$.

The code

Read this code after you have computed the loss by hand. It will make more sense.

double reparam(double mu, double sigma, double eps) { return mu + sigma * eps; }

double kl_term(double mu, double sigma) {               /* KL(N(mu, sigma^2) || N(0, 1)) */
    return 0.5 * (sigma * sigma + mu * mu - 1 - log(sigma * sigma));
}

double vae_loss(double x[], double xh[], int d, double mu, double sigma) {
    double rec = 0;
    for (int j = 0; j < d; j++) rec += (x[j] - xh[j]) * (x[j] - xh[j]);   /* reconstruction */
    return rec + kl_term(mu, sigma);
}

Definition

What you just did, in one line: a variational autoencoder encodes each input as a probability distribution over codes, samples from it with the reparameterization trick, and trains with reconstruction error plus a KL penalty that keeps codes close to $\mathcal{N}(0, 1)$, which makes it a generative model.

flowchart LR
  X["x"] --> ENC["encoder"]
  ENC --> MU["μ"]
  ENC --> SG["σ"]
  EPS["ε ~ N(0, 1)"] --> Z["z = μ + σ ε"]
  MU --> Z
  SG --> Z
  Z --> DEC["decoder"]
  DEC --> XH["x̂"]
          
Before you scroll past this diagram, cover the right side and guess: which input is the only random one? (Answer: $\varepsilon$; that's why gradients can still flow through $\mu$ and $\sigma$.)

Putting numbers on it

Quick recall: Before looking at the formula, predict: how do you generate a brand-new sample after training?

Check your answer

Draw $z$ from $\mathcal{N}(0, 1)$ and run only the decoder.

The two loss terms for our example:

$$\underbrace{(1 - 0.8)^2 + (0 - 0.1)^2}_{0.05} + \underbrace{\tfrac12\big(0.64 + 0.25 - 1 - \ln 0.64\big)}_{\approx 0.168} \approx 0.218$$
$\mu$$\sigma$KL termMeaning
010Exactly the prior: no penalty
0.50.80.168Our example
212.0Mean far from 0 is costly
00.1≈ 1.81Very precise code is costly

Warning

VAE samples are often blurry: with a squared-error reconstruction loss, the decoder averages over plausible outputs. GANs and diffusion models usually produce sharper images.

Exam tip

Name the two loss terms and what each does (reconstruction: be accurate; KL: be regular), write $z = \mu + \sigma\varepsilon$, and explain why this trick is needed for backpropagation.

Common mistakes

  • Sampling $z$ directly from $\mathcal{N}(\mu, \sigma^2)$ in code, which blocks gradients to $\mu$ and $\sigma$.
  • Forgetting the KL term, which turns the VAE into a plain autoencoder with a gappy code space.
  • Having the encoder output $\sigma$ directly; in practice it outputs $\ln \sigma^2$ so that $\sigma$ stays positive.

Try it yourself

Exercise 1 (warm-up)

Compute the KL term for $\mu = 0$, $\sigma = 1$, and for $\mu = 1$, $\sigma = 1$.

Hint

$\ln 1 = 0$.

Answer

0 and $\tfrac12(1 + 1 - 1 - 0) = 0.5$.

Exercise 2 (a bit harder)

With $\mu = 0.5$, $\sigma = 0.8$, compute $z$ for $\varepsilon = -1$ and $\varepsilon = 2$. How does that show what the encoder "believes" about the input? Write your answer down before you open it.

Show answer

$z = -0.3$ and $z = 2.1$. The encoder says the input's code is most likely near 0.5 but uncertain by about ±0.8; different draws explore that region, and the decoder must handle all of them.

Did you know?

Did you know?

Kingma and Welling published the VAE in 2013 ("Auto-Encoding Variational Bayes"), the same Kingma who co-created the Adam optimiser.

Latent diffusion image generators use a VAE to compress images into a small latent space, then run the diffusion process there.

Key points to remember

If you remember one thing from each line, remember the because.

  • The encoder outputs a distribution because that fills the code space instead of leaving isolated points.
  • The KL term keeps codes near $\mathcal{N}(0, 1)$ because random samples from $\mathcal{N}(0, 1)$ must decode to sensible data.
  • The reparameterization trick enables training because it moves the randomness into $\varepsilon$, outside the path of the gradients.
  • The two loss terms compete because precise codes help reconstruction but cost KL.
  • VAEs can generate because decoding any sample from the prior lands in a region the decoder learned.

Self-check questions

Answer these in order, out loud. They follow the page, so your answers become the script of your video.

  1. How is a VAE like filing photos as fuzzy regions on a shelf?
    Sample answer

    Each photo covers a region, and a rule packs the regions around the middle, so any spot you pick decodes to something sensible.

  2. Compute $z$, the reconstruction error, the KL term and the total loss for the example.
    Sample answer

    $z = 0.9$; reconstruction 0.05; KL ≈ 0.168; total ≈ 0.218.

  3. Why does reparam take eps as an input rather than sampling inside?

    A good answer mentions gradients.

    Sample answer

    Keeping the random draw $\varepsilon$ outside makes $z$ a simple deterministic function of $\mu$ and $\sigma$, so backpropagation can compute gradients for them.

  4. So what is a VAE, in one sentence?
    Sample answer

    An autoencoder whose encoder outputs a distribution, trained with reconstruction error plus a KL penalty towards $\mathcal{N}(0, 1)$, so it can generate new data.

  5. Why does a plain autoencoder generate poorly while a VAE generates well?

    A good answer mentions gaps in the code space.

    Sample answer

    A plain autoencoder's codes are isolated points with gaps that decode to garbage; the VAE's KL term and sampling fill the space around $\mathcal{N}(0, 1)$ with decodable codes.

  6. What is the KL term for one latent dimension?
    Sample answer

    $\tfrac12(\sigma^2 + \mu^2 - 1 - \ln \sigma^2)$.

  7. How do you generate a new sample with a trained VAE?
    Sample answer

    Sample $z$ from $\mathcal{N}(0, 1)$ and pass it through the decoder only.

  8. If you had to teach this to a friend in 2 minutes, what would you leave out, and why?
    Sample answer

    I'd leave out the KL formula and the blurriness issue. I'd keep the fuzzy-shelf analogy, $z = \mu + \sigma\varepsilon = 0.9$, and "loss = reconstruction + KL; sample from $\mathcal{N}(0, 1)$ to generate".

External resources

Videos

Review schedule

Come back after 3, 7, 14, then 30 days. Spacing beats cramming.

Feynman prompt

Explain this topic in your own words, as if teaching a beginner.

Explain it in your own words first, then record a 2–3 minute video on your phone.

25:00

Ready to record? Open your phone camera now and record a 2–3 minute explanation.

My notes

Saved only in this browser (localStorage). Nothing is uploaded.