Variational Autoencoders
After this lesson, you will be able to:
- Say what a VAE changes: it stores a small cloud of possibilities, not one point, and why that closes the holes
- Read the VAE training score (the ELBO) as two goals that pull against each other: rebuild well, and keep the latent space tidy
- Explain the reparameterization trick: the random draw is moved outside the network so training can still pass through it
- Walk smoothly between two latents and get sensible in-between pictures
- Say what a bigger beta buys and what it costs, and name posterior collapse
Before You Start
#From Autoencoder to Generator
This lesson turns the squeezer into a generator. It uses the encoder, decoder, latent and bottleneck from the last lesson, and adds randomness. It covers the cloud-of-possibilities idea, the training score (the ELBO), the reparameterization trick, smooth walks between latents, beta-VAE, and the bridge to discrete latents.
An autoencoder whose encoder outputs a small cloud of possible latents, not one point, so that decoding a random point gives a sensible picture.
The center of the cloud and how wide it is. The mean is written mu and the spread is written sigma.
A number for how different two bell curves are. Here: how far the encoder's cloud is from a plain bell curve centered at zero.
The VAE training score: how well the picture was rebuilt, minus a penalty for a messy latent space.
Write the random draw as mean plus spread times a fixed random number, so that training can pass gradients through it.
A VAE that multiplies the tidiness penalty by a number beta. A bigger beta gives a tidier but blurrier model.
A failure where the encoder ignores the input and the decoder ignores the latent, so the model learns nothing useful.
#The Variational Autoencoder (VAE)
This small change has three effects:
-
Continuity: The encoder outputs a cloud, not a point, so nearby latents must give similar outputs. The decoder must handle a neighborhood, not one point.
-
Coverage: The VAE loss pushes the clouds to cover the latent space evenly, which fills the holes a plain autoencoder leaves.
-
Generativity: The latent space is smooth and well covered, so you can pick any point and get a meaningful output.
The sample is z = mean + spread x random draw. The mean and spread come from the network, and the random draw does not, so the network can still learn through that step.
#The ELBO: The VAE Loss Function
A tiny worked example. Suppose the squared rebuilding error is 3.0 and the cloud is far from the plain bell curve, costing 2.0. The loss is 3.0 + 2.0 = 5.0. If a tweak lowers the error to 2.5 but raises the cost to 3.0, the loss is 5.5, so the tweak is rejected. Training keeps the tweaks that lower the total.
The VAE loss is the negative ELBO, which we minimize. It has two terms that pull in opposite directions:
The two terms pull against each other. Reconstruction wants the clouds far apart, to keep every detail. KL wants them all pulled in toward the center. The VAE finds a balance, and that balance gives a tidy latent space you can sample from.
#The Reparameterization Trick
A tiny example. Say the encoder gives mean 2.0 and spread 0.5, and the dice roll gives epsilon = 1.2. Then z = 2.0 + 0.5 x 1.2 = 2.6. If the spread grows to 0.6, z becomes 2.72. The change in z is smooth and easy to follow, so training can learn the spread.
Try it below. The sliders set the mean and spread; the dot shows where a sample can land.
- Do: Drag the point in the plane, set the mean and spread sliders, and press the Sad to Happy button.
- Notice: A larger spread draws a wider circle of possible samples, and the shown face changes smoothly along the path.
- Why: The sample is mean plus spread times a random draw, so each slider moves it smoothly. Drawn stand-in, not a trained model: the face is picked by distance to five hand-placed regions.
For a hands-on check of the trick itself, use the lab below. It lets you set the mean and spread of one latent value, draw a cloud of samples, and flip between rolling the dice inside the network and outside it.
Do: Leave the dice outside and press Sample twice. Then switch to "Random draw inside the network". Finally set the mean to 0 and the spread to 1.Notice: With the dice outside, a red arrow carries the learning signal back to the encoder, and nudging the mean moves the sample by exactly 1 per unit. With the dice inside, the arrow is blocked. At mean 0 and spread 1 the cloud sits on the standard bell and KL reads 0.00.Why: A random draw cannot be differentiated, so writing sample = mean + spread x draw puts the dice outside the network, so the mean and spread can be trained. Drawn stand-in, not a trained model: the cloud and KL number are computed from your sliders, with no real encoder or decoder.
#Step 1: The Problem
We want to sample z from N(mu, sigma^2), where mu and sigma come from the encoder. But sampling is a stochastic operation — we cannot compute d(sample)/d(mu). Gradients cannot flow through the sampling step, so we cannot train the encoder.
#Step 2: Separate the Randomness
The key insight: any sample from N(mu, sigma^2) can be written as mu + sigma * epsilon, where epsilon comes from a standard N(0,1). We split the operation into a deterministic transformation (mu + sigma * epsilon) and a fixed noise source (epsilon).
#Step 3: Gradients Flow Again
Now z = mu + sigma * epsilon is a deterministic, differentiable function of mu and sigma (epsilon is treated as a constant). Gradients flow cleanly: dz/d(mu) = 1, dz/d(sigma) = epsilon. The encoder can be trained with standard backpropagation.
#Step 4: Training Works
During training, each forward pass samples a different epsilon, giving a different z. This randomness acts as regularization — the decoder must handle a range of z values for each input, not just one specific latent. Over many training steps, the gradients average out correctly.
- Do: Scroll through the four steps and watch where the random draw enters.
- Notice: In step 3 the draw sits beside the network, not inside it, and the path from the loss back to the encoder is unbroken.
- Why: Gradients can only pass through steps that depend smoothly on their inputs. Drawn stand-in, not a trained model.
Why mu plus sigma times epsilon has exactly the distribution N(mu, sigma squared) is derived in Multivariate Gaussian & Joint Distributions. The gradients are one line: the derivative of z with respect to mu is 1, and with respect to sigma it is epsilon.
The reparameterization trick appears far beyond VAEs: in stochastic computation graphs and in policy gradient methods with continuous actions. The principle is the same each time. When you must pass gradients through a sampling step, move the randomness outside the parameters.
#Latent Space Interpolation
Because the latent space is smooth, you can walk between two pictures. Given two inputs x1 and x2:
- Encode both: z1 = E(x1), z2 = E(x2)
- Interpolate: z_alpha = (1 - alpha) * z1 + alpha * z2, for alpha in [0, 1]
- Decode the interpolated points: D(z_alpha)
The result is a smooth morph between the two inputs: one face turns into another, a "3" gradually becomes a "7", a shoe becomes a boot.
This works because the KL term keeps the latent space smooth: there are no dead zones between encoded points, so every point maps to a plausible output.
- Do: Click two points, then move the interpolation slider from one to the other.
- Notice: The in-between point travels in a straight line and its class label changes where it crosses a cluster border.
- Why: A smooth latent space keeps nearby points similar. Drawn stand-in, not a trained model: the points are placed by hand.
#Beta-VAE: Disentangled Representations
- Dimension 3 controls hair color
- Dimension 7 controls smile intensity
- Dimension 12 controls viewing angle
A higher beta means a stronger pull toward the plain bell curve, more disentanglement, and blurrier reconstructions. It is a real trade-off: you cannot have perfect reconstruction and perfect disentanglement at once.
The beta-VAE objective is derived as the ELBO with a weighted KL term in Autoencoders (Deep Learning track).
#CodePlayground: VAE on MNIST
This is a toy, not a trained VAE. The ten digit centres are placed by hand, the encoder only adds a small random offset, and the decoder picks the nearest centre. It shows what walking through a 2-D latent space looks like, not what a real VAE learns.
Tests · Verify that interpolation produces valid digits at all alpha values. Verify that alpha=0 returns the first digit and alpha=1 returns the second.
#VAE Variants and Modern Descendants
Why are plain VAE outputs blurry? Squared error rewards the average. Under squared error, the best single output is the average of all the images that could belong to the same latent. The derivation shows it exactly.
#Bridge: from continuous to discrete latents
#The continuous VAE inside Stable Diffusion
The two compression figures in this lesson, 64 times and 48 times, count different things. The derivation shows where each comes from.
Auto-Encoding Variational Bayes
Diederik Kingma, Max Welling (2013)
The foundational VAE paper. Introduced the ELBO objective, the reparameterization trick, and launched an entire subfield of deep generative modeling.
Neural Discrete Representation Learning
Aaron van den Oord, Oriol Vinyals, Koray Kavukcuoglu (2017)
Introduced VQ-VAE: replacing continuous latent variables with discrete codebook entries. Discrete image tokens later influenced DALL-E 1's dVAE and many token-based image and audio models. Stable Diffusion's VAE is continuous (KL-regularised), not VQ.
#Key Takeaways
- VAEs add structure to the latent space. Instead of one point, the encoder gives a cloud (mean and spread), which makes the latent space smooth and easy to walk through
- The ELBO is the VAE training score: rebuild well, minus a penalty for a messy latent space
- The reparameterization trick makes VAEs trainable. Writing the random sample as z = mu + sigma * epsilon (epsilon is a random draw) lets gradients pass through the sampling step
- Walking between two points in a well-built latent space gives smooth, realistic in-between pictures
- A bigger beta gives more readable axes and blurrier pictures. Too much, or a full KL weight from step one, and the latent carries nothing (posterior collapse)
#Quick Check
What does a VAE encoder produce for one input picture?