The Math Behind the Machine/ Unit 20 · From Noise to Pictures Checks 0/32
Unit 20 of 20 · by Prof. Saurabh

From Noise to Pictures: VAEs and Diffusion

In Unit 19 a machine wrote text one word at a time. Here a machine draws. The secret is almost too simple: start from random noise, and turn it, step by step, into something that looks like real data. First we meet the VAE, which squeezes pictures into a small map and learns to draw from any point on it. Then we meet diffusion, which learns to destroy a picture with noise and then runs the film backwards — a compass at every point showing the way to real data. Gaussians, KL, the chain rule and gradient descent from the whole course all come back here.

≈ 150 min read + play 14 interactive widgets · 3 in 3D · every diffusion picture computed exactly 32 inline checks 🧾 18 proofs, folded away — open "if you want the algebra" when you are ready ✍ 16 solved practice problems

← Unit 19 · The Maths Inside an LLM

static walks back into a picture · drag to orbit
1

Drawing from a hat of noise

Imagine this

Before Ganesh Chaturthi, a sculptor in a small workshop makes one idol after another. Every morning his helper hands him a lump of clay. No two lumps are the same: one is a little bigger, one a little lopsided, one a little wetter.

The sculptor's hands make the same moves every time. Yet every idol comes out slightly different, and every one of them still looks like Ganesha. The skill is fixed. The lump is random. Put the two together and new idols keep coming.

The question. How can a machine draw a face that has never existed?

Here is the whole idea of this unit in one line: to create is to sample. A machine that creates is a machine that takes easy randomness — the lump of clay — and turns it into something that looks like the real data. We call such a machine a generator. The randomness goes in, the sculptor's fixed skill is a function gg, and a new example comes out: x=g(z)x=g(z).

By hand, with heights. Say the heights of grown men in a town follow a bell curve with mean 170 cm and spread 7 cm, written N(170, 72)N(170,\ 7^2). How do we make up a new, realistic height? Draw a standard random number zz from N(0,1)N(0,1) — the easiest bell curve there is, centred at 0 with spread 1 — and then stretch and shift it:

x=μ+σz=170+7z.x=\mu+\sigma z=170+7z.

Four draws of the hat give z=−1, 0, 0.5, 2z=-1,\ 0,\ 0.5,\ 2. The machine turns them into

170+7(−1)=163170+7(0)=170170+7(0.5)=173.5170+7(2)=184.\begin{aligned}170+7(-1)&=163\\ 170+7(0)&=170\\ 170+7(0.5)&=173.5\\ 170+7(2)&=184.\end{aligned}

Four new men who never existed, each with a believable height. The skill (×7\times7, then +170+170) never changed. Only the lump zz did.

Not every shape is a bell. Waiting times at a bus stop, say, follow an exponential curve: short waits are common and long waits are rare. With λ=1\lambda=1 the chance that the wait is at most xx minutes is F(x)=1−e−xF(x)=1-e^{-x}. Now take the plainest noise of all, a number uu spread evenly between 0 and 1, and solve u=F(x)u=F(x) for xx:

x=−ln⁡(1−u).x=-\ln(1-u).

With u=0.5u=0.5: x=−ln⁡0.5≈0.6931x=-\ln 0.5\approx0.6931 minutes. This trick is called the inverse CDF (the CDF is the "chance of at most xx" curve, FF). It works for any shape of data in one dimension: run the curve FF backwards on even noise.

The hard part. For heights and waiting times someone can write the curve down. For pictures, nobody can. A 20 × 20 grey picture is already 400 numbers, and there is no formula for "all the pictures that look like a face". So the generator has to be learned from examples. That is what the whole unit is about: two ways to learn the sculptor's hands — the VAE (Act II) and diffusion (Act III).

The noise machineAlong the bottom: the easy noise that goes in (grey). The curve is the machine x=g(z)x=g(z). Up the left side: what comes out (green). Each ball drops in at the bottom, rises to the curve, and slides across to its output. The dashed lines show the shapes the two piles should take.

Try: On heights, press the four draws of the text: the balls come out at 163, 170, 173.5 and 184. Press draw 500 and watch the green pile take the bell shape of N(170, 72)N(170,\ 7^2). Switch to waiting times and press draw u = 0.5: it comes out at 0.6931. Then try two bumps: plain bell-curve noise in, two humps out — the steep part of the curve splits the pile in two.

Why does this work?

Look at the curve as a funnel. Where it is steep, a narrow band of inputs is stretched over a wide band of outputs, so the balls spread thin. Where it is flat, a wide band of inputs is squeezed into a narrow band of outputs, so the balls pile up. So the curve decides where the pile is high and where it is low: output density = input density ÷ slope. The inverse CDF picks exactly the curve whose slope makes the pile come out right. A learned generator does the same thing in hundreds of dimensions, with a neural network as the curve.

Four ways to learn the sculptor's hands. Every modern generator turns noise into data. They differ in how the noise goes in and how the machine is trained.

familyhow it drawswhere the noise goes ingood atweak at
autoregressive (Unit 19)one piece at a time, each piece chosen from a probability lista dice roll at every tokentext; exact likelihoodslow: one step per piece
VAE (§3–§7)pick a point on a small map, decode it in one gothe point z∼N(0,I)z\sim N(0,I)fast; a smooth map you can walkblurry pictures
GANone pass of a generator networka random vector zzsharp pictures, fastunstable training; can forget whole kinds of data
diffusion (§8–§13)start from static, remove a little noise many timesthe starting static, and a little at every stepsharp, varied pictures; easy to steermany steps (§12 makes it faster)

A GAN in one paragraph. A GAN (a generative adversarial network) trains two networks against each other, like a forger and a detective. The forger turns noise into fake pictures. The detective looks at real pictures and fakes and says "real" or "fake". The forger improves by fooling the detective, the detective improves by catching the forger. It gives sharp pictures, but the contest is hard to balance, and the forger may learn to draw only a few kinds of picture that fool the detective. We will not build one here: the VAE and diffusion are the ones whose maths this course has prepared you for.

Rule of thumb. Text: autoregressive. A fast generator with a smooth map of the data: VAE. The best pictures today: diffusion — often run inside a VAE's map (§13).

Trap

A machine that hands back the training pictures is not creating — it is copying. We want new examples that come from the same distribution as the training data: new heights that are believable, not the heights of the men we measured. A generator is judged by whether its samples look like they came from the same hat, not by whether they match any one example.

The realization

x=g(z),z∼easy noisex=g(z),\qquad z\sim\text{easy noise}

A generator is a fixed function applied to fresh noise. In one dimension we can write the function down: stretch-and-shift for a bell curve, the inverse CDF for anything else. For pictures the function must be learned — and learning it is the whole art.

Pause & predict

In the heights machine you change the curve from 170+7z170+7z to 170+14z170+14z. What happens to the green pile of outputs?

Pause & predict

In the waiting-times machine x=−ln⁡(1−u)x=-\ln(1-u), where do most of the outputs pile up, and why?

If you want the algebra · 2 proofs, step by step
Prove it · running the CDF backwards gives the right shape

Claim. Let FF be a CDF that rises steadily (so it has an inverse), and let uu be spread evenly on (0,1)(0,1). Then x=F−1(u)x=F^{-1}(u) has exactly the CDF FF.

1
Ask for the chance that the output is at most some value aa: P(x≤a)=P(F−1(u)≤a)=P(u≤F(a)).\begin{aligned}&P(x\le a)\\ &=P\big(F^{-1}(u)\le a\big)\\ &=P\big(u\le F(a)\big).\end{aligned} FF rises steadily, so applying it to both sides keeps the "≤\le" the right way round.
2
For even noise on (0,1)(0,1), the chance of landing below any number cc between 0 and 1 is just cc. So P(u≤F(a))=F(a)P(u\le F(a))=F(a) — exactly the CDF we wanted. ∎ Exponential with λ=1\lambda=1: F(x)=1−e−xF(x)=1-e^{-x}, so u=1−e−xu=1-e^{-x} gives x=−ln⁡(1−u)x=-\ln(1-u); u=0.5u=0.5 gives ln⁡2≈0.6931\ln2\approx0.6931.
Prove it · output density = input density ÷ slope

Claim. If x=g(z)x=g(z) with gg increasing, and zz has density pzp_z, then xx has density px(x)=pz(z) / g′(z)p_x(x)=p_z(z)\,/\,g'(z) at x=g(z)x=g(z).

1
A thin band of inputs [z, z+dz][z,\ z+dz] holds probability pz(z) dzp_z(z)\,dz. The curve sends it to the band [x, x+g′(z) dz][x,\ x+g'(z)\,dz], which must hold the same probability: px(x) g′(z) dz=pz(z) dz.p_x(x)\,g'(z)\,dz=p_z(z)\,dz. Balls are neither made nor lost on the way through the curve.
2
Divide by g′(z) dzg'(z)\,dz: px(x)=pz(z)/g′(z)p_x(x)=p_z(z)/g'(z). Steep curve, thin pile; flat curve, tall pile. ∎ For x=170+7zx=170+7z: g′=7g'=7, so the output bell is 7 times wider and 7 times lower than N(0,1)N(0,1) — that is N(170, 72)N(170,\ 7^2). In many dimensions the slope becomes a Jacobian determinant (Unit 4's volume factor).

The road ahead. The unit has four acts.

  1. To create is to sample (§1–§2): the noise machine, and the two facts about Gaussian noise that everything later uses.
  2. Squeeze, then rebuild (§3–§7): the autoencoder, the VAE's cloud, the reparameterisation trick, the ELBO, and walking the map of faces.
  3. Noise in, noise out (§8–§12): diffusion — destroy a picture with noise, learn to guess the noise, the score as a compass, walk back from static, and the fast jump.
  4. Steering, and the whole course (§13–§14): steering with words, latent diffusion, and every tool of the course inside the two machines.

In one sentence: A generator is a sculptor's fixed skill applied to a random lump of clay — x=g(z)x=g(z) with fresh noise zz — and since nobody can write gg down for pictures, the machine has to learn it.

2

The Gaussian toolkit for noise

Imagine this

You have a glass of hot chai, filled to the brim. You pour out one tenth of it and top the glass up with milk. Then you do it again, and again. The glass is always exactly full. But after enough rounds, what is in it is almost all milk, and it no longer matters whether you started with strong chai or weak chai.

The question. Diffusion (Act III) will add noise to a picture again and again. How do we add noise so that the numbers never blow up, and so that we always know exactly where they end up?

Two facts about bell curves from Unit 14 do all the work.

  1. Scaling. Multiply a random number by aa and its variance is multiplied by a2a^2: Var⁡(aX)=a2Var⁡X\operatorname{Var}(aX)=a^2\operatorname{Var}X. (The spread, which is the square root, is multiplied by ∣a∣|a|.)
  2. Adding. Add two independent bell curves and you get a bell curve whose variances add: Var⁡(X+Y)=Var⁡X+Var⁡Y\operatorname{Var}(X+Y)=\operatorname{Var}X+\operatorname{Var}Y.

One noising step. Take a number xx and fresh noise ε∼N(0,1)\varepsilon\sim N(0,1), and make

xnew=0.9 x+0.1 ε.x_{\text{new}}=\sqrt{0.9}\,x+\sqrt{0.1}\,\varepsilon.

This is the chai glass: keep 90% of the variance of the old drink, top up with 10% of new milk. If xx itself was a standard bell curve, the two facts give the new variance at once:

(0.9)2⋅1+(0.1)2⋅1=0.9+0.1=1.\begin{aligned}&(\sqrt{0.9})^2\cdot1+(\sqrt{0.1})^2\cdot1\\ &=0.9+0.1=1.\end{aligned}

The glass stays exactly full. Now fix one starting value, x=2x=2. The first part is no longer random: 0.9×2≈1.8974\sqrt{0.9}\times2\approx1.8974. Only the noise part is random, with spread 0.1≈0.3162\sqrt{0.1}\approx0.3162. So

xnew∼N(1.8974, 0.31622).x_{\text{new}}\sim N\big(1.8974,\ 0.3162^2\big).

In words: shrink the signal a little, add a little noise, and the total size stays the same. Repeat it nn times and the signal shrinks to 0.9 nx\sqrt{0.9}^{\,n}x while the noise variance grows to 1−0.9n1-0.9^{n}. After many steps the starting point is forgotten, and every start ends in the same cloud, N(0,1)N(0,1). This one step, repeated, is the forward process of diffusion (§8).

The chai glass: shrink a little, add a little400 copies of one starting number (green) take the step x→0.9 x+0.1 εx\to\sqrt{0.9}\,x+\sqrt{0.1}\,\varepsilon, each with its own noise. Top: their pile (bars) and the bell curve the two facts predict (dashed). Right: how much of the start survives, 0.9 n\sqrt{0.9}^{\,n}, and how big the noise has grown, 1−0.9 n\sqrt{1-0.9^{\,n}}.

Try: Press 1 step: the pile sits at 1.8974 with spread 0.3162. Press 10 steps a few times: the pile slides to 0 and widens to spread 1, and the start is forgotten. Move start to −3 and do it again — same end. Switch to start from a whole N(0, 1) cloud: step as much as you like, the cloud never changes size, because 0.9 + 0.1 = 1.

2
Why does this work?

Because the two numbers 0.9\sqrt{0.9} and 0.1\sqrt{0.1} are chosen so that their squares add up to 1. Variance is what adds for independent noise, and a factor inside a variance comes out squared. So the step takes exactly 10% of the variance away from the signal and gives exactly 10% to fresh noise. Nothing grows, nothing shrinks overall; the drink just slowly turns into milk. Any pair 1−β\sqrt{1-\beta} and β\sqrt{\beta} does the same, which is why diffusion writes every step this way.

Two ways to add noise, side by side.

just add noise: x+0.1 εx+\sqrt{0.1}\,\varepsilonshrink, then add: 0.9 x+0.1 ε\sqrt{0.9}\,x+\sqrt{0.1}\,\varepsilon
variance after one step (start N(0,1)N(0,1))1.11
after 100 steps11 — it keeps growingstill 1
where every start ends upnowhere fixed: the cloud keeps spreadingthe same N(0,1)N(0,1), whatever the start
used byscore models with growing noiseDDPM (§8) — "variance preserving"

Rule of thumb. Shrink by 1−β\sqrt{1-\beta} whenever you add noise of variance β\beta. Then the numbers stay the same size forever, and the end of the road is always the same easy cloud.

Trap

Add two independent noises, each with spread 1. The spread of the sum is not 2. Variances add, spreads do not: the variance is 1+1=21+1=2, so the spread is 2≈1.414\sqrt2\approx1.414. Two people pushing a cart in random directions do not push it twice as far — they often partly cancel.

The realization

Var⁡(aX+bY)=a2Var⁡X+b2Var⁡Yx→1−β x+β ε\begin{gathered}\operatorname{Var}(aX+bY)\\ =a^2\operatorname{Var}X+b^2\operatorname{Var}Y\\ x\to\sqrt{1-\beta}\,x+\sqrt{\beta}\,\varepsilon\end{gathered}

For independent noise, variances add and a scale factor comes out squared. So "shrink by 1−β\sqrt{1-\beta}, add noise of variance β\beta" keeps a standard cloud standard, and slowly washes any starting point into the same N(0,1)N(0,1).

Pause & predict

Start from the fixed number x=2x=2 and take two steps x→0.9 x+0.1 εx\to\sqrt{0.9}\,x+\sqrt{0.1}\,\varepsilon, with fresh noise each time. What is the bell curve now?

Pause & predict

You add three independent noises, each with spread 2. What is the spread of the total?

If you want the algebra · 2 proofs, step by step
Prove it · variances of independent noise add

Claim. If XX and YY are independent, with means mX,mYm_X,m_Y, then Var⁡(aX+bY)=a2Var⁡X+b2Var⁡Y\operatorname{Var}(aX+bY)=a^2\operatorname{Var}X+b^2\operatorname{Var}Y.

1
Subtract the mean and call what is left X~=X−mX\tilde X=X-m_X, Y~=Y−mY\tilde Y=Y-m_Y: then aX+bY−(amX+bmY)=aX~+bY~aX+bY-(am_X+bm_Y)=a\tilde X+b\tilde Y. Square and average: Var⁡=a2 E[X~2]+b2 E[Y~2]+2ab E[X~Y~].\begin{aligned}\operatorname{Var}&=a^2\,\mathbb E[\tilde X^2]\\ &\quad+b^2\,\mathbb E[\tilde Y^2]\\ &\quad+2ab\,\mathbb E[\tilde X\tilde Y].\end{aligned} (p+q)2=p2+q2+2pq(p+q)^2=p^2+q^2+2pq, then average each part.
2
For independent X,YX,Y the last average splits into E[X~] E[Y~]=0⋅0\mathbb E[\tilde X]\,\mathbb E[\tilde Y]=0\cdot0. What is left is a2Var⁡X+b2Var⁡Ya^2\operatorname{Var}X+b^2\operatorname{Var}Y. ∎ With a=0.9a=\sqrt{0.9}, b=0.1b=\sqrt{0.1} and two standard bells: 0.9+0.1=10.9+0.1=1. The sum of two independent bells is again a bell (Unit 14), so knowing the mean and variance is knowing everything.
Prove it · after n steps: N(0.9 nx0, 1−0.9n)N\big(\sqrt{0.9}^{\,n}x_0,\ 1-0.9^{n}\big)

Claim. Start at a fixed x0x_0 and repeat x→0.9 x+0.1 εx\to\sqrt{0.9}\,x+\sqrt{0.1}\,\varepsilon with fresh noise. After nn steps, xn∼N(0.9 nx0, 1−0.9n)x_n\sim N\big(\sqrt{0.9}^{\,n}x_0,\ 1-0.9^{n}\big).

1
True for n=0n=0: mean x0x_0, variance 1−1=01-1=0. Suppose it holds for nn. One more step gives mean 0.9⋅0.9 nx0=0.9 n+1x0\sqrt{0.9}\cdot\sqrt{0.9}^{\,n}x_0=\sqrt{0.9}^{\,n+1}x_0. The noise has mean 0, so only the signal carries the mean.
2
Variance: the old noise is scaled by 0.9\sqrt{0.9}, the new noise adds 0.1: 0.9 (1−0.9n)+0.1=1−0.9 n+1.\begin{aligned}&0.9\,(1-0.9^{n})+0.1\\ &=1-0.9^{\,n+1}.\end{aligned} ∎ As nn grows, 0.9n→00.9^{n}\to0: mean →0\to0, variance →1\to1. Every start ends in N(0,1)N(0,1). With n=1n=1, x0=2x_0=2: N(1.8974, 0.31622)N(1.8974,\ 0.3162^2).

In one sentence: For independent noise variances add and scale factors come out squared, so "shrink by 1−β\sqrt{1-\beta}, add noise of variance β\beta" keeps the glass exactly full while slowly turning any chai into the same milk, N(0,1)N(0,1).

3

The autoencoder: squeeze and rebuild

Imagine this

Your friend is arriving at a crowded railway station, and your cousin has never seen him. You phone your cousin, and the line is bad — you only have time for two numbers. You say: "Face size 7 out of 10. Smile 9 out of 10." Your cousin, who is good at sketching, draws a face from those two numbers and goes looking for the man who matches.

You squeezed a whole face into two numbers. Your cousin rebuilt a face from them. If the sketch looks like your friend, the two numbers held what mattered.

The question. Can a machine learn, by itself, which few numbers describe a picture — and learn to draw the picture back from them?

An autoencoder is two networks back to back. The encoder (you, on the phone) reads a picture xx and squeezes it into a short list of numbers, the code zz. The decoder (your cousin) reads the code and rebuilds a picture x^\hat x. Training asks only one thing: make the rebuild match the picture. The loss is the squared error over every pixel, summed over all the training pictures:

L=∑pictures∥x−x^∥2,x^=dec⁡(enc⁡(x)).\begin{gathered}L=\sum_{\text{pictures}}\big\|x-\hat x\big\|^2,\\ \hat x=\operatorname{dec}\big(\operatorname{enc}(x)\big).\end{gathered}

The toy on this page. We made up 4 000 small grey faces, each 20 × 20 = 400 pixels. Two things vary: how big the face is, and how much it smiles (from a frown to a big smile). We trained a small autoencoder on them for this page, with a code of just 2 numbers — so the whole map of codes fits on your screen. 400 numbers in, 2 in the middle, 400 out: a squeeze of 200 times. Nobody told the network about "size" or "smile". The squeeze forced it to find them, because two numbers are only enough if they are the two that matter.

You have seen this before. In Unit 12, PCA squeezed data onto the few directions with the most variation. Make the encoder and decoder plain matrices (no curves at all) and train with squared error: the best such autoencoder squeezes onto exactly the same subspace as PCA. A curved (nonlinear) autoencoder can do more: it can bend its map to follow data that lies on a curved surface.

So can we create? Here is the tempting idea: throw away the encoder, pick a random code, and let the decoder draw. Try it below. On the plain autoencoder it mostly fails. The codes of real faces landed in a lopsided patch, stretched far to one side of 0, with empty regions around it. Nothing in training ever asked the decoder what to draw for a code from an empty region, so it draws whatever it likes — often something that is not a face at all.

The map of codes, and what each point drawsLeft: every pink dot is the code of one training face (300 are shown). Behind them, faintly, is what the decoder draws at every point of the map. The rings mark where N(0,I)N(0,I) puts 39% and 86% of its draws. Right: the face drawn at the point you picked, and how far it is from the nearest real face's rebuild. A toy trained for this page on made-up drawings.

Try: On the plain autoencoder, click inside the pink patch: a clean face. Click in the empty area near 0 — right inside the rings: a smudge or an inverted blob, marked not a face. Press 200 random codes from N(0, I): about 65% are not faces. Switch to the VAE and press it again: about 4%. The VAE's map is centred and full.

Why does this work?

Because the squeeze leaves no room for anything else. Two numbers cannot hold 400 pixels, so the network must spend them on whatever changes most from face to face — here, size and smile. Every face that differs only in the small details gets the same code and the same rebuild. That is PCA's idea (Unit 12) done with curves: keep the few directions along which the data really varies, and throw the rest away. And it is also why the empty regions are dangerous: the loss only ever looked at the codes of real faces, so every other point of the map is untested.

Three ways to squeeze, side by side.

PCA (Unit 12)linear autoencodernonlinear autoencoder
squeezeproject onto the top eigenvectorsa matrixa network with curves
rebuildthe same eigenvectors, backanother matrixanother network
what it findsthe best flat subspacethe same subspace (maybe with tilted axes)a curved surface that follows the data
trained byan eigen-decomposition, in one gogradient descentgradient descent
a random code givesa blend of eigen-picturesa blend of eigen-picturesanything — often garbage outside the patch

Rule of thumb. If the data lies near a flat subspace, PCA is enough and needs no training. If it lies on a curved surface, use an autoencoder. If you want to create, a plain autoencoder is not enough: you need a map with no empty regions — the VAE of §4.

Trap

A good rebuild does not make a good generator. The plain autoencoder rebuilds its training faces very well, yet most random codes decode to rubbish. Rebuilding asks "is the decoder right at the codes of real pictures?" Creating asks "is the decoder right everywhere we might pick a code?" Those are different questions.

The realization

min⁡enc, dec∑x∥x−dec⁡(enc⁡(x))∥2\min_{\text{enc},\ \text{dec}}\sum_{x}\big\|x-\operatorname{dec}(\operatorname{enc}(x))\big\|^2

An autoencoder squeezes each picture into a short code and learns to rebuild it. The squeeze forces the code to keep only what varies most — with straight lines, it is PCA. But it makes no promise about the empty parts of the map, so it is a compressor, not yet a creator.

Pause & predict

The plain autoencoder's codes lie roughly between −10 and 0 across and between −1 and 4 up. You pick 1 000 random codes from N(0,I)N(0,I), centred at the origin. What happens?

Pause & predict

You train a linear autoencoder (matrices only, no curves) with a 2-number code on some data, using squared error. PCA on the same data gives a top-2 plane. What does the autoencoder's decoder span?

If you want the algebra · 1 proof, step by step
Prove it · a linear autoencoder finds PCA's subspace

Claim. Take centred data (the rows of XX), a linear encoder z=E xz=E\,x and a linear decoder x^=D z\hat x=D\,z with a kk-number code. The smallest possible total squared error ∑∥x−DEx∥2\sum\|x-DEx\|^2 is reached when DEDE is the projection onto the top-kk principal directions — the same subspace PCA keeps.

1
Whatever EE and DD are, DEDE is a matrix of rank at most kk: every rebuild DExDEx lies in the column space of DD, a kk-dimensional subspace SS. A kk-number code can only reach kk directions.
2
For a fixed subspace SS, the closest point of SS to each xx is its orthogonal projection PxPx (Unit 3). So the best any linear autoencoder can do with that SS is ∑∥x−Px∥2\sum\|x-Px\|^2, and it achieves it by choosing EE to compute the projection's coordinates. Any other point of SS is farther away, by Pythagoras.
3
Now choose SS. The total error is the total spread minus the spread kept in SS, and Unit 12 showed the spread kept is largest for the top-kk eigenvectors of the covariance. So the best SS is PCA's subspace. ∎ The columns of DD need not be the eigenvectors themselves: any basis of the same plane gives the same rebuilds. Gradient descent usually lands on a tilted, stretched basis of it.

In one sentence: An autoencoder squeezes a picture into a few numbers and learns to rebuild it — describing a friend's face in two numbers over a bad phone line — but its map of codes has empty regions, so a random code usually draws rubbish.

4

The VAE: a cloud, not a point

Imagine this

You tell a friend where to meet you. If you give the exact house number — "14/B, Lane 3" — and he lands on the house next door, he is lost. If you say "near the temple in Rajpur" — a neighbourhood, not a house — then anywhere in that neighbourhood is a fine answer, and he will find you.

Now imagine every friend gives a neighbourhood instead of a house number, and the town asks everyone to keep their neighbourhoods near the town centre. The neighbourhoods overlap, and there is no empty land left in town.

The question. How do we stop the map of codes from having empty regions, so that every point decodes to something sensible?

The variational autoencoder, or VAE (Kingma and Welling, 2014), makes two changes.

  1. A cloud, not a point. The encoder no longer outputs one code. It outputs a centre μ\mu and a spread σ\sigma — a small bell-shaped cloud N(μ,σ2)N(\mu,\sigma^2) on the map. During training we pick a random point zz inside the cloud, and the decoder must rebuild the picture from that point. So the decoder learns to draw well over the whole cloud, not just at its centre. A neighbourhood, not a house number.
  2. A pull towards the centre. A second term in the loss pulls every cloud towards the standard cloud N(0,1)N(0,1): centre 0, spread 1. It is the KL divergence of Unit 14, which measures how far one bell curve is from another. For one number of the code,

KL⁡(N(μ,σ2) ∥ N(0,1))=12(μ2+σ2−1−ln⁡σ2).\begin{aligned}&\operatorname{KL}\big(N(\mu,\sigma^2)\,\|\,N(0,1)\big)\\ &=\tfrac12\big(\mu^2+\sigma^2-1-\ln\sigma^2\big).\end{aligned}

Read it aloud. μ2\mu^2: you pay for sitting far from the centre. σ2−1−ln⁡σ2\sigma^2-1-\ln\sigma^2: you pay for a spread that is not 1 — too wide or too narrow. Four clouds, by hand:

μ=1, σ=0.5:12(1+0.25−1−ln⁡0.25)≈0.8181μ=0, σ=1:  12(0+1−1−0)=0μ=2, σ=1:  12(4+1−1−0)=2μ=0, σ=0.1:12(0+0.01−1−ln⁡0.01)≈1.8076\begin{aligned}&\mu=1,\ \sigma=0.5:\\ &\quad\tfrac12(1+0.25-1-\ln0.25)\approx0.8181\\ &\mu=0,\ \sigma=1:\ \ \tfrac12(0+1-1-0)=0\\ &\mu=2,\ \sigma=1:\ \ \tfrac12(4+1-1-0)=2\\ &\mu=0,\ \sigma=0.1:\\ &\quad\tfrac12(0+0.01-1-\ln0.01)\approx1.8076\end{aligned}

The standard cloud itself costs nothing. Moving it away costs μ2/2\mu^2/2. And look at the last one: a cloud sitting right at the centre but too sure of itself (spread 0.1) costs more than the one at μ=1\mu=1. The KL does not only pull clouds in; it also keeps them from shrinking back into points.

The full loss for one picture adds the two jobs, with a weight β\beta on the pull (β=1\beta=1 is the plain VAE):

loss= rebuild error from a point in the cloud⏟be useful+β KL⁡(cloud ∥ N(0,I))⏟stay near the centre.\begin{aligned}\text{loss}=\ &\underbrace{\text{rebuild error from a point in the cloud}}_{\text{be useful}}\\ &+\beta\,\underbrace{\operatorname{KL}\big(\text{cloud}\,\|\,N(0,I)\big)}_{\text{stay near the centre}}.\end{aligned}

(For a code of two numbers, the KLs of the two entries simply add up.) Our toy VAEs were trained with three weights, β=0.1, 1, 30\beta=0.1,\ 1,\ 30, on the same faces.

Every face is a cloud — and every cloud pays a priceThe glass floor is the map of codes. Each pink ellipse is one training face's cloud (its 1σ outline; 150 of the 300 faces are drawn), and it floats at a height equal to its KL price: the higher, the more it pays. Its shadow on the floor shows where it sits. The white rings are N(0,I)N(0,I), where the KL pulls. Below: 12 faces, and what each model rebuilds from the centre of their clouds.

Try: Switch between the three weights. At β = 0.1 the clouds are tiny and float high (KL about 8 each), and their shadows leave empty land between them. At β = 1 they are bigger, lower, and their shadows cover the rings. At β = 30 they sink to the floor, stretch into long bars across the whole map, and the rebuilds below all get the same blurred mouth: the smile number has stopped carrying anything (its KL is 0). Click a face below to light up its cloud and read its KL by the formula.

drag the picture to orbit

12 training faces · top: the face · bottom: rebuilt from the centre of its cloud
Why does this work?

Two forces meet. The rebuild term wants each cloud small and apart, so that the decoder can tell the faces apart. The KL term wants every cloud to be the same wide cloud at the centre. The balance is a map where clouds of similar faces overlap. Wherever two clouds overlap, the decoder was trained to draw both faces from nearby points, so it learns to draw something in between — a sensible face. Overlap everywhere means no empty land: every point of the rings has been trained on.

The weight on the pull, side by side. These are the three toy VAEs of the widget.

β=0.1\beta=0.1 (weak pull)β=1\beta=1 (the plain VAE)β=30\beta=30 (strong pull)
cloudstiny, almost pointssmall, overlappingwide, all at the centre
average KL per faceabout 8.0about 5.0about 1.2 (the smile number: 0)
rebuildssharpsharpright size, but every mouth the same blur
random codesmany land in holesalmost all good facesfaces, but no smiles or frowns

Rule of thumb. Too little pull and you have a plain autoencoder with holes. Too much and the code stops carrying information — "posterior collapse". Start at β=1\beta=1 and watch the KL of each code number: a number whose KL falls to 0 has stopped being used.

Trap

The KL term is not a nuisance to push to zero. A KL of exactly 0 means the cloud is the standard cloud, whatever the picture — so the code tells the decoder nothing about the picture. At β=30\beta=30 this happened to the smile number: its KL is 0, and every rebuilt mouth is the same average blur. A useful code must pay some KL.

The realization

loss= E ∥x−dec⁡(z)∥2+β KL⁡(cloud ∥ N(0,I))\begin{aligned}\text{loss}=\ &\mathbb E\,\big\|x-\operatorname{dec}(z)\big\|^2\\ &+\beta\,\operatorname{KL}\big(\text{cloud}\,\|\,N(0,I)\big)\end{aligned}

A VAE encodes each picture as a cloud, rebuilds from a random point zz in it, and pays a KL price — 12(μ2+σ2−1−ln⁡σ2)\tfrac12(\mu^2+\sigma^2-1-\ln\sigma^2) for each number of the code — for every cloud that is far from the centre or too narrow. The clouds of similar pictures overlap, the map fills up, and every point decodes to something sensible.

Pause & predict

Two clouds for one code number: A has μ=0\mu=0, σ=0.5\sigma=0.5; B has μ=0.5\mu=0.5, σ=1\sigma=1. Which pays the bigger KL?

Pause & predict

You raise the KL weight β\beta from 1 to 30. What happens to the clouds and to the rebuilds?

Pause & predict

A code has two numbers. Its cloud has μ=(2,0)\mu=(2,0) and σ=(1,1)\sigma=(1,1). What is its total KL to N(0,I)N(0,I)?

If you want the algebra · 1 proof, step by step
Prove it · the KL of a bell curve to the standard one

Claim. KL⁡(N(μ,σ2) ∥ N(0,1))=12(μ2+σ2−1−ln⁡σ2)\operatorname{KL}\big(N(\mu,\sigma^2)\,\|\,N(0,1)\big)=\tfrac12\big(\mu^2+\sigma^2-1-\ln\sigma^2\big), and it is 0 only at μ=0, σ=1\mu=0,\ \sigma=1.

1
KL is the average, under q=N(μ,σ2)q=N(\mu,\sigma^2), of ln⁡q(z)−ln⁡p(z)\ln q(z)-\ln p(z) (Unit 14). The two logs of bell curves are ln⁡q=−12ln⁡(2πσ2)−(z−μ)22σ2ln⁡p=−12ln⁡(2π)−z22\begin{aligned}\ln q&=-\tfrac12\ln(2\pi\sigma^2)\\ &\quad-\tfrac{(z-\mu)^2}{2\sigma^2}\\ \ln p&=-\tfrac12\ln(2\pi)-\tfrac{z^2}{2}\end{aligned} The ln⁡2π\ln2\pi parts cancel in the difference.
2
Average over z∼qz\sim q: E[(z−μ)2]=σ2\mathbb E[(z-\mu)^2]=\sigma^2 and E[z2]=μ2+σ2\mathbb E[z^2]=\mu^2+\sigma^2. So KL⁡=−12ln⁡σ2−12+12(μ2+σ2)=12(μ2+σ2−1−ln⁡σ2).\begin{aligned}\operatorname{KL}&=-\tfrac12\ln\sigma^2-\tfrac12\\ &\quad+\tfrac12(\mu^2+\sigma^2)\\ &=\tfrac12(\mu^2+\sigma^2\\ &\qquad-1-\ln\sigma^2).\end{aligned} E[z2]\mathbb E[z^2] is the variance plus the mean squared.
3
μ2≥0\mu^2\ge0 is smallest at μ=0\mu=0. And s−1−ln⁡ss-1-\ln s with s=σ2s=\sigma^2 has slope 1−1/s1-1/s, zero only at s=1s=1, where it is 00; it is positive everywhere else. So the KL is 0 exactly for the standard cloud. ∎ μ=0, σ=0.1\mu=0,\ \sigma=0.1: 12(0.01−1+4.6052)≈1.8076\tfrac12(0.01-1+4.6052)\approx1.8076. A too-narrow cloud pays through −ln⁡σ2-\ln\sigma^2.

In one sentence: A VAE gives every picture a neighbourhood, not a house number — a small cloud on the map — and a KL price pulls every cloud towards the town centre, so the clouds overlap and every point of the map has been trained to draw a sensible picture.

5

The reparameterisation trick

Imagine this

A darts player's hand always wobbles a little. If the wobble happens by surprise, you cannot say what would have happened had he aimed a little to the left. But suppose the wobble is decided in advance — written on a card before the throw: "2 cm right, 1 cm up". Now the dart lands at aim + wobble. Move the aim 1 cm left, and the dart moves exactly 1 cm left. You can ask how the aim moves the dart.

The question. Training a VAE means backpropagation (Unit 7): blame flows from the loss back to every weight. But in the middle of the network we draw a random point from the cloud. How does blame flow backwards through a dice roll?

It cannot, as long as the dice roll is inside the network. "Draw zz from N(μ,σ2)N(\mu,\sigma^2)" is not a formula in μ\mu and σ\sigma: nudge μ\mu and the draw simply comes out different, with no slope to follow.

The trick. Roll the dice first, outside the network, as the card with the wobble: ε∼N(0,1)\varepsilon\sim N(0,1). Then build the draw by the stretch-and-shift of §1:

z=μ+σ ε.z=\mu+\sigma\,\varepsilon.

The randomness has moved into an input. And zz is now an ordinary formula in μ\mu and σ\sigma, so it has slopes.

By hand. Take μ=1\mu=1, σ=0.5\sigma=0.5, and the card says ε=0.4\varepsilon=0.4:

z=1+0.5×0.4=1.2∂z∂μ=1,∂z∂σ=ε=0.4.\begin{aligned}z&=1+0.5\times0.4=1.2\\ \frac{\partial z}{\partial\mu}&=1,\qquad \frac{\partial z}{\partial\sigma}=\varepsilon=0.4.\end{aligned}

Now the chain rule of Unit 7 does the rest. Say the rest of the network (a stand-in here) gives the loss L=(z−2)2L=(z-2)^2: the decoder would like zz to be 2. Then ∂L/∂z=2(1.2−2)=−1.6\partial L/\partial z=2(1.2-2)=-1.6, and the blame splits:

∂L∂μ=−1.6×1=−1.6∂L∂σ=−1.6×0.4=−0.64.\begin{aligned}\frac{\partial L}{\partial\mu}&=-1.6\times1=-1.6\\ \frac{\partial L}{\partial\sigma}&=-1.6\times0.4=-0.64.\end{aligned}

Both slopes are negative, so gradient descent raises μ\mu (and, with this ε\varepsilon, σ\sigma a little) to move the dart towards 2. Blame flows straight through.

Blame through a dice rollThe computation graph of one draw. Pink: the cloud's centre μ and spread σ, made by the encoder. Grey: the random wobble. Press ▶ to send the blame backwards (gold) from the loss L=(z−2)2L=(z-2)^2. Right: 2 000 draws of z made with fresh wobbles, and the bell curve N(μ,σ2)N(\mu,\sigma^2) they should follow.

Try: In dice inside the network, press ▶ backward pass: the blame stops at the dice, broken — μ and σ get nothing. Switch to reparameterised and press it again: the blame reaches μ as −1.6 and σ as −0.64. Drag ε to −0.4: z = 0.8, and σ's slope becomes +0.96 — the other way, because this wobble points left. The histogram on the right always matches N(μ,σ2)N(\mu,\sigma^2): the trick changes how we draw, not what we draw.

1
0.5
0.4
Why does this work?

Because μ+σε\mu+\sigma\varepsilon with ε∼N(0,1)\varepsilon\sim N(0,1) is exactly a draw from N(μ,σ2)N(\mu,\sigma^2) — the stretch-and-shift of §1. So nothing about the model changes; only the bookkeeping does. The randomness is now a fixed input for each training step, like a picture, and everything that depends on μ\mu and σ\sigma is a smooth formula. Average the slopes over many wobbles and you get the true slope of the average loss.

Two ways to draw, side by side.

dice inside: draw z∼N(μ,σ2)z\sim N(\mu,\sigma^2)reparameterised: z=μ+σεz=\mu+\sigma\varepsilon
what comes outa draw from N(μ,σ2)N(\mu,\sigma^2)a draw from N(μ,σ2)N(\mu,\sigma^2) — the same
where the randomness livesin the middle of the networkin an input ε\varepsilon, drawn first
∂z/∂μ\partial z/\partial\mu, ∂z/∂σ\partial z/\partial\sigmanot defined1 and ε\varepsilon
trainingneeds slow, noisy tricksordinary backprop

Rule of thumb. Whenever a network must sample in the middle, write the sample as "parameters + a formula of outside noise". Diffusion does the same thing in §8: xt=αˉ x0+1−αˉ εx_t=\sqrt{\bar\alpha}\,x_0+\sqrt{1-\bar\alpha}\,\varepsilon.

Trap

The wobble ε\varepsilon is not learned and not optimised. It is fresh noise for every picture at every step, and it gets no slope of its own. What learns are μ\mu and σ\sigma — and, through them, the encoder's weights.

The realization

z=μ+σ ε,ε∼N(0,1)⇒ ∂z∂μ=1,  ∂z∂σ=ε\begin{gathered}z=\mu+\sigma\,\varepsilon,\quad\varepsilon\sim N(0,1)\\ \Rightarrow\ \frac{\partial z}{\partial\mu}=1,\ \ \frac{\partial z}{\partial\sigma}=\varepsilon\end{gathered}

Roll the dice before the network, not inside it. The draw is the same, but now it is a formula in μ\mu and σ\sigma, and the chain rule carries the blame straight back to the encoder.

Pause & predict

With μ=1\mu=1, σ=0.5\sigma=0.5, the card says ε=−2\varepsilon=-2. What are zz and ∂z/∂σ\partial z/\partial\sigma?

Pause & predict

You switch from "dice inside" to the reparameterised form, and draw 10 000 values of zz each way. How do the two histograms compare?

If you want the algebra · 1 proof, step by step
Prove it · the slope of an average, through the trick

Claim. For a loss ff and z=μ+σεz=\mu+\sigma\varepsilon, ε∼N(0,1)\varepsilon\sim N(0,1):  ∂∂μE[f(z)]=E[f′(z)]\ \dfrac{\partial}{\partial\mu}\mathbb E\big[f(z)\big]=\mathbb E\big[f'(z)\big] and ∂∂σE[f(z)]=E[f′(z) ε]\dfrac{\partial}{\partial\sigma}\mathbb E\big[f(z)\big]=\mathbb E\big[f'(z)\,\varepsilon\big].

1
Write the average over the fixed noise: Eε[f(μ+σε)]\mathbb E_\varepsilon\big[f(\mu+\sigma\varepsilon)\big]. The distribution of ε\varepsilon does not depend on μ\mu or σ\sigma, so the slope can go inside the average. Before the trick, the distribution itself moved with μ\mu, and there was nothing to differentiate inside.
2
Inside, the chain rule (Unit 7): ∂f/∂μ=f′(z)⋅1\partial f/\partial\mu=f'(z)\cdot1, ∂f/∂σ=f′(z)⋅ε\partial f/\partial\sigma=f'(z)\cdot\varepsilon. ∎ One draw gives one noisy estimate of each slope; a batch of pictures averages them. With f=(z−2)2f=(z-2)^2, μ=1, σ=0.5, ε=0.4\mu=1,\ \sigma=0.5,\ \varepsilon=0.4: f′=−1.6f'=-1.6, slopes −1.6-1.6 and −0.64-0.64.

In one sentence: Write the random draw as z=μ+σεz=\mu+\sigma\varepsilon with the wobble ε\varepsilon rolled in advance — a dartboard where the wobble is written on a card — and the chain rule can carry blame through the sampling step straight back to the encoder.

6

The ELBO: the score a VAE maximises

Imagine this

You want to know how high the ceiling of a hall is, but you cannot reach it. What you can measure is a platform you are standing on. The platform is always below the ceiling. Push the platform up, and one of two things must be happening: the ceiling is rising, or the gap between you and the ceiling is closing. Either way, you are doing something useful.

The question. A good generator gives real pictures a high probability p(x)p(x). But for a VAE, p(x)p(x) means "add up, over every code, the chance of that code times the chance it draws xx" — an impossible sum over the whole map. What can we compute and maximise instead?

The answer is the ELBO, the evidence lower bound. (The "evidence" is log⁡p(x)\log p(x).) For any guess q(z)q(z) the encoder makes about which codes could have drawn xx:

log⁡p(x)= Eq[log⁡p(x∣z)]⏟rebuild well−KL⁡(q ∥ p(z))⏟stay near the prior+KL⁡(q ∥ p(z∣x))⏟the gap ≥ 0.\begin{aligned}\log p(x)=\ &\underbrace{\mathbb E_{q}\big[\log p(x\mid z)\big]}_{\text{rebuild well}}\\ &-\underbrace{\operatorname{KL}\big(q\,\|\,p(z)\big)}_{\text{stay near the prior}}\\ &+\underbrace{\operatorname{KL}\big(q\,\|\,p(z\mid x)\big)}_{\text{the gap}\ \ge\ 0}.\end{aligned}

The first two lines together are the ELBO. The ELBO is the platform, log⁡p(x)\log p(x) is the ceiling, and the gap is how wrong the encoder's guess is about the true codes behind xx. Its two parts are exactly the VAE loss of §4, with the sign flipped: rebuild well, and pay KL to the prior.

A whole example, by hand. Take the smallest possible model: just two codes, A and B, each chosen with chance p(z)=0.5p(z)=0.5. Code A draws our picture xx with chance p(x∣A)=0.6p(x\mid A)=0.6, code B with chance p(x∣B)=0.2p(x\mid B)=0.2.

p(x)=0.5(0.6)+0.5(0.2)=0.4log⁡p(x)=ln⁡0.4≈−0.9163p(A∣x)=0.30.4=0.75p(B∣x)=0.25.\begin{aligned}p(x)&=0.5(0.6)+0.5(0.2)=0.4\\ \log p(x)&=\ln0.4\approx-0.9163\\ p(A\mid x)&=\frac{0.3}{0.4}=0.75\\ p(B\mid x)&=0.25.\end{aligned}

That last line is the true posterior: given the picture, A is three times as likely as B. Now let the encoder guess q=(qA, qB)q=(q_A,\ q_B), and compute the ELBO's parts: rebuild =qAln⁡0.6+qBln⁡0.2=q_A\ln0.6+q_B\ln0.2, KL =qAln⁡qA0.5+qBln⁡qB0.5=q_A\ln\frac{q_A}{0.5}+q_B\ln\frac{q_B}{0.5}.

the encoder's guess qqrebuildKL to priorELBOgap
(0.5, 0.5) — no idea−1.06010−1.06010.1438
(0.9, 0.1) — too sure−0.62070.3681−0.98880.0725
(0.75, 0.25) — the truth−0.78550.1308−0.91630

Every row adds up: ELBO + gap =−0.9163=-0.9163, always. The "too sure" guess rebuilds best of all, but pays so much KL that its ELBO is lower than the truth's. The ELBO is highest exactly when the guess is the true posterior — and there it touches the ceiling.

A platform under the ceilingThe two-code toy, on one scale. Left column: the rebuild (orange line) minus the KL (red) leaves the ELBO, the platform (pink). Right column: the platform plus the gap (red hatching) reaches the ceiling log⁡p(x)\log p(x) (white). Far right: the ELBO for every guess qAq_A — a hill that touches the ceiling at the true posterior.

Try: Slide q(A) from 0.5 to 0.9, then to 0.75: the gap shrinks to 0 and the platform touches the ceiling at −0.9163. Then make the model better — slide p(x | A) from 0.6 to 0.8: the ceiling itself rises to ln 0.5 ≈ −0.6931, and the best guess moves to 0.8. Pushing the ELBO up does both jobs.

0.5
0.6
Why does this work?

Because the gap is a KL, and a KL is never negative (Unit 14). So the ELBO is always a floor under log⁡p(x)\log p(x). Training pushes the floor up in two ways at once. Improving the decoder raises the ceiling itself — real pictures become more likely. Improving the encoder closes the gap — its guess gets closer to the true codes. We never compute the ceiling, and we never need to.

Two ways to read the same score.

ELBO = rebuild − KL to priorELBO = log⁡p(x)\log p(x) − gap
what you can computeboth parts, for any pictureneither part (both need the whole map)
what it tells youthe VAE loss, turned upside downwhy the loss is a sensible thing to optimise
best guess qqbalance rebuilding against the pullthe true posterior (gap 0)

Rule of thumb. Train with the left-hand form; understand with the right-hand one. The left form tells you what to compute; the right form tells you why it works — every step that raises it either makes the model better or makes the encoder's guess more honest.

Trap

Maximising the ELBO is not only "rebuild better". It does two jobs at once: it improves the decoder (a higher ceiling) and makes the encoder's guess closer to the truth (a smaller gap). In the table, the guess that rebuilds best, (0.9, 0.1), is not the one with the best ELBO.

The realization

log⁡p(x)=Eq[log⁡p(x∣z)]−KL⁡(q ∥ p(z))+KL⁡(q ∥ p(z∣x))≥ ELBO\begin{aligned}\log p(x)&=\mathbb E_q[\log p(x\mid z)]\\ &\quad-\operatorname{KL}(q\,\|\,p(z))\\ &\quad+\operatorname{KL}\big(q\,\|\,p(z\mid x)\big)\\ &\ge\ \text{ELBO}\end{aligned}

We cannot compute how likely the model makes a picture, but we can compute a floor under it: rebuild well, stay near the prior. Raising the floor either raises the ceiling or closes the gap — and at the true posterior the floor touches the ceiling.

Pause & predict

In the two-code toy, the encoder guesses q=(1,0)q=(1,0): "certainly A". What happens to the ELBO compared with the truth (0.75, 0.25)(0.75,\ 0.25)?

Pause & predict

You make the decoder better: p(x∣A)p(x\mid A) goes from 0.6 to 0.8 (with p(x∣B)=0.2p(x\mid B)=0.2 as before). Where does the best guess qAq_A move, and what is the new ceiling?

Pause & predict

For some guess qq, the rebuild part is −1.2 and the KL to the prior is 0.3, and you know log⁡p(x)=−1.1\log p(x)=-1.1. How big is the gap?

If you want the algebra · 2 proofs, step by step
Prove it · log p(x) = ELBO + KL(q ‖ true posterior)

Claim. For any guess q(z)q(z): log⁡p(x)=Eq[log⁡p(x∣z)]−KL⁡(q ∥ p(z))+KL⁡(q ∥ p(z∣x))\log p(x)=\mathbb E_q\big[\log p(x\mid z)\big]-\operatorname{KL}\big(q\,\|\,p(z)\big)+\operatorname{KL}\big(q\,\|\,p(z\mid x)\big).

1
Bayes (Unit 14): p(z∣x)=p(x∣z) p(z)/p(x)p(z\mid x)=p(x\mid z)\,p(z)/p(x). Take logs and rearrange: log⁡p(x)=log⁡p(x∣z)+log⁡p(z)−log⁡p(z∣x).\begin{aligned}\log p(x)&=\log p(x\mid z)\\ &\quad+\log p(z)\\ &\quad-\log p(z\mid x).\end{aligned} This holds for every single zz.
2
Add and subtract log⁡q(z)\log q(z), then average over z∼qz\sim q (the left side does not depend on zz): log⁡p(x)=Eqlog⁡p(x∣z)−Eqlog⁡qp(z)+Eqlog⁡qp(z∣x).\begin{aligned}\log p(x)&=\mathbb E_q\log p(x\mid z)\\ &\quad-\mathbb E_q\log\tfrac{q}{p(z)}\\ &\quad+\mathbb E_q\log\tfrac{q}{p(z\mid x)}.\end{aligned} The two averages of log-ratios are exactly the two KLs.
3
A KL is never negative, so log⁡p(x)≥\log p(x)\ge ELBO, with equality exactly when q=p(z∣x)q=p(z\mid x). ∎ Two-code toy, q=(0.9,0.1)q=(0.9,0.1): ELBO −0.9888-0.9888, gap 0.9ln⁡0.90.75+0.1ln⁡0.10.25≈0.07250.9\ln\frac{0.9}{0.75}+0.1\ln\frac{0.1}{0.25}\approx0.0725, total −0.9163-0.9163.
Prove it · the ELBO's rebuild term is the VAE's squared error

Claim. If the decoder says "the picture is dec⁡(z)\operatorname{dec}(z) plus bell-shaped pixel noise of spread ss", then log⁡p(x∣z)=−∥x−dec⁡(z)∥2/(2s2)+const\log p(x\mid z)=-\|x-\operatorname{dec}(z)\|^2/(2s^2)+\text{const} — so maximising the ELBO is minimising the VAE loss of §4.

1
Each of the nn pixels is N(dec⁡(z)i, s2)N(\operatorname{dec}(z)_i,\ s^2), independently. The log of their joint density is −∑i12ln⁡(2πs2)−∑i(xi−dec⁡(z)i)22s2.\begin{aligned}&-\sum_i\tfrac12\ln(2\pi s^2)\\ &-\sum_i\tfrac{(x_i-\operatorname{dec}(z)_i)^2}{2s^2}.\end{aligned} The same step that turned likelihood into least squares in Unit 14.
2
The first part does not depend on the model, so it drops out of any comparison. What is left is −∥x−dec⁡(z)∥2/(2s2)-\|x-\operatorname{dec}(z)\|^2/(2s^2): the squared error, with weight 1/(2s2)1/(2s^2). Flip the sign of the ELBO and you have "squared error + KL". ∎ Our toy used s=0.25s=0.25, so the rebuild weight is 1/(2×0.0625)=81/(2\times0.0625)=8 per unit of squared error. β\beta then weighs the KL against it.

In one sentence: The ELBO — rebuild well, stay near the prior — is a platform that always sits under the ceiling log⁡p(x)\log p(x); pushing it up either raises the ceiling or closes the gap, and at the true posterior the two touch.

7

Walking the latent map

Imagine this

Picture a huge map of a country where every village is a face. Villages next to each other hold faces that look alike. Walk north and the faces grow bigger; walk west and they start to smile. You can stop anywhere — even in a field between villages — and a face is waiting for you there too.

The question. Now that the map is full, how do we use it to make new faces — and what are its limits?

The VAE's map is called its latent space ("latent" means hidden: the code is never seen in the data). Three things become easy.

  1. Sampling. Draw z∼N(0,I)z\sim N(0,I) — the same cloud the KL pulled everything towards — and decode. Each draw is a new face. This is the sculptor of §1: fixed hands (the decoder), a random lump (zz).
  2. Morphing. Take the codes of two faces and walk in a straight line between them, decoding as you go: one face turns smoothly into the other.
  3. Directions mean something. Because similar faces sit near each other, a direction on the map becomes a property: "this way is bigger", "that way is happier". In big VAEs such directions are found for hair, glasses or age.

The honest limit. VAE pictures are blurry. The rebuild loss is a squared error, and when the decoder is unsure between two possible pictures — a mouth slightly up or slightly down — the squared error is smallest for their average. An average of two sharp mouths is one soft mouth. So wherever the code does not pin a detail down, the VAE paints a blur. Keep this in mind: it is the gap that diffusion (Act III) closes.

The map of facesThe whole code plane of the toy VAE (β = 1) from −3 to 3, drawn as a grid of the faces its decoder paints there. The pink rings are N(0,I)N(0,I)'s 1σ and 2σ. Drag the cursor anywhere: the big face on the right is decoded live.

Try: Drag the cursor upwards: the faces grow. Drag it from left to right: a big smile turns into a frown. Drag it to the far left edge, outside both rings: the decoder was hardly trained there, and it paints inverted blobs. Press draw 12 random for twelve new faces from N(0,I)N(0,I). Press morph A → B: the strip walks from a small smiling face to a big frowning one. Compare its middle frame with the pixel average of A and B — two faces laid on top of each other — which is not a face at all.

Why does this work?

Because of the overlapping clouds of §4. During training, every point near the centre was drawn from some face's cloud, and the decoder was asked to rebuild that face from it. Points between two clouds were trained on both faces, so the decoder learned to paint something between them. That is exactly what a smooth morph and a good random sample need: a decoder that was trained everywhere the prior puts its draws.

Two kinds of "in between", side by side.

pixel average 12(xA+xB)\tfrac12(x_A+x_B)decoded midpoint dec⁡(12(zA+zB))\operatorname{dec}\big(\tfrac12(z_A+z_B)\big)
what it doeslays the two pictures on top of each otherwalks halfway on the map, then draws
what you seetwo faint outlines, two mouths — a double exposureone face, middle-sized, with a middle smile
is it a face?noyes — the map only holds faces

Rule of thumb. To blend two things, blend their codes, not their pixels. Straight lines in the latent space become curved, sensible paths among real-looking pictures.

Trap

A straight line on the map is not a straight line in pixel space. The pixel-space straight line from A to B passes through double exposures that are not faces at all. The decoder bends the straight latent line into a curve that stays among faces. "Halfway" on the map means "halfway in meaning", not "the average of the pixels".

The realization

xnew=dec⁡(z),  z∼N(0,I)x(t)=dec⁡((1−t) zA+t zB)\begin{gathered}x_{\text{new}}=\operatorname{dec}(z),\ \ z\sim N(0,I)\\ x(t)=\operatorname{dec}\big((1-t)\,z_A+t\,z_B\big)\end{gathered}

A trained VAE is a map where every point is a picture: draw a point from the prior to create, walk a straight line to morph. Its weakness is blur — the squared-error rebuild paints the average wherever the code leaves a detail open.

Pause & predict

You decode codes far outside the rings, at z=(6,6)z=(6,6). What do you expect?

Pause & predict

A VAE decoder is unsure whether a mouth pixel should be 0 (dark) or 1 (bright), each equally likely. Under squared error, what value does it paint?

If you want the algebra · 1 proof, step by step
Prove it · squared error paints the average (where VAE blur comes from)

Claim. If the true value of a pixel is random, the single guess cc with the smallest average squared error E[(Y−c)2]\mathbb E[(Y-c)^2] is the average c=E[Y]c=\mathbb E[Y].

1
Expand: E[(Y−c)2]=E[Y2]−2c E[Y]+c2\mathbb E[(Y-c)^2]=\mathbb E[Y^2]-2c\,\mathbb E[Y]+c^2. This is a bowl in cc (Unit 9); its slope −2 E[Y]+2c-2\,\mathbb E[Y]+2c is zero at c=E[Y]c=\mathbb E[Y]. A parabola opening upwards has one bottom.
2
With YY equal to 0 or 1, each half the time, E[Y]=0.5\mathbb E[Y]=0.5: the best guess is a grey 0.5 with cost 0.250.25, while guessing 0 or 1 costs 0.50.5. ∎ A decoder that cannot tell whether the mouth curves up or down paints the average of both — a soft blur. Diffusion avoids this by never deciding everything at once.

In one sentence: A trained VAE is a map of faces you can walk — draw a point from the prior to create, walk a straight line to morph — but where the code leaves a detail open, its squared-error decoder paints the average, so its pictures are soft.

8

Forward: destroy a picture one small step at a time

Imagine this

Drop a single drop of blue ink into a glass of still water. At first it is a sharp little cloud with a clear shape. A second later it has spread a bit; a minute later it is a faint haze; after an hour the whole glass is an even pale blue, and nothing tells you what shape the drop once had.

Destroying is easy. Every moment the ink simply spreads a little more. Nobody has to plan it.

The question. The VAE drew a picture in one go, and it came out blurry. Diffusion takes the opposite road: it learns to undo destruction. But first we need the destruction itself. How do we turn a picture into pure static — in a way so simple that we know exactly what happened at every step?

A picture is a list of numbers (for our faces, 400 pixels, scaled to run from −1 to 1). We use the step of §2, over and over, with a small noise amount βt\beta_t at step tt:

xt=1−βt xt−1+βt εt,εt∼N(0,I).\begin{gathered}x_t=\sqrt{1-\beta_t}\,x_{t-1}+\sqrt{\beta_t}\,\varepsilon_t,\\ \varepsilon_t\sim N(0,I).\end{gathered}

Shrink the picture a little, add a little noise — the chai glass. Every pixel gets its own noise.

By hand, three steps. Take β=0.1\beta=0.1 at every step. The picture is shrunk by 0.9\sqrt{0.9} three times, and the three noises pile up. The two facts of §2 add them into one noise:

αˉ3=0.9×0.9×0.9=0.729x3=0.729 x0+1−0.729 ε≈0.8538 x0+0.5206 ε.\begin{aligned}\bar\alpha_3&=0.9\times0.9\times0.9=0.729\\ x_3&=\sqrt{0.729}\,x_0+\sqrt{1-0.729}\,\varepsilon\\ &\approx0.8538\,x_0+0.5206\,\varepsilon.\end{aligned}

This is the key shortcut. We never have to walk the steps one by one: to jump straight to step tt, multiply the "keep" factors together, αˉt=(1−β1)(1−β2)⋯(1−βt)\bar\alpha_t=(1-\beta_1)(1-\beta_2)\cdots(1-\beta_t), and draw one noise:

xt=αˉt x0+1−αˉt ε.x_t=\sqrt{\bar\alpha_t}\,x_0+\sqrt{1-\bar\alpha_t}\,\varepsilon.

It is the reparameterisation trick of §5 again: a formula of the picture and outside noise.

The real schedule. DDPM (Ho, Jain and Abbeel, 2020) uses T=1 000T=1\,000 steps, with βt\beta_t rising in a straight line from 0.0001 to 0.02. Then

αˉ100≈0.897  (SNR 8.71)αˉt<0.5  from step 260 onαˉ500≈0.07859  (SNR 0.0853)αˉ1000≈4.04×10−5.\begin{aligned}\bar\alpha_{100}&\approx0.897\ \ (\text{SNR }8.71)\\ \bar\alpha_t&<0.5\ \text{ from step }260\ \text{on}\\ \bar\alpha_{500}&\approx0.07859\ \ (\text{SNR }0.0853)\\ \bar\alpha_{1000}&\approx4.04\times10^{-5}.\end{aligned}

The signal-to-noise ratio αˉ/(1−αˉ)\bar\alpha/(1-\bar\alpha) compares the variance kept from the picture with the variance of the noise. At step 100 the picture is still 8.71 times louder than the noise. By step 500 the noise is about 12 times louder. At step 1 000 only 4.04×10−5≈0.0064\sqrt{4.04\times10^{-5}}\approx0.0064 of the picture survives: it is pure static, N(0,I)N(0,I), whatever you started from.

The ink drop spreadsLeft: one of our faces. Middle: 1 500 points drawn from the rangoli (the 2-D data of Act III, green). Both are noised to step tt by the one-jump formula, with the same fixed noise, so the picture is reproducible. Right: αˉt\bar\alpha_t (how much of the picture's variance is kept) and the signal-to-noise ratio, for two schedules.

Try: Drag t slowly from 0 to 1 000 and watch the face and the rangoli melt into the same grey static. Press t = 100: αˉ=0.897\bar\alpha=0.897, signal-to-noise 8.71 — the face is still easy to see, but the rangoli's fine pattern is already a blur: small details vanish first, big shapes last. t = 260: αˉ\bar\alpha has just dropped below 0.5. t = 500: 0.07859, you can barely guess the face. Switch to cosine: at t = 500 it keeps αˉ≈0.49\bar\alpha\approx0.49 — the picture fades more evenly, instead of being mostly destroyed in the first third.

100
Why does this work?

Because every step is §2's step, which keeps the total size fixed while swapping picture for noise. Independent noises simply add their variances, so a thousand small noises are exactly one big noise, and a thousand small shrinks are one big shrink αˉt\sqrt{\bar\alpha_t}. The destination does not depend on the picture at all: every picture ends in the same N(0,I)N(0,I). That fixed, easy destination is what will let us start the reverse journey from pure static.

Two schedules, side by side.

linear (DDPM, Ho et al., 2020)cosine (Nichol and Dhariwal, 2021)
recipeβt\beta_t rises in a straight line, 0.0001 → 0.02αˉt\bar\alpha_t follows a cosine curve from 1 to 0
αˉ\bar\alpha at t = 5000.07859about 0.49
how the picture fadesfast early: much of the late journey is already staticevenly across all the steps
good forthe original DDPM resultssmall pictures, where the linear one destroys detail too soon

Rule of thumb. The schedule only decides how fast the picture fades. Whatever it is, the one-jump formula holds with its own αˉt\bar\alpha_t — so you can always jump straight to any step.

Trap

No learning happens in the forward process. It is a fixed recipe with no weights: shrink, add noise, repeat. Everything a diffusion model learns is in the reverse direction, in the next sections. The forward process is only there to make training examples: a clean picture, a step tt, and the noise that was added.

The realization

xt=αˉt x0+1−αˉt εαˉt=∏s≤t(1−βs)\begin{gathered}x_t=\sqrt{\bar\alpha_t}\,x_0+\sqrt{1-\bar\alpha_t}\,\varepsilon\\ \bar\alpha_t=\prod_{s\le t}(1-\beta_s)\end{gathered}

A thousand small "shrink and add noise" steps are one big one. The picture survives with weight αˉt\sqrt{\bar\alpha_t}, the noise has weight 1−αˉt\sqrt{1-\bar\alpha_t}, and at the end every picture is the same pure static.

Pause & predict

Two steps with β=0.36\beta=0.36 each. Write x2x_2 as one jump from x0x_0.

Pause & predict

With the linear schedule, you forward-noise two very different pictures — a face and a cat — to t=1 000t=1\,000. How different are the two results?

Pause & predict

At step 100 of DDPM, αˉ=0.897\bar\alpha=0.897. Roughly how much louder is the picture than the noise, in variance?

If you want the algebra · 1 proof, step by step
Prove it · a thousand small noisings are one big one

Claim. If xt=1−βt xt−1+βt εtx_t=\sqrt{1-\beta_t}\,x_{t-1}+\sqrt{\beta_t}\,\varepsilon_t with fresh independent noise at every step, then xt=αˉt x0+1−αˉt εx_t=\sqrt{\bar\alpha_t}\,x_0+\sqrt{1-\bar\alpha_t}\,\varepsilon for one standard noise ε\varepsilon, where αˉt=∏s≤t(1−βs)\bar\alpha_t=\prod_{s\le t}(1-\beta_s).

1
True for t=1t=1: αˉ1=1−β1\bar\alpha_1=1-\beta_1. Suppose it holds for t−1t-1. Substitute: xt=αˉt x0+c ε′+βt εt,c=(1−βt)(1−αˉt−1).\begin{aligned}x_t&=\sqrt{\bar\alpha_t}\,x_0\\ &\quad+c\,\varepsilon'+\sqrt{\beta_t}\,\varepsilon_t,\\ c&=\sqrt{(1-\beta_t)(1-\bar\alpha_{t-1})}.\end{aligned} (1−βt)αˉt−1=αˉt(1-\beta_t)\bar\alpha_{t-1}=\bar\alpha_t by the definition of αˉ\bar\alpha. The last two terms are two independent noises.
2
Two independent bells add into one bell whose variance is the sum (§2): (1−βt)(1−αˉt−1)+βt=1−(1−βt)αˉt−1=1−αˉt.\begin{aligned}&(1-\beta_t)(1-\bar\alpha_{t-1})+\beta_t\\ &=1-(1-\beta_t)\bar\alpha_{t-1}\\ &=1-\bar\alpha_t.\end{aligned} So the noise part is 1−αˉt ε\sqrt{1-\bar\alpha_t}\,\varepsilon for a single standard ε\varepsilon. ∎ β=0.1\beta=0.1 three times: αˉ3=0.729\bar\alpha_3=0.729, x3=0.8538x0+0.5206εx_3=0.8538x_0+0.5206\varepsilon.

In one sentence: The forward process spreads the ink — shrink a little, add a little noise, a thousand times — and because the noises add up into one, any step can be reached in a single jump, xt=αˉtx0+1−αˉt εx_t=\sqrt{\bar\alpha_t}x_0+\sqrt{1-\bar\alpha_t}\,\varepsilon, ending in the same static for every picture.

9

The denoiser: guess the noise

Imagine this

An old photograph of your grandparents' wedding has faded and gathered dust. A restorer at a studio in Chandni Chowk looks at it for a long time and says: "This much of what you see is dust." He paints the dust out, and the wedding comes back.

He does not paint the picture from memory. He only has to be good at one thing: spotting the dust.

The question. The forward process is fixed. So what does a diffusion model actually learn?

It learns to be the restorer. A network εθ(xt,t)\varepsilon_\theta(x_t,t) looks at a noisy picture and the step number, and guesses the noise ε\varepsilon that was added. Training is a plain regression with squared error — the loss of Unit 10 and Unit 15:

  1. Take a real picture x0x_0 and a random step tt.
  2. Draw noise ε\varepsilon and make xt=αˉt x0+1−αˉt εx_t=\sqrt{\bar\alpha_t}\,x_0+\sqrt{1-\bar\alpha_t}\,\varepsilon in one jump (§8).
  3. Ask the network for its guess ε^=εθ(xt,t)\hat\varepsilon=\varepsilon_\theta(x_t,t), and pay ∥ε−ε^∥2\|\varepsilon-\hat\varepsilon\|^2.

That is all. No second network, no guessing game: the right answer — the noise — is known for every training example, because we added it ourselves. (Underneath, it is §6 again: Ho and colleagues showed that this plain squared error is an ELBO, like the VAE's, in which the noisy pictures play the part of the code — with the steps weighted a little differently. The bookkeeping just comes out very simple.)

Knowing the noise is knowing the picture. Solve the one-jump formula for x0x_0:

x^0=xt−1−αˉt ε^αˉt.\hat x_0=\frac{x_t-\sqrt{1-\bar\alpha_t}\,\hat\varepsilon}{\sqrt{\bar\alpha_t}}.

Paint out the dust, then turn the brightness back up. By hand, with one number: x0=2x_0=2, αˉ=0.64\bar\alpha=0.64 (so αˉ=0.8\sqrt{\bar\alpha}=0.8, 1−αˉ=0.6\sqrt{1-\bar\alpha}=0.6), and noise ε=0.5\varepsilon=0.5:

xt=0.8(2)+0.6(0.5)=1.9ε^=0.5:  x^0=1.9−0.6(0.5)0.8=2ε^=0.3:  x^0=1.9−0.6(0.3)0.8=2.15.\begin{aligned}x_t&=0.8(2)+0.6(0.5)=1.9\\ \hat\varepsilon=0.5:\ \ \hat x_0&=\frac{1.9-0.6(0.5)}{0.8}=2\\ \hat\varepsilon=0.3:\ \ \hat x_0&=\frac{1.9-0.6(0.3)}{0.8}=2.15.\end{aligned}

A perfect guess gives the picture back exactly. A guess that is 0.2 too small leaves some noise in, and the rescaling blows it up a little.

What network? For pictures, a U-Net (a network that squeezes the picture down and widens it back up, with shortcuts between matching sizes), or a transformer (Unit 18) that reads the picture as patches. Either way it also reads tt, so it knows how much dust to expect.

The restorerTop: one number. The green dot is the clean x0x_0, the grey dot the noisy xtx_t, the gold dot the restorer's answer x^0\hat x_0 from his noise guess; the red bar is the training loss (ε−ε^)2(\varepsilon-\hat\varepsilon)^2. Bottom: 300 noisy rangoli points (grey) and, for each, the best possible guess of its clean point (gold) — computed exactly from the true data, no network.

Try: With x0=2x_0=2, αˉ=0.64\bar\alpha=0.64, ε=0.5\varepsilon=0.5: set the guess ε^\hat\varepsilon to 0.5 and the gold dot lands on 2 with loss 0; set it to 0.3 and it lands on 2.15. Now push αˉ\bar\alpha down to 0.05 (very noisy): in the bottom panel every best guess crowds into a small blob near the centre — the average of the whole rangoli. Raise αˉ\bar\alpha to 0.95: the best guesses spread out and sit on the rangoli.

2
0.64
0.5
0.3
Why does this work?

Because squared error teaches averages (the drawer of §7). Many different clean pictures could have produced the same noisy xtx_t, and the network cannot know which one it was. So it learns the average noise over all of them — and, through the formula, the average clean picture. When the noise is small, only one clean picture fits, and the average is sharp. When the noise is huge, everything fits, and the best guess is the average of the whole dataset. Each guess is honest about how much it can know.

What should the network predict? Two choices, side by side.

the network predictsthe clean picture x^0\hat x_0the noise ε^\hat\varepsilon (DDPM)
loss∥x0−x^0∥2\|x_0-\hat x_0\|^2∥ε−ε^∥2\|\varepsilon-\hat\varepsilon\|^2
size of the targeta whole picture, every stepalways N(0,I)N(0,I): the same size at every step
convert to the otherε^=(xt−αˉ x^0)/1−αˉ\hat\varepsilon=(x_t-\sqrt{\bar\alpha}\,\hat x_0)/\sqrt{1-\bar\alpha}x^0=(xt−1−αˉ ε^)/αˉ\hat x_0=(x_t-\sqrt{1-\bar\alpha}\,\hat\varepsilon)/\sqrt{\bar\alpha}
in practiceworks; often weaker at low noisethe standard choice since DDPM

Rule of thumb. Predict the noise: the target always has the same size, which keeps training steady at every step. §10 adds a third choice, the score. Any of the three can be turned into the others with one line of algebra.

Trap

The network is not used to draw the final picture in one go. From a very noisy input its best guess x^0\hat x_0 is a blurry average — in the widget, a blob near the centre. That is why diffusion does not stop at the first guess. It uses the guess to take one small step back, looks again, guesses again, and sharpens the picture over many steps (§11).

The realization

min⁡θ E∥ε−εθ(xt, t)∥2xt=αˉt x0+1−αˉt εx^0=xt−1−αˉt ε^αˉt\begin{gathered}\min_\theta\ \mathbb E\big\|\varepsilon-\varepsilon_\theta(x_t,\ t)\big\|^2\\ x_t=\sqrt{\bar\alpha_t}\,x_0+\sqrt{1-\bar\alpha_t}\,\varepsilon\\ \hat x_0=\frac{x_t-\sqrt{1-\bar\alpha_t}\,\hat\varepsilon}{\sqrt{\bar\alpha_t}}\end{gathered}

A diffusion model is a restorer trained by squared error to spot the dust: noise a real picture by a known amount, and ask for the noise back. Knowing the noise is the same as knowing the clean picture — as well as it can be known from what is left.

Pause & predict

xt=1x_t=1, αˉ=0.36\bar\alpha=0.36 (so αˉ=0.6\sqrt{\bar\alpha}=0.6, 1−αˉ=0.8\sqrt{1-\bar\alpha}=0.8), and the restorer guesses ε^=0.5\hat\varepsilon=0.5. What is x^0\hat x_0?

Pause & predict

A perfect restorer sees pure static at t=1 000t=1\,000. What is its best guess x^0\hat x_0 of the clean picture?

If you want the algebra · 1 proof, step by step
Prove it · the best noise guess gives the best clean guess

Claim. Among all functions of xtx_t, the one with the smallest average ∥ε−ε^∥2\|\varepsilon-\hat\varepsilon\|^2 is ε^(xt)=E[ε∣xt]\hat\varepsilon(x_t)=\mathbb E[\varepsilon\mid x_t]; and then x^0=(xt−1−αˉ ε^)/αˉ\hat x_0=(x_t-\sqrt{1-\bar\alpha}\,\hat\varepsilon)/\sqrt{\bar\alpha} equals E[x0∣xt]\mathbb E[x_0\mid x_t], the average clean picture behind xtx_t.

1
Fix one xtx_t. The guess is a single number (or vector) cc, and the drawer of §7 says the cc with the smallest average squared error is the average: c=E[ε∣xt]c=\mathbb E[\varepsilon\mid x_t]. A network trained long enough on squared error learns these conditional averages (Unit 14's least squares, grown up).
2
Average the identity x0=(xt−1−αˉ ε)/αˉx_0=(x_t-\sqrt{1-\bar\alpha}\,\varepsilon)/\sqrt{\bar\alpha} over everything consistent with this xtx_t. The formula is a straight line in ε\varepsilon, so the average passes through: E[x0∣xt]=xt−1−αˉ E[ε∣xt]αˉ.\begin{aligned}&\mathbb E[x_0\mid x_t]\\ &=\frac{x_t-\sqrt{1-\bar\alpha}\,\mathbb E[\varepsilon\mid x_t]}{\sqrt{\bar\alpha}}.\end{aligned} ∎ So at huge noise, where every picture is consistent with xtx_t, the best clean guess is the dataset's average — the blob in the widget.

In one sentence: A diffusion model is a restorer who, shown a noisy picture and how noisy it is, guesses the dust by plain squared-error regression — and from the dust guess, x^0=(xt−1−αˉ ε^)/αˉ\hat x_0=(x_t-\sqrt{1-\bar\alpha}\,\hat\varepsilon)/\sqrt{\bar\alpha} is the best clean picture that can be known.

10

The score: a compass pointing at the data

Imagine this

You are lost in fog in the hills above a few villages. You hold a strange compass: it always points towards the most likely place to find people. Far out in the fog it points vaguely towards the middle of all the villages. As you come closer, it starts to choose: this village, not that one. Right at the edge of a village it points sharply to its centre.

The question. The restorer's noise guess feels like a trick for one picture. Is there a single field — an arrow at every point of space — that tells us which way real data lies?

There is. It is called the score: the slope (gradient, Unit 6) of the log of the density, ∇xlog⁡p(x)\nabla_x\log p(x). At every point it is an arrow pointing uphill — towards where data is more likely.

One village, by hand. For a bell curve N(μ,σ2)N(\mu,\sigma^2), log⁡p(x)=−(x−μ)22σ2+const\log p(x)=-\frac{(x-\mu)^2}{2\sigma^2}+\text{const}, so its slope is

score(x)=−x−μσ2.\text{score}(x)=-\frac{x-\mu}{\sigma^2}.

With μ=2\mu=2 and σ2=0.25\sigma^2=0.25: at x=1x=1 the score is −(1−2)/0.25=+4-(1-2)/0.25=+4 (go right, towards 2); at x=3x=3 it is −4-4 (go left). The farther away, the stronger the pull; at the centre, 0.

The noise guess is the score in disguise. Given one clean x0x_0, the noisy xtx_t is a bell curve with centre αˉ x0\sqrt{\bar\alpha}\,x_0 and variance 1−αˉ1-\bar\alpha. Its score is −(xt−αˉx0)/(1−αˉ)=−ε/1−αˉ-(x_t-\sqrt{\bar\alpha}x_0)/(1-\bar\alpha)=-\varepsilon/\sqrt{1-\bar\alpha}. So

score=−ε^1−αˉ.\text{score}=-\frac{\hat\varepsilon}{\sqrt{1-\bar\alpha}}.

Check it on §9's numbers (x0=2x_0=2, αˉ=0.64\bar\alpha=0.64, xt=1.9x_t=1.9): from the bell curve, −(1.9−1.6)/0.36≈−0.8333-(1.9-1.6)/0.36\approx-0.8333; from the noise, −0.5/0.6≈−0.8333-0.5/0.6\approx-0.8333. The same arrow, both ways. A trained restorer is a compass.

Two villages. Now the data is two bumps: half the points near −2-2, half near +2+2, each with variance 0.01. Noise it to αˉ=0.64\bar\alpha=0.64: the bumps move to ±0.8×2=±1.6\pm0.8\times2=\pm1.6, and each widens to variance 0.64(0.01)+0.36=0.36640.64(0.01)+0.36=0.3664. At x=0.5x=0.5, how much does each village "claim" the point? Compare the two bells (the responsibilities, as in Unit 14's Bayes):

claims∝e−(0.5+1.6)2/(2×0.3664), e−(0.5−1.6)2/(2×0.3664)=(0.0125, 0.9875).\begin{aligned}\text{claims}&\propto e^{-(0.5+1.6)^2/(2\times0.3664)},\\ &\quad\ e^{-(0.5-1.6)^2/(2\times0.3664)}\\ &=(0.0125,\ 0.9875).\end{aligned}

The score is the claims times each village's own pull:

0.0125⋅−(0.5+1.6)0.3664+0.9875⋅−(0.5−1.6)0.3664≈2.8927.\begin{aligned}&0.0125\cdot\frac{-(0.5+1.6)}{0.3664}\\ &+0.9875\cdot\frac{-(0.5-1.6)}{0.3664}\approx2.8927.\end{aligned}

A strong arrow to the right: the compass has picked the nearer village.

A compass between two villagesTop: the density of the noisy data (green); the two shaded bells are the two villages' shares. Bottom: the score at every point (gold). Drag the gold marker: its arrow shows the compass there.

Try: In two villages at αˉ=0.64\bar\alpha=0.64, drag the marker to 0.5: the claims read (0.0125, 0.9875) and the score 2.8927. Now slide αˉ\bar\alpha down to 0.05: the two bells merge into one soft hill, and the compass everywhere just points to the middle. Slide it up to 0.99: two sharp villages, and a steep cliff in the score between them — the compass flips from "go left" to "go right" at 0. Switch to one village and drag to 1 and 3: +4 and −4.

0.64
0.5

In two dimensions. The rangoli is 55 small villages. The same rule holds: at every point, the score is the claims of the villages times their pulls — and we can compute it exactly. Below, the height of the landscape is log⁡p\log p of the noisy rangoli, and the gold arrows running over it are the compass. In this widget, and in all of Act III, the trained network is replaced by this exact answer, so every arrow is true. A real model learns an approximation of this field from examples.

The compass field over the rangoliThe landscape is log⁡pt(x)\log p_t(x) of the noisy rangoli (the lowest 9 units are cut flat, so the floor is "very unlikely"). Each small gold arrow (pale gold on the dark page) lies on the landscape and points along the score — always uphill; its length grows with the strength of the pull, up to a limit. The big arrow with the “compass” label is the compass at the probe.

Try: Start at t = 600: one smooth hill, and every arrow points to the middle. Slide down to t = 300, then t = 100: still one hill, but its top flattens into a wide plateau — the outer ring of lamps is beginning to pull. At t = 60 the plateau breaks up into rings and petals, and some arrows turn outwards: the compass starts to choose. At t = 30 the landscape is 55 sharp peaks and each arrow points to its own nearest lamp or petal. Press the probe buttons to read the compass exactly — for example between two lamps.

drag the picture to orbit

300
probe
Why does this work?

Because of one small miracle, called Tweedie's formula: take one step along the score, of size 1−αˉ1-\bar\alpha, and you land exactly on the restorer's best average guess, scaled: xt+(1−αˉ) score=αˉ x^0x_t+(1-\bar\alpha)\,\text{score}=\sqrt{\bar\alpha}\,\hat x_0. So the arrow points from where you are to the average of the clean pictures that could have made this noisy one. Far away, that average is the centre of everything. Close to one village, it is that village. The compass is just the restorer's guess, turned into a direction.

Three ways to say the same thing, side by side. Any one of them can be computed from the others.

the noise guess ε^\hat\varepsilonthe clean guess x^0\hat x_0the score
answers"how much of this is dust?""what was under the dust?""which way is more likely?"
from ε^\hat\varepsilon—(xt−1−αˉ ε^)/αˉ(x_t-\sqrt{1-\bar\alpha}\,\hat\varepsilon)/\sqrt{\bar\alpha}−ε^/1−αˉ-\hat\varepsilon/\sqrt{1-\bar\alpha}
picturethe dust layerthe restored photoa compass needle
who uses itDDPM training (§9)DDIM's jump (§12)score models, Langevin (§11)

Rule of thumb. Train the noise, think in scores. When you picture a diffusion model, picture a field of arrows that sharpens as the noise goes down.

Trap

The score is not the probability. It points uphill, but it says nothing directly about how high you are. The compass reads 0 at the very top of a village — and also exactly halfway between two equal villages, where the pulls cancel. A zero score means "flat", not "likely".

The realization

∇xlog⁡pt(x)=∑krk(x) αˉ μk−xvscore=−ε^1−αˉ\begin{gathered}\nabla_x\log p_t(x)\\ =\sum_k r_k(x)\,\frac{\sqrt{\bar\alpha}\,\mu_k-x}{v}\\ \text{score}=-\frac{\hat\varepsilon}{\sqrt{1-\bar\alpha}}\end{gathered}

The score is a compass at every point, pointing towards more likely data. For a mixture it is each village's pull, weighted by how strongly that village claims the point. A noise predictor is a compass: divide its guess by −1−αˉ-\sqrt{1-\bar\alpha}.

Pause & predict

Two equal villages at ±1.6\pm1.6 (after noising), and you stand exactly at x=0x=0. What does the compass read?

Pause & predict

You noise the two-village data much more, to αˉ=0.05\bar\alpha=0.05. At x=0.5x=0.5, what happens to the compass compared with αˉ=0.64\bar\alpha=0.64?

Pause & predict

A trained model sees xtx_t at αˉ=0.91\bar\alpha=0.91 and predicts ε^=0.6\hat\varepsilon=0.6. What is its score there?

If you want the algebra · 2 proofs, step by step
Prove it · the noise guess is the score

Claim. For the noised data ptp_t, the score is ∇log⁡pt(xt)=−E[ε∣xt]/1−αˉ\nabla\log p_t(x_t)=-\mathbb E[\varepsilon\mid x_t]/\sqrt{1-\bar\alpha}. (For one known x0x_0 this is just the score of the bell curve N(αˉx0, 1−αˉ)N(\sqrt{\bar\alpha}x_0,\ 1-\bar\alpha).)

1
For one clean x0x_0: log⁡p(xt∣x0)=−∥xt−αˉx0∥22(1−αˉ)+const\log p(x_t\mid x_0)=-\frac{\|x_t-\sqrt{\bar\alpha}x_0\|^2}{2(1-\bar\alpha)}+\text{const}, whose slope is −(xt−αˉx0)/(1−αˉ)=−ε/1−αˉ-(x_t-\sqrt{\bar\alpha}x_0)/(1-\bar\alpha)=-\varepsilon/\sqrt{1-\bar\alpha}. xt−αˉx0=1−αˉ εx_t-\sqrt{\bar\alpha}x_0=\sqrt{1-\bar\alpha}\,\varepsilon by the one-jump formula.
2
For the whole data, pt(xt)=∑p(x0) p(xt∣x0)p_t(x_t)=\sum p(x_0)\,p(x_t\mid x_0). The slope of a log of a sum is a weighted average of the separate slopes, weighted by how much each x0x_0 explains xtx_t — its posterior: ∇log⁡pt=Ex0∣xt[−ε1−αˉ]=−E[ε∣xt]1−αˉ.\begin{aligned}\nabla\log p_t&=\mathbb E_{x_0\mid x_t}\Big[-\tfrac{\varepsilon}{\sqrt{1-\bar\alpha}}\Big]\\ &=-\frac{\mathbb E[\varepsilon\mid x_t]}{\sqrt{1-\bar\alpha}}.\end{aligned} ∎ ∇log⁡∑kfk=∑kfk∑jfj∇log⁡fk\nabla\log\sum_k f_k=\sum_k\frac{f_k}{\sum_jf_j}\nabla\log f_k. With §9: xt+(1−αˉ)∇log⁡pt=αˉ x^0x_t+(1-\bar\alpha)\nabla\log p_t=\sqrt{\bar\alpha}\,\hat x_0 — Tweedie's formula.
Prove it · the compass of a mixture of villages

Claim. For equal-weight bells N(mk, vI)N(m_k,\ vI) (the noised rangoli: mk=αˉμkm_k=\sqrt{\bar\alpha}\mu_k, v=αˉs2+1−αˉv=\bar\alpha s^2+1-\bar\alpha), the score is ∑krk(x) (mk−x)/v\sum_kr_k(x)\,(m_k-x)/v, with claims rk∝e−∥x−mk∥2/(2v)r_k\propto e^{-\|x-m_k\|^2/(2v)}.

1
p(x)=1K∑kfk(x)p(x)=\frac1K\sum_k f_k(x) with fkf_k the bells. Each ∇log⁡fk=(mk−x)/v\nabla\log f_k=(m_k-x)/v (the one-village formula). Adding noise to a small bell keeps it a bell: its centre shrinks by αˉ\sqrt{\bar\alpha}, its variance becomes αˉs2+(1−αˉ)\bar\alpha s^2+(1-\bar\alpha) (§2).
2
The log-of-a-sum rule of the previous drawer gives weights rk=fk/∑jfjr_k=f_k/\sum_jf_j; the common factors of the bells cancel, leaving rk∝e−∥x−mk∥2/(2v)r_k\propto e^{-\|x-m_k\|^2/(2v)}. ∎ Two villages at ±1.6\pm1.6, v=0.3664v=0.3664, x=0.5x=0.5: r=(0.0125, 0.9875)r=(0.0125,\ 0.9875), score ≈2.8927\approx2.8927. Since every vv is the same, the score is (mˉ(x)−x)/v(\bar m(x)-x)/v: from xx to the claim-weighted average of the villages.

In one sentence: The score ∇log⁡p\nabla\log p is a compass pointing towards more likely data — fuzzy and central in thick fog, sharp and local near a village — and a noise predictor is that compass in disguise: score=−ε^/1−αˉ\text{score}=-\hat\varepsilon/\sqrt{1-\bar\alpha}.

11

Walking back from static

Imagine this

Film the ink drop spreading in the glass, and play the film backwards. The even haze gathers, a little at a time, into a faint cloud, then a sharper one, until the single drop hangs there again, with its shape.

Played backwards, every small moment looks like "the ink moves a little towards where it is thicker". That is all the reverse film is.

The question. We have a compass that works at every noise level. How do we use it to turn pure static into a picture?

Start from pure static, xT∼N(0,I)x_T\sim N(0,I), and repeat for t=T, T−1, …, 1t=T,\ T-1,\ \dots,\ 1:

  1. Ask the restorer for the noise, ε^=εθ(xt,t)\hat\varepsilon=\varepsilon_\theta(x_t,t) — the compass.
  2. Step a little uphill: remove a small part of the guessed noise and undo one step's shrink.
  3. Add a little fresh noise, of the right size for this step.

DDPM's step says exactly how much of each:

xt−1= 1αt(xt−βt1−αˉt ε^)+σt z,z∼N(0,1),\begin{aligned}x_{t-1}=\ &\frac{1}{\sqrt{\alpha_t}}\Big(x_t-\frac{\beta_t}{\sqrt{1-\bar\alpha_t}}\,\hat\varepsilon\Big)\\ &+\sigma_t\,z,\qquad z\sim N(0,1),\end{aligned}

with αt=1−βt\alpha_t=1-\beta_t and σt=βt\sigma_t=\sqrt{\beta_t}. Read it aloud. βt1−αˉtε^\frac{\beta_t}{\sqrt{1-\bar\alpha_t}}\hat\varepsilon: only the share of the guessed noise that this one step added. 1αt\frac1{\sqrt{\alpha_t}}: undo this step's shrink. σtz\sigma_tz: a fresh jiggle.

By hand. βt=0.1\beta_t=0.1 (so αt=0.9\alpha_t=0.9), αˉt=0.729\bar\alpha_t=0.729, xt=1.2x_t=1.2, ε^=0.5\hat\varepsilon=0.5, and the fresh draw is z=−0.3z=-0.3:

mean=10.9(1.2−0.10.271(0.5))≈1.1637σt=0.1≈0.3162xt−1=1.1637+0.3162(−0.3)≈1.0688.\begin{aligned}\text{mean}&=\tfrac{1}{\sqrt{0.9}}\Big(1.2-\tfrac{0.1}{\sqrt{0.271}}(0.5)\Big)\\ &\approx1.1637\\ \sigma_t&=\sqrt{0.1}\approx0.3162\\ x_{t-1}&=1.1637+0.3162(-0.3)\\ &\approx1.0688.\end{aligned}

You have met this walker before. Write ε^\hat\varepsilon as the score (§10) and the step has the same shape as Langevin dynamics — a small step along the score, plus a jiggle:

x←x+η ∇log⁡p(x)+2η z.x\leftarrow x+\eta\,\nabla\log p(x)+\sqrt{2\eta}\,z.

For p=N(0,1)p=N(0,1) the score is −x-x. From x=3x=3 with η=0.1\eta=0.1 and no jiggle (z=0z=0): x←3+0.1(−3)=2.7x\leftarrow3+0.1(-3)=2.7. That is Unit 9's gradient descent walker, walking downhill on the landscape −log⁡p-\log p — with a jiggle at every step (Unit 9's noise as a friend), so that the walkers spread over the whole distribution instead of all piling onto its highest point.

The ink drop, filmed backwards3 000 points start as pure static at the top (noise level t = 1 000) and fall, one DDPM step at a time, to the floor (t = 0), where the rangoli's 55 parts are marked by faint rings. Height is the step. A few points leave trails. Every step uses the exact compass — no network.

Try: Press ▶ walk back with 100 steps: the static drifts, gathers, and lands on the rangoli — about 96% of the points on the shape, all 55 parts used. Switch fresh noise off and walk again: every point piles onto the centre dot — 1 part of 55. Put the noise back and choose 10 steps: less than half land on the shape. Drag scrub to replay any moment.

drag the picture to orbit

steps
0
Why does this work?

Because each forward step is tiny. When a step adds only a little noise, undoing it is almost a bell curve too — its centre given by the compass, its spread σt\sigma_t. (This is Unit 8's Taylor idea: over a small enough step, everything looks simple.) So a thousand small, simple reverse steps undo a thousand small forward steps. And the fresh noise matters: the reverse film must end with the right spread of pictures, and a compass alone only knows the direction of more likely data.

With and without the jiggle, side by side. These are the widget's own counts, 3 000 points, 100 steps, the same starting static.

DDPM, fresh noise onfresh noise off (only the "mean" step)Langevin (a fixed landscape)
each stepcompass step + σtz\sigma_tzcompass step onlyη⋅\eta\cdotscore +2η z+\sqrt{2\eta}\,z
where the points endspread over the whole rangoliall on the centre dotspread over pp, if run long enough
parts of the rangoli used55 of 551 of 55—
noise levelwalks down from 1 000 to 0walks down from 1 000 to 0one fixed level

Rule of thumb. Keep the jiggle. The compass tells each walker where "more likely" is; the jiggle keeps the walkers from all agreeing. Want a sampler without randomness? Use DDIM (§12), which is built to be deterministic — not DDPM with the noise switched off.

Trap

Removing the added noise zz does not give "cleaner" samples. It gives less varied ones. Without the jiggle, the early steps pull every walker towards the middle of everything, and they all end in the same place — here, all 3 000 points on the single centre dot of the rangoli. The randomness is not a flaw in the sampler; it is what makes it a sampler.

The realization

xt−1= 1αt(xt−βt1−αˉt ε^)+βt z\begin{aligned}x_{t-1}=\ &\frac{1}{\sqrt{\alpha_t}}\Big(x_t-\frac{\beta_t}{\sqrt{1-\bar\alpha_t}}\,\hat\varepsilon\Big)\\ &+\sqrt{\beta_t}\,z\end{aligned}

Generation is the ink film played backwards: start from static, and at every step move a little along the compass and add a little fresh noise. It is gradient descent on −log⁡p-\log p with a jiggle, walked down through the noise levels from very blurry to sharp.

Pause & predict

In the worked step, the fresh draw is z=+0.3z=+0.3 instead of −0.3-0.3. What is xt−1x_{t-1}?

Pause & predict

You run the reverse walk with no fresh noise. What do the finished samples look like?

Pause & predict

One Langevin step for p=N(0,1)p=N(0,1), from x=−2x=-2, with η=0.25\eta=0.25 and jiggle z=0.4z=0.4. Where do you land?

If you want the algebra · 2 proofs, step by step
Prove it · where DDPM's step comes from

Claim. If we knew x0x_0, the step back from xtx_t would be a bell curve with centre μ~=αˉt−1βt1−αˉtx0+αt(1−αˉt−1)1−αˉtxt\tilde\mu=\frac{\sqrt{\bar\alpha_{t-1}}\beta_t}{1-\bar\alpha_t}x_0+\frac{\sqrt{\alpha_t}(1-\bar\alpha_{t-1})}{1-\bar\alpha_t}x_t. Putting in x^0\hat x_0 from ε^\hat\varepsilon gives exactly DDPM's mean 1αt(xt−βt1−αˉtε^)\frac1{\sqrt{\alpha_t}}\big(x_t-\frac{\beta_t}{\sqrt{1-\bar\alpha_t}}\hat\varepsilon\big).

1
Bayes: p(xt−1∣xt,x0)∝p(xt∣xt−1) p(xt−1∣x0)p(x_{t-1}\mid x_t,x_0)\propto p(x_t\mid x_{t-1})\,p(x_{t-1}\mid x_0), a product of two bells in xt−1x_{t-1} — itself a bell. Its centre is the precision-weighted average of the two "votes" xt/αtx_t/\sqrt{\alpha_t} (weight αt/βt\alpha_t/\beta_t) and αˉt−1x0\sqrt{\bar\alpha_{t-1}}x_0 (weight 1/(1−αˉt−1)1/(1-\bar\alpha_{t-1})); simplifying with αtαˉt−1=αˉt\alpha_t\bar\alpha_{t-1}=\bar\alpha_t gives μ~\tilde\mu above. Multiplying bells adds their precisions (Unit 14).
2
Substitute x0=(xt−1−αˉt ε^)/αˉtx_0=\big(x_t-\sqrt{1-\bar\alpha_t}\,\hat\varepsilon\big)/\sqrt{\bar\alpha_t}. The xtx_t terms collect to xt/αtx_t/\sqrt{\alpha_t} and the ε^\hat\varepsilon term to −βtαt1−αˉtε^-\frac{\beta_t}{\sqrt{\alpha_t}\sqrt{1-\bar\alpha_t}}\hat\varepsilon. ∎ The spread of that bell is β~t=1−αˉt−11−αˉtβt\tilde\beta_t=\frac{1-\bar\alpha_{t-1}}{1-\bar\alpha_t}\beta_t; DDPM found σt2=βt\sigma_t^2=\beta_t works as well, and it is the choice used here.
Prove it · Langevin keeps the right distribution

Claim (for a bell). For p=N(0,1)p=N(0,1), the Langevin step x′=x+η(−x)+2η zx'=x+\eta(-x)+\sqrt{2\eta}\,z maps N(0,v)N(0,v) to N(0,(1−η)2v+2η)N\big(0,(1-\eta)^2v+2\eta\big), whose only fixed point for small η\eta is v≈1v\approx1 — the target itself.

1
x′=(1−η)x+2η zx'=(1-\eta)x+\sqrt{2\eta}\,z: the two facts of §2 give variance (1−η)2v+2η(1-\eta)^2v+2\eta. A scaled bell plus an independent bell.
2
Set v′=vv'=v: v(1−(1−η)2)=2ηv\big(1-(1-\eta)^2\big)=2\eta, so v=2η2η−η2=22−η≈1v=\frac{2\eta}{2\eta-\eta^2}=\frac{2}{2-\eta}\approx1 for small η\eta. ∎ Without the jiggle (z=0z=0) the variance shrinks by (1−η)2(1-\eta)^2 every step and every walker ends at 0 — the collapse of the widget. With η=0.1\eta=0.1 from x=3x=3: 3−0.3=2.73-0.3=2.7.

In one sentence: To create, play the ink film backwards — start from static, and a thousand times move a little along the compass and add a little fresh noise — which is Unit 9's downhill walker on −log⁡p-\log p, with the jiggle that keeps every walker from ending in the same place.

12

Faster: DDIM and the smooth path

Imagine this

You are coming down a long staircase in the dark, one step at a time, holding the rail. Then someone switches on the light. Now you can see the landing far below, and you can take the stairs three or four at a time — you know where you are heading.

The question. DDPM needs a thousand steps, and every step runs the whole network once. Can we reach the picture in far fewer steps?

DDIM (Song, Meng and Ermon, 2021) takes big, deterministic jumps. At every visit it does two things with the same noise guess:

  1. Look at the landing: estimate the clean picture, x^0=(xt−1−αˉt ε^)/αˉt\hat x_0=(x_t-\sqrt{1-\bar\alpha_t}\,\hat\varepsilon)/\sqrt{\bar\alpha_t} (§9).
  2. Jump straight to a much lower noise level ss, re-noising the landing with that same ε^\hat\varepsilon:

xs=αˉs x^0+1−αˉs ε^.x_s=\sqrt{\bar\alpha_s}\,\hat x_0+\sqrt{1-\bar\alpha_s}\,\hat\varepsilon.

By hand. xt=1.9x_t=1.9, αˉt=0.64\bar\alpha_t=0.64, ε^=0.5\hat\varepsilon=0.5: the landing is x^0=2\hat x_0=2 (as in §9). Jump to αˉs=0.9\bar\alpha_s=0.9:

xs=0.9(2)+0.1(0.5)≈2.0555.x_s=\sqrt{0.9}(2)+\sqrt{0.1}(0.5)\approx2.0555.

No fresh noise is drawn. So the walk is deterministic: the same starting static always gives the same picture. And because it never throws a random jiggle in, the path is smooth, and it can be walked with big strides. (In the limit of tiny steps it follows an ordinary differential equation, the probability-flow ODE: a smooth river that carries every point of the static to a picture.) Song and colleagues report that 50 DDIM steps give pictures close to those of the full 1 000-step DDPM.

A staircase and a jumpThe same 8 starting points walked back with DDPM (left) and DDIM (right), over the faint rangoli. Each path goes from its start (grey) to its landing (green). Below each panel: how many of 400 walkers land on the shape.

Try: With 50 steps, press again, same starts a few times: the DDPM paths jitter and land somewhere new every time; the DDIM paths do not move at all. Slide the steps down to 10: both land off the shape more often — fewer steps are not free. Slide up to 100: DDIM puts about 95% of its walkers on the shape.

50
Why does this work?

Because the restorer's guess already contains a full picture, x^0\hat x_0. DDPM uses only a sliver of it per step and relies on fresh noise to keep the right spread. DDIM instead keeps the noise it already has — the same ε^\hat\varepsilon — and re-mixes it with the landing in exactly the proportions the forward process would have at level ss. So after every jump the point looks like a proper sample of level ss, and the next compass reading is trustworthy even after a big stride.

DDPM and DDIM, side by side. The last row is the widget's own count: 400 walkers on our rangoli.

DDPM (§11)DDIM
each stepsmall compass step + fresh noiseestimate x^0\hat x_0, jump, re-noise with the same ε^\hat\varepsilon
randomnessat every steponly the starting static
same start twicetwo different picturesthe same picture
typical steps1 00025–100
same network?yesyes — only the sampler changes
our rangoli, 400 walkers50 steps: about 88% on the shape; 100 steps: about 95%50 steps: 92.5%; 100 steps: about 95%

Rule of thumb. Train once, sample however you like. DDIM with 50–100 steps is the usual fast choice; add back some randomness when you want more variety between runs.

Trap

Fewer steps are not free. Each jump trusts one compass reading over a long distance; if the stride is too long, the reading is out of date by the time you land. With 10 steps, fewer than half of our walkers land on the rangoli, with DDIM as well as with DDPM.

The realization

xs= αˉs xt−1−αˉt ε^αˉt+1−αˉs ε^\begin{aligned}x_s=\ &\sqrt{\bar\alpha_s}\,\frac{x_t-\sqrt{1-\bar\alpha_t}\,\hat\varepsilon}{\sqrt{\bar\alpha_t}}\\ &+\sqrt{1-\bar\alpha_s}\,\hat\varepsilon\end{aligned}

DDIM looks at the landing and jumps: estimate the clean picture, then re-noise it with the same noise guess to a much lower level. No fresh randomness, so the path is smooth, the same start gives the same picture, and a few dozen strides can do the work of a thousand small steps.

Pause & predict

A DDIM jump from xt=1.9x_t=1.9, αˉt=0.64\bar\alpha_t=0.64, ε^=0.5\hat\varepsilon=0.5, all the way to αˉs=1\bar\alpha_s=1 (no noise at all). Where does it land?

Pause & predict

You run DDIM twice from the same starting static, with the same trained network. What do you get?

If you want the algebra · 1 proof, step by step
Prove it · a DDIM jump lands at the right noise level

Claim. If the network is exact for a single clean picture (so ε^=ε\hat\varepsilon=\varepsilon and x^0=x0\hat x_0=x_0), then the DDIM jump xs=αˉsx^0+1−αˉsε^x_s=\sqrt{\bar\alpha_s}\hat x_0+\sqrt{1-\bar\alpha_s}\hat\varepsilon gives exactly αˉs x0+1−αˉs ε\sqrt{\bar\alpha_s}\,x_0+\sqrt{1-\bar\alpha_s}\,\varepsilon — a proper level-ss sample of the forward process, with the same noise.

1
Substitute: x^0=(αˉtx0+1−αˉtε−1−αˉtε)/αˉt=x0\hat x_0=\big(\sqrt{\bar\alpha_t}x_0+\sqrt{1-\bar\alpha_t}\varepsilon-\sqrt{1-\bar\alpha_t}\varepsilon\big)/\sqrt{\bar\alpha_t}=x_0. The guessed noise removes exactly the noise that was added.
2
Then xs=αˉsx0+1−αˉsεx_s=\sqrt{\bar\alpha_s}x_0+\sqrt{1-\bar\alpha_s}\varepsilon, which is the one-jump formula of §8 at level ss. Walking from tt to ss moved along a fixed line in the (x0,ε)(x_0,\varepsilon) plane: no randomness was added. ∎ With many possible pictures the guesses are averages, so each jump is only approximately right — which is why strides that are too long drift off the data.

In one sentence: DDIM switches on the light on the staircase — at each visit it estimates the clean picture and jumps far down with the same noise guess — so the path is smooth, the same start always gives the same picture, and a few dozen strides replace a thousand steps.

13

Steering with words: guidance and latent diffusion

Imagine this

You are driving to a friend's house with the map app on. At a busy junction the voice says: "Keep left." Your own habit — "most people go straight here" — pulls you one way; the voice pulls you another. A good voice even says: "More to the left than you think." It takes the difference between where you would go and where you should go, and makes it bigger.

The question. A diffusion model draws something that looks real. How do we make it draw what we ask for — "a cat on a scooter" — and how do big models afford to do it on huge pictures?

Step 1: give the restorer the request. Train the noise guesser with the text as an extra input: ε^(xt,t,c)\hat\varepsilon(x_t,t,c), where cc is the prompt. A transformer (Unit 18) reads the text into vectors, and the picture network looks at them with cross-attention: every patch of the picture asks the words "which of you is about me?". Sometimes, during training, the prompt is dropped on purpose, so the same network also learns the unconditional guess ε^(xt,t)\hat\varepsilon(x_t,t).

Step 2: go past the request. Classifier-free guidance (Ho and Salimans, 2022) mixes the two guesses with a weight ww:

ε~= εuncond+w (εcond−εuncond).\begin{aligned}\tilde\varepsilon=\ &\varepsilon_{\text{uncond}}\\ &+w\,\big(\varepsilon_{\text{cond}}-\varepsilon_{\text{uncond}}\big).\end{aligned}

By hand: εuncond=0.2\varepsilon_{\text{uncond}}=0.2, εcond=0.5\varepsilon_{\text{cond}}=0.5, w=3w=3 gives 0.2+3(0.5−0.2)=1.10.2+3(0.5-0.2)=1.1. The difference 0.3 is "what the request adds"; guidance adds it three times. w=0w=0 ignores the prompt, w=1w=1 follows it plainly, and w>1w>1 says "more to the left than you think".

On our rangoli we can do it exactly: the "prompt" is a class — the petals or the lamps — and the conditional guess is the exact noise guess of that class's parts alone. So guidance, too, is computed with no network at all.

The sat-nav voice1 200 walkers go back from static by the DDPM steps of §11, using the guided noise ε~\tilde\varepsilon with the exact guesses. Each landing is coloured by the part it lands on: petals violet, lamps cyan, off the shape grey. Right: how many landed on each part of the chosen class, from the centre outwards.

Try: Choose lamps and set w = 0: the prompt is ignored and about half the walkers land on lamps. w = 1: about 97% on lamps, spread evenly over all 30. w = 3, then w = 5: still lamps — but the inner ring, the lamps that sit closest to the petals, empties out, and the walkers crowd the outer ring. Past 1, guidance buys "the most lamp-like lamps" and pays in variety.

1
Why does this work?

Turn the guesses into scores (§10). The difference εcond−εuncond\varepsilon_{\text{cond}}-\varepsilon_{\text{uncond}} is, up to a factor, the slope of log⁡p(c∣x)\log p(c\mid x) — "how much more does this picture look like the request?", by Bayes (Unit 14). Guidance with weight ww samples as if that vote were raised to the power ww. A louder vote pushes the walkers to the places that are most typical of the class and least like anything else — sharper and more faithful, but less varied.

Step 3: diffuse in a small space. A 512 × 512 colour picture is 512×512×3=786 432512\times512\times3=786\,432 numbers, and a diffusion model must run a big network on all of them at every step. Latent diffusion (Rombach and colleagues, 2022 — the idea behind Stable Diffusion) first trains a VAE-like autoencoder (§3–§4) that squeezes the picture into a latent of 64×64×4=16 38464\times64\times4=16\,384 numbers — 48 times fewer — and runs the whole diffusion there. At the end the decoder turns the finished latent into the full picture. Act II and Act III join: the VAE's map becomes the place where diffusion walks.

The steering choices, side by side.

ww013 to 7 (common for pictures)
what it samplesanything, ignoring the promptthe prompt's distribution, plainlythe most typical pictures of the prompt
faithful to the promptnoyesvery
varietymostthe prompt's ownless; too high looks over-cooked

Rule of thumb. Guidance is a dial between "varied" and "on-message". Latent diffusion is how the dial stays affordable: squeeze with a VAE, diffuse the code, decode once at the end.

Trap

w=1w=1 is plain conditional sampling — no guidance at all. "Guidance" means w>1w>1: the model is pushed beyond its own conditional answer, away from the generic one. The widget shows it: at w=1w=1 every lamp gets its share; only from w>1w>1 does the voice start to insist.

The realization

ε~=εu+w (εc−εu)786 432 → 16 384  (48×)\begin{gathered}\tilde\varepsilon=\varepsilon_{\text{u}}+w\,(\varepsilon_{\text{c}}-\varepsilon_{\text{u}})\\ 786\,432\ \to\ 16\,384\ \ (48\times)\end{gathered}

Steer by taking the difference the request makes to the noise guess and making it louder; walk in a VAE's small latent space to keep it cheap. Words guide the picture through the same compass that made it.

Pause & predict

εuncond=0.4\varepsilon_{\text{uncond}}=0.4, εcond=0.1\varepsilon_{\text{cond}}=0.1, and w=2w=2. What is the guided guess?

Pause & predict

In the widget you raise ww from 1 to 5 for the class lamps. What happens?

If you want the algebra · 1 proof, step by step
Prove it · guidance is Bayes' rule with a louder class vote

Claim. In scores, ε~=εu+w(εc−εu)\tilde\varepsilon=\varepsilon_u+w(\varepsilon_c-\varepsilon_u) is the noise guess of the tilted density p(x) p(c∣x)wp(x)\,p(c\mid x)^{w}: it samples as if the "does this look like cc?" vote were raised to the power ww.

1
Bayes (Unit 14): p(x∣c)=p(c∣x) p(x)/p(c)p(x\mid c)=p(c\mid x)\,p(x)/p(c). Take logs and slopes in xx (p(c)p(c) has no slope): ∇log⁡p(x∣c)=∇log⁡p(x)+∇log⁡p(c∣x).\begin{aligned}&\nabla\log p(x\mid c)\\ &=\nabla\log p(x)\\ &\quad+\nabla\log p(c\mid x).\end{aligned} So the class vote's slope is the difference of the two scores.
2
Scores are −ε/1−αˉ-\varepsilon/\sqrt{1-\bar\alpha} (§10), so εc−εu=−1−αˉ ∇log⁡p(c∣x)\varepsilon_c-\varepsilon_u=-\sqrt{1-\bar\alpha}\,\nabla\log p(c\mid x). Then ε~=εu+w(εc−εu)=−1−αˉ ∇(log⁡p(x)+wlog⁡p(c∣x)),\begin{aligned}\tilde\varepsilon&=\varepsilon_u+w(\varepsilon_c-\varepsilon_u)\\ &=-\sqrt{1-\bar\alpha}\,\nabla\big(\log p(x)\\ &\qquad+w\log p(c\mid x)\big),\end{aligned} the noise guess of p(x) p(c∣x)wp(x)\,p(c\mid x)^w. ∎ w=0w=0: p(x)p(x). w=1w=1: p(x∣c)p(x\mid c), up to a constant. w>1w>1: the class vote counts ww times, which favours places where the class is most certain. On the rangoli with class "lamps", that is the outer ring.

In one sentence: Guidance is a sat-nav voice saying "more to the left than you think" — ε~=εuncond+w(εcond−εuncond)\tilde\varepsilon=\varepsilon_{\text{uncond}}+w(\varepsilon_{\text{cond}}-\varepsilon_{\text{uncond}}) — and latent diffusion runs the whole walk in a VAE's code, 48 times smaller, before decoding once at the end.

14

What to carry forward — and the whole course inside one picture

Thirteen pictures hold this unit. If you can draw each one and say its line, you own the unit.

1 · The lump of clay

To create is to sample: x=g(z)x=g(z), a fixed skill applied to fresh noise.

2 · The chai glass

Shrink by 1−β\sqrt{1-\beta}, add noise of variance β\beta: the glass stays full, and every start ends in N(0,1)N(0,1).

3 · Two numbers on the phone

An autoencoder squeezes and rebuilds; with straight lines it is PCA. Its map has empty land.

4 · A neighbourhood, not a house

A VAE's cloud plus a KL price 12(μ2+σ2−1−ln⁡σ2)\tfrac12(\mu^2+\sigma^2-1-\ln\sigma^2) fills the map.

5 · The wobble on a card

z=μ+σεz=\mu+\sigma\varepsilon: roll the dice first, and blame flows through.

6 · A platform under the ceiling

log⁡p(x)=ELBO+gap\log p(x)=\text{ELBO}+\text{gap}: rebuild well, stay near the prior.

7 · A map of faces

Sample from the prior, walk straight lines to morph; squared error paints blur.

8 · The ink drop

xt=αˉtx0+1−αˉtεx_t=\sqrt{\bar\alpha_t}x_0+\sqrt{1-\bar\alpha_t}\varepsilon: a thousand noisings in one jump.

9 · The restorer

Learn the dust by squared error; x^0=(xt−1−αˉε^)/αˉ\hat x_0=(x_t-\sqrt{1-\bar\alpha}\hat\varepsilon)/\sqrt{\bar\alpha}.

10 · The compass

score=−ε^/1−αˉ\text{score}=-\hat\varepsilon/\sqrt{1-\bar\alpha}: fuzzy far away, sharp near a village.

11 · The film backwards

Step along the compass, add a jiggle, a thousand times. No jiggle, no variety.

12 · The light on the stairs

DDIM: estimate the landing, jump with the same noise guess. Same start, same picture.

13 · The sat-nav voice

Steer with εu+w(εc−εu)\varepsilon_u+w(\varepsilon_c-\varepsilon_u): take the difference the request makes and say it louder — "more to the left than you think". And to keep it cheap, run the whole walk in a VAE's small code and decode once at the end.

The families of generators, again — now you know what is inside.

autoregressive (Unit 19)VAEGANdiffusion
trained bynext-token cross-entropythe ELBOa forger–detective gamesquared error on the noise
draws withone token at a timeone decoder passone generator pass25 to 1 000 small steps
best attext, codesmooth maps, compressionfast sharp picturesthe sharpest, most varied pictures; steering
its weak spotslow for long outputsblurunstable, forgets kinds of datamany steps

The whole course, inside two machines. An LLM (Unit 19) and a diffusion model look nothing alike: one writes a word at a time, the other paints a whole picture out of static. Yet follow either one from start to end, and every stage is a tool you built in this course.

An LLM · Unit 19
a promptwords cut into tokens16
vectorsevery token is a list of numbers2316
attention layersdot products pick what to look at; matrices mix1318
a probability listsoftmax over every next word14
a dice rollthe next word, sampled1419
A diffusion model · this unit
pure statica draw from N(0,I)N(0,I)14
the restorera network of matrices and attention guesses the noise1518
the compassthe score: a gradient of log⁡p\log p614
a small step + a jiggledescent with noise, small enough for Taylor89
a pictureoften decoded from a VAE's small map1220
Both are trained the same way: a loss built from probability 14 · slopes by the chain rule and backprop 6715 · downhill steps with Adam 91011
Each numbered circle is a unit of this course (its ring has the colour of its part); tap one to go back to it. Every stage of both machines is built from tools you already own.

The same story, as a table you can read row by row:

what you learnedwhere it lives now
Vectors and dot products (Unit 3)attention scores in the LLM; cross-attention from the picture to the prompt
Matrices and rank (Units 1, 5)every layer; low-rank fine-tuning of both machines
Eigenvectors, SVD, PCA (Units 4, 5, 12)the autoencoder's squeeze; the latent space of latent diffusion
Derivatives, the chain rule, backprop (Units 6, 7, 15)training both; the reparameterisation trick; the score is a gradient
Taylor (Unit 8)why tiny reverse steps are almost bell curves
Gradient descent, noise, Adam (Units 9, 11)training both; and sampling itself — Langevin is descent with a jiggle
Probability, Gaussians, softmax, KL (Unit 14)every loss: cross-entropy for the LLM, the ELBO's KL for the VAE, squared error (a Gaussian likelihood) for diffusion; sampling from both
Attention and transformers (Unit 18)the LLM's whole body; the text reader and often the denoiser of a diffusion model

Rule of thumb. When you meet a new model, ask three questions: what noise goes in, what is it trained to predict, and how does it walk from noise to data? Every generator in this unit is an answer to those three.

Pause & predict

A friend says: "Diffusion models have nothing to do with gradient descent — they are trained differently and they sample differently." Which is the best reply?

In one sentence: A machine creates by learning to walk from noise to data — through a small map (the VAE) or down a thousand steps of fading static along a learned compass (diffusion) — and every step of that walk is built from the vectors, derivatives, descents and probabilities of this course.

15

Practice arena — sixteen problems, solved in full

Sixteen problems, in the order of the unit: making samples from noise, the Gaussian toolkit, the KL of a cloud, the trick and its slopes, a whole ELBO by hand, the forward jump and a schedule's half-life, the restorer, the compass for one and two villages, one step of DDPM, Langevin and DDIM, guidance, and the latent squeeze. The tags say which are easy and which are hard. Every number here was checked by machine.

Three habits do most of the work. Square roots first: write down αˉ\sqrt{\bar\alpha} and 1−αˉ\sqrt{1-\bar\alpha} before anything else — almost every formula uses them. Variances add, spreads do not. And check the sign of every score: it must point towards the data.

Problem 1easysampling

A tea stall's daily sales follow N(200, 152)N(200,\ 15^2) cups. (a) Turn the standard draws z=−2, 0.4, 1.5z=-2,\ 0.4,\ 1.5 into sales. (b) Which zz would give a day of 245 cups?

What this tests. The stretch-and-shift generator of §1. Plan. x=μ+σzx=\mu+\sigma z forwards, then solve it for zz.

Show the full solution
Step 1 — (a). 200+15(−2)=170200+15(-2)=170, 200+15(0.4)=206200+15(0.4)=206, 200+15(1.5)=222.5200+15(1.5)=222.5.
Step 2 — (b). z=(x−μ)/σ=(245−200)/15=3z=(x-\mu)/\sigma=(245-200)/15=3.

answers at a glance: (a) 170, 206, 222.5 cups. (b) z=3z=3.

Remember

The generator never changes; only the noise does. Running it backwards, z=(x−μ)/σz=(x-\mu)/\sigma, is what an encoder does.

Problem 2easyinverse CDF

Waiting times follow an exponential curve with λ=2\lambda=2: F(x)=1−e−2xF(x)=1-e^{-2x}. (a) Find the sampler x=F−1(u)x=F^{-1}(u). (b) Sample it at u=0.75u=0.75 and u=0.2u=0.2. (c) Which uu gives the median wait, and what is it?

What this tests. The inverse-CDF trick of §1. Plan. Solve u=1−e−2xu=1-e^{-2x} for xx.

Show the full solution
Step 1 — (a). e−2x=1−ue^{-2x}=1-u, so x=−12ln⁡(1−u)x=-\tfrac12\ln(1-u).
Step 2 — (b). u=0.75u=0.75: −12ln⁡0.25=12ln⁡4≈0.6931-\tfrac12\ln0.25=\tfrac12\ln4\approx0.6931. u=0.2u=0.2: −12ln⁡0.8≈0.1116-\tfrac12\ln0.8\approx0.1116.
Step 3 — (c). The median is where half the waits are shorter: u=0.5u=0.5, x=12ln⁡2≈0.3466x=\tfrac12\ln2\approx0.3466.

answers at a glance: (a) x=−12ln⁡(1−u)x=-\tfrac12\ln(1-u). (b) 0.6931 and 0.1116. (c) u=0.5u=0.5, x≈0.3466x\approx0.3466.

Remember

Even noise in, any shape out: run the CDF backwards. The quantiles of the output are the quantiles of uu.

Problem 3mediumthe toolkit

One noising step is x→0.8 x+0.2 εx\to\sqrt{0.8}\,x+\sqrt{0.2}\,\varepsilon. (a) For the fixed start x=−1x=-1, give the bell curve after one step (mean and spread). (b) If instead x∼N(0,4)x\sim N(0,4), what is the variance after one step? (c) For independent XX, YY with variances 1 and 2, find Var⁡(3X−2Y)\operatorname{Var}(3X-2Y).

What this tests. The two facts of §2. Plan. Factors come out squared; independent variances add (a minus sign squares away).

Show the full solution
Step 1 — (a). Mean 0.8(−1)≈−0.8944\sqrt{0.8}(-1)\approx-0.8944; spread 0.2≈0.4472\sqrt{0.2}\approx0.4472.
Step 2 — (b). 0.8×4+0.2=3.40.8\times4+0.2=3.4: the cloud shrinks towards variance 1.
Step 3 — (c). 32(1)+(−2)2(2)=9+8=173^2(1)+(-2)^2(2)=9+8=17.

answers at a glance: (a) N(−0.8944, 0.44722)N(-0.8944,\ 0.4472^2). (b) 3.4. (c) 17.

Remember

Only a start of variance exactly 1 stays at 1. Anything else drifts towards 1, step by step.

Problem 4mediumKL of a cloud

(a) Find KL⁡(N(0.5, 0.82) ∥ N(0,1))\operatorname{KL}\big(N(0.5,\ 0.8^2)\,\|\,N(0,1)\big). (b) A cloud centred at μ=0\mu=0 pays a KL of 0.3181 and is narrower than the standard one. Find its spread σ\sigma.

What this tests. The KL formula of §4, forwards and backwards. Plan. 12(μ2+σ2−1−ln⁡σ2)\tfrac12(\mu^2+\sigma^2-1-\ln\sigma^2); for (b), try simple spreads below 1.

Show the full solution
Step 1 — (a). 12(0.25+0.64−1−ln⁡0.64)=12(−0.11+0.4463)≈0.1681\tfrac12(0.25+0.64-1-\ln0.64)=\tfrac12(-0.11+0.4463)\approx0.1681.
Step 2 — (b). With μ=0\mu=0: σ2−1−ln⁡σ2=2×0.3181≈0.636\sigma^2-1-\ln\sigma^2=2\times0.3181\approx0.636. Try σ=0.5\sigma=0.5: 0.25−1−ln⁡0.25=−0.75+1.3863≈0.6360.25-1-\ln0.25=-0.75+1.3863\approx0.636. ✓
Step 3 — check. A wider cloud can pay the same price too (about σ≈1.608\sigma\approx1.608): the KL punishes too narrow and too wide.

answers at a glance: (a) ≈0.1681\approx0.1681. (b) σ=0.5\sigma=0.5.

Remember

The spread part σ2−1−ln⁡σ2\sigma^2-1-\ln\sigma^2 is 0 only at σ=1\sigma=1 and grows on both sides.

Problem 5easythe trick

An encoder gives μ=−0.5\mu=-0.5, σ=2\sigma=2, and the wobble is ε=0.3\varepsilon=0.3. The loss is L=z2L=z^2. Find (a) zz; (b) ∂L/∂μ\partial L/\partial\mu and ∂L/∂σ\partial L/\partial\sigma.

What this tests. The reparameterisation trick and the chain rule (§5). Plan. z=μ+σεz=\mu+\sigma\varepsilon; then ∂L/∂z\partial L/\partial z times 1 and times ε\varepsilon.

Show the full solution
Step 1 — (a). z=−0.5+2(0.3)=0.1z=-0.5+2(0.3)=0.1.
Step 2 — (b). ∂L/∂z=2z=0.2\partial L/\partial z=2z=0.2. ∂L/∂μ=0.2×1=0.2\partial L/\partial\mu=0.2\times1=0.2; ∂L/∂σ=0.2×0.3=0.06\partial L/\partial\sigma=0.2\times0.3=0.06.

answers at a glance: (a) z=0.1z=0.1. (b) 0.2 and 0.06.

Remember

The slope to σ\sigma is the slope to zz times the wobble: a draw that landed on the other side (ε<0\varepsilon<0) would push σ\sigma the other way.

Problem 6harda whole ELBO

Two codes A and B, each with prior 0.5. p(x∣A)=0.9p(x\mid A)=0.9, p(x∣B)=0.1p(x\mid B)=0.1. (a) Find p(x)p(x), log⁡p(x)\log p(x) and the true posterior. (b) For q=(0.5, 0.5)q=(0.5,\ 0.5), find the rebuild, the KL to the prior, the ELBO and the gap. (c) The same for q=(0.7, 0.3)q=(0.7,\ 0.3). (d) Check that the gap in (c) equals KL⁡(q ∥ posterior)\operatorname{KL}(q\,\|\,\text{posterior}).

What this tests. §6 end to end. Plan. rebuild =∑qln⁡p(x∣z)=\sum q\ln p(x\mid z), KL =∑qln⁡(q/prior)=\sum q\ln(q/\text{prior}), ELBO = rebuild − KL, gap =log⁡p(x)−=\log p(x)- ELBO.

Show the full solution
Step 1 — (a). p(x)=0.45+0.05=0.5p(x)=0.45+0.05=0.5; log⁡p(x)=ln⁡0.5≈−0.6931\log p(x)=\ln0.5\approx-0.6931; posterior (0.45/0.5, 0.05/0.5)=(0.9, 0.1)(0.45/0.5,\ 0.05/0.5)=(0.9,\ 0.1).
Step 2 — (b). rebuild =0.5ln⁡0.9+0.5ln⁡0.1≈−1.2040=0.5\ln0.9+0.5\ln0.1\approx-1.2040; KL =0=0; ELBO ≈−1.2040\approx-1.2040; gap ≈−0.6931+1.2040=0.5108\approx-0.6931+1.2040=0.5108.
Step 3 — (c). rebuild =0.7ln⁡0.9+0.3ln⁡0.1≈−0.0738−0.6908=−0.7645=0.7\ln0.9+0.3\ln0.1\approx-0.0738-0.6908=-0.7645. KL =0.7ln⁡1.4+0.3ln⁡0.6≈0.2355−0.1532=0.0823=0.7\ln1.4+0.3\ln0.6\approx0.2355-0.1532=0.0823. ELBO ≈−0.8468\approx-0.8468; gap ≈0.1537\approx0.1537.
Step 4 — (d). 0.7ln⁡0.70.9+0.3ln⁡0.30.1≈−0.1759+0.3296=0.15370.7\ln\frac{0.7}{0.9}+0.3\ln\frac{0.3}{0.1}\approx-0.1759+0.3296=0.1537. ✓

answers at a glance: (a) 0.5, −0.6931, (0.9, 0.1). (b) −1.2040, 0, −1.2040, gap 0.5108. (c) −0.7645, 0.0823, −0.8468, gap 0.1537. (d) equal.

Remember

The closer the guess is to the posterior, the smaller the gap — here (0.9, 0.1) would close it completely, with ELBO =−0.6931=-0.6931.

Problem 7easyone jump

A short schedule has β=(0.1, 0.2, 0.5)\beta=(0.1,\ 0.2,\ 0.5). (a) Find αˉ3\bar\alpha_3. (b) Write x3x_3 as one jump from x0x_0. (c) Evaluate it for x0=1x_0=1, ε=−0.5\varepsilon=-0.5.

What this tests. The closed form of §8. Plan. Multiply the keep factors 1−β1-\beta; take square roots.

Show the full solution
Step 1 — (a). 0.9×0.8×0.5=0.360.9\times0.8\times0.5=0.36.
Step 2 — (b). x3=0.36 x0+0.64 ε=0.6x0+0.8εx_3=\sqrt{0.36}\,x_0+\sqrt{0.64}\,\varepsilon=0.6x_0+0.8\varepsilon.
Step 3 — (c). 0.6(1)+0.8(−0.5)=0.20.6(1)+0.8(-0.5)=0.2.

answers at a glance: (a) 0.36. (b) 0.6x0+0.8ε0.6x_0+0.8\varepsilon. (c) 0.2.

Remember

The two weights always satisfy 0.62+0.82=10.6^2+0.8^2=1: the glass stays full.

Problem 8harda schedule's half-life

A schedule uses the same β\beta at every step. (a) Find a formula for the first step tt at which αˉt\bar\alpha_t drops below a level aa. (b) Apply it with β=0.01\beta=0.01, a=0.5a=0.5. (c) And with a=0.1a=0.1.

What this tests. αˉt=(1−β)t\bar\alpha_t=(1-\beta)^t, turned around with logs. Plan. Solve (1−β)t<a(1-\beta)^t<a; both logs are negative, so the inequality flips.

Show the full solution
Step 1 — (a). tln⁡(1−β)<ln⁡at\ln(1-\beta)<\ln a. Divide by the negative ln⁡(1−β)\ln(1-\beta): t>ln⁡a/ln⁡(1−β)t>\ln a/\ln(1-\beta). The first whole step is the next whole number above ln⁡a/ln⁡(1−β)\ln a/\ln(1-\beta).
Step 2 — (b). ln⁡0.5/ln⁡0.99≈68.97\ln0.5/\ln0.99\approx68.97, so t=69t=69. Check: 0.9968≈0.50490.99^{68}\approx0.5049, 0.9969≈0.49980.99^{69}\approx0.4998. ✓
Step 3 — (c). ln⁡0.1/ln⁡0.99≈229.1\ln0.1/\ln0.99\approx229.1, so t=230t=230. Check: 0.99229≈0.10010.99^{229}\approx0.1001, 0.99230≈0.09910.99^{230}\approx0.0991. ✓

answers at a glance: (a) the first whole t>ln⁡a/ln⁡(1−β)t>\ln a/\ln(1-\beta). (b) 69. (c) 230.

Remember

A constant β\beta is a steady decay: every 69 steps it halves what is left. DDPM's β\beta is not constant — it starts tiny and grows — so its halfway point (step 260) has to be counted by multiplying the factors one by one.

Problem 9easythe restorer

At αˉ=0.64\bar\alpha=0.64 the restorer sees xt=0.5x_t=0.5 and guesses ε^=−1\hat\varepsilon=-1. (a) Find x^0\hat x_0. (b) If the true clean value was 1.4, what noise was really added, and what is the training loss?

What this tests. x^0\hat x_0 from ε^\hat\varepsilon, and the other way round (§9). Plan. αˉ=0.8\sqrt{\bar\alpha}=0.8, 1−αˉ=0.6\sqrt{1-\bar\alpha}=0.6.

Show the full solution
Step 1 — (a). x^0=(0.5−0.6(−1))/0.8=1.1/0.8=1.375\hat x_0=(0.5-0.6(-1))/0.8=1.1/0.8=1.375.
Step 2 — (b). ε=(xt−0.8x0)/0.6=(0.5−1.12)/0.6≈−1.0333\varepsilon=(x_t-0.8x_0)/0.6=(0.5-1.12)/0.6\approx-1.0333. Loss (ε−ε^)2=(−1.0333+1)2≈0.0011(\varepsilon-\hat\varepsilon)^2=(-1.0333+1)^2\approx0.0011.

answers at a glance: (a) 1.375. (b) ε≈−1.0333\varepsilon\approx-1.0333, loss ≈0.0011\approx0.0011.

Remember

A small error in ε^\hat\varepsilon becomes an error in x^0\hat x_0 multiplied by 1−αˉ/αˉ\sqrt{1-\bar\alpha}/\sqrt{\bar\alpha}: here 0.75 times as big.

Problem 10mediumthe compass

(a) For N(−1, 0.5)N(-1,\ 0.5) (variance 0.5), find the score at x=0x=0 and at x=−2x=-2. (b) A single clean point x0=3x_0=3 is noised to αˉ=0.25\bar\alpha=0.25, and you see xt=1.2x_t=1.2. Find the score there, and the noise guess ε^\hat\varepsilon it corresponds to.

What this tests. The score of a bell, and score ↔ε^\leftrightarrow\hat\varepsilon (§10). Plan. −(x−μ)/σ2-(x-\mu)/\sigma^2; the noisy point is N(αˉx0, 1−αˉ)N(\sqrt{\bar\alpha}x_0,\ 1-\bar\alpha).

Show the full solution
Step 1 — (a). x=0x=0: −(0+1)/0.5=−2-(0+1)/0.5=-2 (go left). x=−2x=-2: −(−2+1)/0.5=+2-(-2+1)/0.5=+2 (go right).
Step 2 — (b). Centre 0.5×3=1.50.5\times3=1.5, variance 0.750.75: score =−(1.2−1.5)/0.75=0.4=-(1.2-1.5)/0.75=0.4.
Step 3 — (b). ε^=−1−αˉ⋅score=−0.75×0.4≈−0.3464\hat\varepsilon=-\sqrt{1-\bar\alpha}\cdot\text{score}=-\sqrt{0.75}\times0.4\approx-0.3464.

answers at a glance: (a) −2 and +2. (b) score 0.4, ε^≈−0.3464\hat\varepsilon\approx-0.3464.

Remember

Score and noise guess always have opposite signs: the noise pushed the point away; the compass points back.

Problem 11hardtwo villages

Data: half the points at −1-1, half at +1+1, each with variance 0.04. It is noised to αˉ=0.36\bar\alpha=0.36. (a) Where are the two noisy villages, and what is their variance? (b) At x=0.2x=0.2, find the two claims. (c) Find the score at x=0.2x=0.2. Which way does it point, and why?

What this tests. The mixture compass of §10. Plan. Centres ±αˉ\pm\sqrt{\bar\alpha}, variance αˉs2+1−αˉ\bar\alpha s^2+1-\bar\alpha; claims from the two bells; score = claims × pulls.

Show the full solution
Step 1 — (a). Centres ±0.6\pm0.6; variance 0.36(0.04)+0.64=0.65440.36(0.04)+0.64=0.6544.
Step 2 — (b). Exponents: −(0.2+0.6)2/(2×0.6544)≈−0.4890-(0.2+0.6)^2/(2\times0.6544)\approx-0.4890 and −(0.2−0.6)2/(2×0.6544)≈−0.1222-(0.2-0.6)^2/(2\times0.6544)\approx-0.1222. e−0.4890≈0.6132e^{-0.4890}\approx0.6132, e−0.1222≈0.8849e^{-0.1222}\approx0.8849. Claims ≈(0.4093, 0.5907)\approx(0.4093,\ 0.5907).
Step 3 — (c). Pulls −(0.2+0.6)/0.6544≈−1.2225-(0.2+0.6)/0.6544\approx-1.2225 and −(0.2−0.6)/0.6544≈0.6112-(0.2-0.6)/0.6544\approx0.6112. Score ≈0.4093(−1.2225)+0.5907(0.6112)≈−0.1394\approx0.4093(-1.2225)+0.5907(0.6112)\approx-0.1394.
Step 4 — why. It points gently left, towards the middle — even though the right village claims more. At this much noise the two villages overlap into one soft hill, and 0.2 is just to the right of its top.

answers at a glance: (a) ±0.6\pm0.6, 0.6544. (b) (0.4093, 0.5907)(0.4093,\ 0.5907). (c) ≈−0.1394\approx-0.1394, gently to the left.

Remember

The nearer village does not always win the compass: a strong pull from a far village, weighted by its claim, can outweigh a weak pull from a near one.

Problem 12mediumone DDPM step

A DDPM step with βt=0.2\beta_t=0.2, αˉt=0.64\bar\alpha_t=0.64, xt=0.8x_t=0.8, ε^=0.3\hat\varepsilon=0.3 and fresh draw z=0.5z=0.5. Find (a) the mean of the step, (b) σt\sigma_t, (c) xt−1x_{t-1}.

What this tests. DDPM's step (§11). Plan. αt=0.8\alpha_t=0.8, 1−αˉt=0.6\sqrt{1-\bar\alpha_t}=0.6, σt=βt\sigma_t=\sqrt{\beta_t}.

Show the full solution
Step 1 — (a). βt1−αˉtε^=0.20.6(0.3)=0.1\frac{\beta_t}{\sqrt{1-\bar\alpha_t}}\hat\varepsilon=\frac{0.2}{0.6}(0.3)=0.1. Mean =(0.8−0.1)/0.8≈0.7/0.8944≈0.7826=(0.8-0.1)/\sqrt{0.8}\approx0.7/0.8944\approx0.7826.
Step 2 — (b). σt=0.2≈0.4472\sigma_t=\sqrt{0.2}\approx0.4472.
Step 3 — (c). 0.7826+0.4472(0.5)≈1.00620.7826+0.4472(0.5)\approx1.0062.

answers at a glance: (a) ≈0.7826\approx0.7826. (b) ≈0.4472\approx0.4472. (c) ≈1.0062\approx1.0062.

Remember

Remove only this step's share of the noise, undo this step's shrink, then jiggle. Never remove all of ε^\hat\varepsilon in one DDPM step.

Problem 13easyLangevin

Target p=N(1, 0.25)p=N(1,\ 0.25). One Langevin step from x=2x=2 with η=0.05\eta=0.05 and jiggle z=−1z=-1. Where do you land?

What this tests. x←x+η score+2η zx\leftarrow x+\eta\,\text{score}+\sqrt{2\eta}\,z (§11). Plan. The score is −(x−1)/0.25-(x-1)/0.25.

Show the full solution
Step 1 — score. −(2−1)/0.25=−4-(2-1)/0.25=-4.
Step 2 — step. 2+0.05(−4)=1.82+0.05(-4)=1.8; jiggle 0.1(−1)≈−0.3162\sqrt{0.1}(-1)\approx-0.3162; land at ≈1.4838\approx1.4838.

answer at a glance: x≈1.4838x\approx1.4838.

Remember

The downhill part pulls towards the peak at 1; the jiggle, of size 2η\sqrt{2\eta}, keeps the walkers spread with the right width.

Problem 14mediumone DDIM jump

At αˉt=0.36\bar\alpha_t=0.36 a walker is at xt=0.2x_t=0.2, and the restorer guesses ε^=−0.5\hat\varepsilon=-0.5. (a) Find x^0\hat x_0. (b) Jump with DDIM to αˉs=0.81\bar\alpha_s=0.81. (c) Where would a jump to αˉs=1\bar\alpha_s=1 land?

What this tests. The two moves of DDIM (§12). Plan. 0.36=0.6\sqrt{0.36}=0.6, 0.64=0.8\sqrt{0.64}=0.8, 0.81=0.9\sqrt{0.81}=0.9, 0.19≈0.4359\sqrt{0.19}\approx0.4359.

Show the full solution
Step 1 — (a). x^0=(0.2−0.8(−0.5))/0.6=0.6/0.6=1\hat x_0=(0.2-0.8(-0.5))/0.6=0.6/0.6=1.
Step 2 — (b). xs=0.9(1)+0.4359(−0.5)≈0.6821x_s=0.9(1)+0.4359(-0.5)\approx0.6821.
Step 3 — (c). At αˉs=1\bar\alpha_s=1 the noise weight is 0: xs=x^0=1x_s=\hat x_0=1.

answers at a glance: (a) 1. (b) ≈0.6821\approx0.6821. (c) 1.

Remember

DDIM re-uses the same ε^\hat\varepsilon: no new randomness, so the same start always gives the same picture.

Problem 15mediumguidance

For one pixel pair, the unconditional guess is εu=(0.1, −0.2)\varepsilon_u=(0.1,\ -0.2) and the conditional guess is εc=(0.4, 0.2)\varepsilon_c=(0.4,\ 0.2). (a) Find the guided guess for w=2.5w=2.5. (b) Which ww makes its first entry 1.3?

What this tests. Classifier-free guidance (§13), forwards and backwards. Plan. εu+w(εc−εu)\varepsilon_u+w(\varepsilon_c-\varepsilon_u), entry by entry.

Show the full solution
Step 1 — the difference. εc−εu=(0.3, 0.4)\varepsilon_c-\varepsilon_u=(0.3,\ 0.4).
Step 2 — (a). (0.1+2.5(0.3), −0.2+2.5(0.4))=(0.85, 0.8)(0.1+2.5(0.3),\ -0.2+2.5(0.4))=(0.85,\ 0.8).
Step 3 — (b). 0.1+0.3w=1.3⇒w=40.1+0.3w=1.3\Rightarrow w=4.

answers at a glance: (a) (0.85, 0.8)(0.85,\ 0.8). (b) w=4w=4.

Remember

w=1w=1 gives exactly εc\varepsilon_c; every extra unit of ww adds one more copy of the difference the prompt makes.

Problem 16easythe latent squeeze

A 1024 × 1024 colour picture is squeezed by an autoencoder into a 128 × 128 × 4 latent. (a) How many numbers before and after, and by what factor? (b) Show that squeezing each side by a factor ff into cc channels shrinks a colour picture by 3f2/c3f^2/c, and apply it to f=16f=16, c=16c=16.

What this tests. Latent diffusion's saving (§13), as a general formula. Plan. Count numbers; each side shrinks by ff, channels go from 3 to cc.

Show the full solution
Step 1 — (a). 1024×1024×3=3 145 7281024\times1024\times3=3\,145\,728; 128×128×4=65 536128\times128\times4=65\,536; factor 48.
Step 2 — (b). H⋅W⋅3(H/f)(W/f) c=3f2c\dfrac{H\cdot W\cdot3}{(H/f)(W/f)\,c}=\dfrac{3f^2}{c}. With f=8, c=4f=8,\ c=4: 48, as in (a). With f=16, c=16f=16,\ c=16: 3×256/16=483\times256/16=48 again.

answers at a glance: (a) 3 145 728 → 65 536, 48 times. (b) 3f2/c3f^2/c; 48.

Remember

The diffusion network runs on the small latent at every one of its steps; the big decoder runs only once, at the end.

The route is complete · 20 of 20

You have walked the whole way — from a line on a page to a machine that draws.

You started with equations that meet at a point. You learned to see matrices as machines, to find the directions they leave alone, to follow a slope downhill, to count with probabilities. Then those tools grew into networks that read, remember, pay attention, write — and now draw from noise.

← Unit 19 · The Maths Inside an LLM · All units