Before this lesson:lesson 01
(the ELBO), lesson 02 (the KL divergence between two
Gaussians) and lesson 06 (denoising score
matching). From other tracks: the multivariate Gaussian
(sums of independent Gaussians, conditioning). Time: about 95 minutes, plus the notebook.
DDPM is the starting point of modern diffusion models: Stable Diffusion, Imagen and DALL·E 2 for
images, diffusion models for video and audio, GenCast for ensemble weather forecasts, and latent
diffusion emulators of seismic ground motion. The loss of this lesson ("predict the noise") is still
the most common training objective. The next lessons change one piece of what is built here: the
prediction target and the loss weights (lesson 08),
the sampler (lesson 09), the conditioning
(lesson 11) and the number of steps
(lesson 12). "Derive the DDPM loss" is also a standard
interview question.
DDPM is a latent variable model with a fixed encoder, so it connects back to lesson 01: the
training loss is the ELBO. It is also a score model: predicting the noise is denoising score
matching at many noise levels, as in lesson 06.
One coordinate, one data point. Take x0=2. One forward step multiplies by 1−β
(a number slightly below 1) and adds Gaussian noise of variance β:
xt=1−βtxt−1+βtzt,zt∼N(0,1).
The mean shrinks geometrically toward 0, and the noise accumulates. If xt−1 has variance 1, then
xt has variance (1−βt)⋅1+βt=1: the process is variance preserving (for data
of unit variance). After many steps, xT is close to N(0,1) and has forgotten x0.
In 2D. The figure applies the forward process to the track's 8 Gaussians. The heat map is the exact
density of xt; the dots are data points pushed to step t.
Interactive figure: loading…
Move the step t (or press Play). The 8 modes shrink toward the center and blur into one Gaussian.
The shaded heat map is the exact density of xt. Switch "How xt is made"
between one jump xt=αˉtx0+1−αˉtε and running the chain for
t steps: the path of the yellow point changes, but the
cloud of points and the variance readouts agree. This is Theorem 1 below.
The generative model runs the chain backward. Start from xT∼N(0,I) and apply
learned Gaussian steps pθ(xt−1∣xt) down to x0. A Gaussian reverse step is a good model
only because each forward step is small. For a small step, the true reverse conditional
q(xt−1∣xt) is close to Gaussian. For a large step it can have several modes, and no Gaussian
can fit it.
Interactive figure: loading…
One reverse step in 1D, for data with two points x0∈{−1,+1}. The
blue curves are the forward posteriors q(xt−1∣xt,x0) for each data
point: always Gaussian. The black curve is the true reverse step q(xt−1∣xt), a mixture of the
two blue curves. The orange dashed curve is the best single Gaussian. With
"large step" the black curve has two bumps and the KL readout is large; choose "small step" and it is
almost Gaussian. Move the observed xt to see the weights change.
It is a latent variable model. The latents are x1,…,xT, each with the same dimension as the
data. The "encoder" q(x1:T∣x0) is the fixed forward process and has no parameters. Only the
"decoder" chain pθ is learned. So DDPM is a hierarchical VAE with a fixed encoder, and the
ELBO of lesson 01 applies without
change.
The key trick. The reverse conditional q(xt−1∣xt) depends on the unknown data distribution.
But once we also condition on x0, the forward posteriorq(xt−1∣xt,x0) is a Gaussian with a
closed form (the blue curves above). The ELBO compares each learned step with this known Gaussian: one
KL divergence per step.
Quick check
In the figure with two data points and a large step, why is the true reverse step q(xt−1∣xt) bimodal even though each forward posterior is Gaussian?
Why.
q(xt−1∣xt)=∑x0q(x0∣xt)q(xt−1∣xt,x0). Each term is Gaussian, but with a large step the two means are far apart, so the mixture has two bumps. The forward noise is always Gaussian, and nothing here is learned.
x0∈Rd is a data point. The noise schedule is β1,…,βT∈(0,1). Write
αt=1−βt,αˉt=s=1∏tαs,αˉ0=1.
Always ε∼N(0,I).
Forward process:q(xt∣xt−1)=N(αtxt−1,βtI) and
q(x1:T∣x0)=∏t=1Tq(xt∣xt−1), a Markov chain.
Reverse model:p(xT)=N(0,I) and pθ(xt−1∣xt)=N(μθ(xt,t),σt2I), with
a network μθ and fixed variances σt2. The joint is
pθ(x0:T)=p(xT)∏t=1Tpθ(xt−1∣xt).
Linear schedule (Ho et al.): βt evenly spaced from β1=10−4 to βT=0.02, with
T=1000. This gives αˉT≈4.04×10−5.
Cosine schedule (Nichol and Dhariwal 2021): αˉt=f(t)/f(0) with
f(t)=cos2(1+st/T+s⋅2π),s=0.008, and each βt capped at 0.999.
Signal-to-noise ratio:SNR(t)=αˉt/(1−αˉt). It decreases with t.
Interactive figure: loading…
Compare the two schedules. Show αˉt,logSNR or βt against t/T. The
linear schedule loses half of the signal variance (αˉt=0.5) after about a
quarter of the steps (t=260); the cosine schedule keeps it until the middle
(t=497). Change T: the dashed curve shows what happens if you keep the T=1000 values of βt
with fewer steps.
The bracket is a sum of independent zero-mean Gaussians. Its covariance is cI with
c=αt(1−αˉt−1)+βt. Expand: c=αt−αˉt+1−αt=1−αˉt.■
So training never runs the chain: draw t and ε, and compute xt in one line.
Quick check
The data have variance 2 in every coordinate. Is the forward process variance preserving for these data?
Why.
Var(xt)=αtVar(xt−1)+βt. This equals Var(xt−1) only when that variance is 1. For data of variance 2, Var(xt)=2αˉt+1−αˉt=1+αˉt, which goes from 2 to 1. This is one reason to standardize the data.
Why this is true. Given x0, the pair (xt−1,xt) is jointly Gaussian: xt−1 comes from
Theorem 1, and xt is a linear function of xt−1 plus Gaussian noise. Conditioning a Gaussian on a
linear observation gives a Gaussian. The mean is a weighted average of "where x0 says xt−1 should
be" and "where xt says it should be".
Proof (completing the square). It is enough to work with one coordinate: all coordinates have the
same coefficients and are independent.
Bayes' rule and the Markov property, q(xt∣xt−1,x0)=q(xt∣xt−1), give, as a function of xt−1,
q(xt−1∣xt,x0)∝q(xt∣xt−1)q(xt−1∣x0).
Write y=xt−1. Up to a constant that does not depend on y, the log of the right side is the
quadratic function of y below. So the posterior is Gaussian:
−21[βt(xt−αty)2+1−αˉt−1(y−αˉt−1x0)2].
Expand and collect the y2 terms. The coefficient of −21y2 is the precision (inverse
variance). With the identity of Theorem 1, step 4, it is
Take −Eq. Each of the first two groups is the expectation of log(q/p) over one variable,
averaged over the others: a KL divergence. The last group is L0.■
Why this form. Every KL is between two Gaussians, so it has a closed form. This has much lower
variance than a Monte Carlo estimate over the whole chain. LT has no parameters; for the linear
schedule and x0=1 it is 2.0×10−5 nats. For images scaled to [−1,1], Ho et al. model L0
with a discrete decoder over the 256 pixel values.
Theorem 4: each Lt−1 is a weighted noise-prediction error #
Parameterize the reverse mean like the ε-form of μ~t, with a noise-prediction networkεθ(xt,t):
μθ(xt,t)=αt1(xt−1−αˉtβtεθ(xt,t)).
Then, for t≥2, with xt=αˉtx0+1−αˉtε and a constant Ct that does
not depend on θ,
Use the KL divergence between two Gaussians in Rd with covariances s12I and s22I
(lesson 02). Here s12=β~t and
s22=σt2 are fixed, so the first part below is the constant Ct:
Write both means in ε-form. They differ only in the noise term:
μ~t−μθ=αt1−αˉtβt(εθ−ε).
Square and divide by 2σt2:2σt2αt(1−αˉt)βt2∥ε−εθ∥2.■
So the network only has to predict the noise. This is denoising score matching at noise level t
(lesson 06): the score of the noised data is
∇logpt(xt)≈−εθ(xt,t)/1−αˉt. The weight depends on σt2:
with σt2=βt:
wt=2αt(1−αˉt)βt;
with σt2=β~t:
wt=2αt(1−αˉt−1)βt=21(SNR(t)SNR(t−1)−1).
For the linear schedule, w2=0.27 (with βt) or 0.60 (with β~t), while wt lies between
about 0.005 and 0.010 for every t≥100. So the ELBO puts about 27 to 120 times more weight on
t=2 than on any t≥100.
The t≥2 terms are the Lt−1 with weight 1 instead of wt. The t=1 term approximates L0.LT is dropped because it has no parameters.
Relative to the ELBO, Lsimplelowers the weight of small t. Those terms teach the
network to remove tiny amounts of noise: easy, and almost invisible in samples. The effort moves to
larger t, where the network must create structure.
Result (Ho et al., CIFAR-10, Table 1): training on the true bound L gives FID 13.51 and
≤3.70 bits/dim; Lsimple gives FID 3.17 and ≤3.75 bits/dim. Much better samples,
slightly worse likelihood. (FID: lower is better; lesson 14.)
Equal weights in ε also give targets of unit scale at every t, which is easy for a network.
Lesson 08 writes every such choice as a weight
over the log-SNR.
Quick check
Compared with the true ELBO, what does training with Lsimple do?
Why.
Lsimple is not the ELBO: it changes the weight of each noise level. It lowers the weight of the small-t terms, which dominate the likelihood but hardly affect what samples look like. On CIFAR-10: FID 3.17 vs 13.51, and ≤3.75 vs ≤3.70 bits/dim.
Training and ancestral sampling (Algorithms 1 and 2 of Ho et al.) #
Training. Repeat:
draw x0 from the data;
draw t∼U{1,…,T};
draw ε∼N(0,I);
take a gradient step on ∥ε−εθ(αˉtx0+1−αˉtε,t)∥2.
Sampling. Draw xT∼N(0,I). For t=T,…,1: draw z∼N(0,I) if t>1, else
set z=0; then
xt−1=αt1(xt−1−αˉtβtεθ(xt,t))+σtz.
Return x0. This costs T network evaluations (1000) per sample;
lesson 09 reduces this.
Another view of the same step. Let x^0=(xt−1−αˉtεθ)/αˉt be the
clean sample implied by the noise prediction. Then the step mean equals μ~t(xt,x^0):predict the clean sample, then take the forward-posterior step toward it. (Substitute x^0 into
Theorem 2; it is the ε-form with εθ in place of ε.) Libraries such as diffusers
compute the step this way, and can clip x^0 to the data range.
Interactive figure: loading…
Press "Play the reverse process". 1000 samples start as Gaussian noise and move
to the 8 data modes; the path of one sample is drawn. The
noise prediction is the exact best ε for this data (computed from the mixture, not learned), so
any error comes from the sampler. Choose T=1,2,5,10: with few large steps the Gaussian reverse step
is wrong, and samples land between the modes. With T=100 or 1000 both variance choices work.
The best fixed σt2 is the variance of the true reverse conditional q(xt−1∣xt), with x0
integrated out. It depends on the data. A 1D Gaussian example shows the range.
Let x0∼N(0,c2) and vt=Var(xt)=αˉtc2+1−αˉt. Then
Cov(xt−1,xt)=αtvt−1 and vt=αtvt−1+βt. Gaussian conditioning gives
c=0 (all data at one point): vt=1−αˉt, so the variance is β~t. This is exact for any
single point, because then q(xt−1∣xt)=q(xt−1∣xt,x0).
c=1 (unit-variance Gaussian data): vt=1, so the variance is βt.
0<c<1: in between.
Ho et al. (§3.2) state it the same way: βt is optimal for x0∼N(0,I),β~t for a
single point, and these are the two extremes for data with unit variance per coordinate. In practice
both give similar samples with T=1000, because β~t/βt=(1−αˉt−1)/(1−αˉt) is
close to 1 except for the first steps. For the linear schedule it is 0.45 at t=2,0.85 at t=10
and above 0.99 for t≥168. The variance matters more for the likelihood, because the ELBO terms
are largest at small t. Nichol and Dhariwal (2021) learn
Σθ=exp(νlogβt+(1−ν)logβ~t) with a network output ν, trained by
Lsimple+0.001L. This improves the log-likelihood and allows fewer sampling steps.
Quick check
All data are one point, x0=c. Which reverse variance makes the reverse model exact?
Why.
With one data point, q(xt−1∣xt)=q(xt−1∣xt,x0=c), whose variance is β~t (Theorem 2). βt is exact for unit-variance Gaussian data instead. σt2=0 would make the sampler deterministic, but the true reverse step still has noise for t≥2.
Why small steps make the reverse step Gaussian
Bayes' rule gives q(xt−1∣xt)∝q(xt∣xt−1)qt−1(xt−1), where qt−1 is the density of the
noised data at step t−1. The first factor is a Gaussian in xt−1 with variance βt/αt, so for
small βt it is very narrow. Over such a narrow window, logqt−1 is close to its first-order
Taylor expansion, a linear function. A Gaussian times the exponential of a linear function is again a
Gaussian, with its mean shifted by (βt/αt)∇logqt−1: the score appears here. So the reverse
step is Gaussian up to an error that shrinks with βt (Feller 1949; Sohl-Dickstein et al. 2015). For a
large βt, the window covers several modes of qt−1, and the product keeps them all.
Answers to section 1. (1) No. Theorem 1 gives x500 from x0 and one draw of ε.
(2) The likelihood gets slightly worse (3.75 vs 3.70 bits/dim) and the samples get much better
(FID 3.17 vs 13.51), because the weights moved from small t to larger t. (3) Worse: with large
steps the true reverse conditional has several modes, and a Gaussian step cannot follow it. With the
exact noise predictor on the 8 Gaussians, 99% of the samples land within 0.45 of a mode with
T=1000, but only 85% with T=10 and 55% with T=5 (notebook, section 4).
For the linear schedule with T=1000 it is 2.0×10−5 nats.
Open the figure of section 2 with "worked example" to see this posterior: αˉt−1=0.64,βt=0.4375 and xt=1.
Quick check
In the worked example, what is the reverse mean μθ if the network predicts the noise exactly, εθ=0.5?
Why.
With εθ=ε the model mean equals the ε-form of μ~2:0.751(1.0−0.546875⋅0.5)=0.96875.1.114583 is the mean for the wrong prediction 0.3;1.3333 forgets to subtract the noise.
NumPy checks the worked example by plain Gaussian conditioning (no DDPM formula), checks Theorem 4 on
the same numbers, and checks Theorems 1 and 2 on the linear schedule.
importnumpyasnp# (a) Worked example: abar = (0.64, 0.36, 0.04). The forward posterior at t = 2 by plain# Gaussian conditioning of the joint (x_1, x_2) given x_0, without any DDPM formula.ab1,ab2=0.64,0.36a2=ab2/ab1# alpha_2 = 0.5625x0,x2=1.0,1.0mean=np.array([np.sqrt(ab1)*x0,np.sqrt(ab2)*x0])cov=np.array([[1-ab1,np.sqrt(a2)*(1-ab1)],[np.sqrt(a2)*(1-ab1),1-ab2]])k=cov[0,1]/cov[1,1]# regression coefficient of x_1 on x_2print(f"{mean[0]+k*(x2-mean[1]):.5f}{cov[0,0]-k*cov[0,1]:.8f}")# 0.96875 0.24609375 (mu_tilde_2 and beta_tilde_2)# (b) The same mean from the eps-form, and the eps-MSE weight with sigma^2 = beta_tildeb2,eps,eps_hat=1-a2,0.5,0.3mu=(x2-b2/np.sqrt(1-ab2)*eps)/np.sqrt(a2)mu_th=(x2-b2/np.sqrt(1-ab2)*eps_hat)/np.sqrt(a2)bt2=(1-ab1)/(1-ab2)*b2w2=b2**2/(2*bt2*a2*(1-ab2))print(f"{mu:.5f}{(mu-mu_th)**2/(2*bt2):.6f}{w2*(eps-eps_hat)**2:.6f}")# 0.96875 0.043210 0.043210# (c) Theorems 1 and 2 on the linear schedule: chain vs jump, and the posterior variancerng=np.random.default_rng(0)T=1000betas=np.linspace(1e-4,0.02,T)abar=np.cumprod(1-betas)x=np.full(100000,2.0)forbinbetas[:300]:# run the chain for 300 stepsx=np.sqrt(1-b)*x+np.sqrt(b)*rng.standard_normal(x.shape)print(f"{x.mean():.3f}{np.sqrt(abar[299])*2:.3f}{x.var():.3f}{1-abar[299]:.3f}")# 1.262 1.259 0.602 0.604 (chain vs closed form: mean, variance)ratio=(1-np.concatenate([[1.0],abar[:-1]]))/(1-abar)# beta_tilde_t / beta_tprint(f"{abar[-1]:.2e}",ratio[1].round(3),ratio[9].round(3),np.argmax(ratio>0.99)+1)# 4.04e-05 0.455 0.853 168
The notebook writes the closed forms, the ELBO weights and the ancestral sampler, runs the sampler with
the exact noise predictor of the 8 Gaussians, and (optionally, with PyTorch) trains a small noise
predictor on two moons.
Images, video, audio. Noise prediction with Lsimple is the original recipe of latent
diffusion (Stable Diffusion 1.x), applied to autoencoder latents
(lesson 13). Imagen, DALL·E 2 and many audio
models (DiffWave, WaveGrad) started from the same loss.
Weather and climate. GenCast generates each ensemble member as a diffusion sample, conditioned on
the recent weather states (it uses the EDM form of lesson 08).
CorrDiff downscales to km scale with a diffusion model of the residual of a regression network.
Seismology. Latent diffusion emulators of ground motion run exactly this forward process on the
latent code of a waveform autoencoder, with conditioning inputs such as magnitude, distance and site terms.
Likelihoods. The full bound L gives bits per dimension
(lesson 14). Variational diffusion models train
L directly and reach strong likelihoods.
Practice: data scale. The schedule assumes data of unit scale. For data with standard deviation c,
the effective SNR is c2αˉt/(1−αˉt). Data with c=10 have 100 times the SNR at every
step, as if the log-SNR were shifted by ln100≈4.6. So standardize each channel (for physical
fields: each variable and level).
Indexing off by one.αˉt includes step t,αˉ0=1, and the posterior uses
αˉt−1. Storing schedules with length T+1 and index 0 for clean data avoids most errors.
Mixing up βt and 1−αˉt.βt is the variance added by one step;
1−αˉt is the total noise variance at t.xt=1−βtx0+βtε is wrong.
A variance where a standard deviation is needed. Multiply ε by 1−αˉt, and z
by σt, not by σt2.
Noise at the last step. At t=1, return the mean (z=0).
Reading Lsimple as a likelihood. Its value is not a bound on −logp(x0). To report
bits/dim, evaluate the weighted bound L.
Expecting the loss to reach zero. Even the best network cannot know ε exactly from xt. The
minimum of the loss is the conditional variance of ε given xt, summed over coordinates
(lesson 08). It stays positive.
Large steps with a Gaussian reverse step. With T=10 and the same total noise, the true reverse
conditional can be far from Gaussian (for multimodal data it can have several modes), and ancestral
sampling gives poor samples. Few-step sampling needs other tools
(lesson 09 and
lesson 12).
Data that are not standardized. The schedule then gives a different SNR than intended, and the
last step may still contain a lot of signal.
Why does q(xt−1∣xt,x0) have a closed form, but q(xt−1∣xt) does not?AnswerGiven x0, all variables are linear-Gaussian, so conditioning is Gaussian algebra. Without x0,q(xt−1∣xt)=∫q(xt−1∣xt,x0)q(x0∣xt)dx0 needs the posterior over the data, which depends on the unknown data distribution.
A constant schedule βt=0.01. After how many steps is αˉt<0.01?Answerαˉt=0.99t, and we need 0.99t<10−4:t>ln10−4/ln0.99=916.4, so t=917.
Show that the DDPM step mean equals μ~t(xt,x^0) with x^0=(xt−1−αˉtεθ)/αˉt.AnswerThe ε-form was obtained by substituting x0=(xt−1−αˉtε)/αˉt into μ~t. The same algebra with εθ in place of ε turns μ~t(xt,x^0) into αt1(xt−1−αˉtβtεθ)=μθ.
With σt2=β~t, write the ELBO weight wt of the ε-MSE in terms of the SNR. Is it larger at
small or at large t for the linear schedule?Answerwt=21(SNR(t−1)/SNR(t)−1). It is largest at small t(0.60 at t=2) and only about 0.005 to 0.010 for t≥100.
All data are one point, x0=c. What must εθ learn so that the reverse model with
σt2=β~t is exact?Answerεθ(xt,t)=(xt−αˉtc)/1−αˉt, the noise implied by the known c. Then x^0=c and μθ=μ~t(xt,c), so every reverse step equals the true one.
Why does LT not appear in training, and when is that a problem?AnswerIt has no parameters when the βt are fixed. It is a problem when αˉT is not small: then the prior N(0,I) does not match q(xT∣x0) (for x0=1: 0.0204 nats for the three-step example, 2×10−5 nats for the linear schedule). Lesson 08 shows a real case (zero terminal SNR).
Recall cardsAnswer in your head first, then reveal. Add the cards to your review deck to see them again just before you would forget.
What is q(xt∣x0) in DDPM?
N(αˉtx0,(1−αˉt)I), with αˉt=∏s=1t(1−βs).
How do you draw xt from x0 in one line?
xt=αˉtx0+1−αˉtε with ε∼N(0,I).
What is the variance β~t of the forward posterior q(xt−1∣xt,x0)?
β~t=1−αˉt1−αˉt−1βt, which is smaller than βt and is 0 at t=1.
Write the forward posterior mean μ~t in terms of xt and the noise ε.
μ~t=αt1(xt−1−αˉtβtε).
What is Lsimple?
Et,x0,ε∥ε−εθ(αˉtx0+1−αˉtε,t)∥2 with t uniform: the ELBO's ε-MSE terms with all weights set to 1.
Why does Lsimple give better samples than the ELBO?
It lowers the weight of small-t terms (removing tiny noise), which dominate the likelihood but barely affect samples, and moves effort to larger t, where structure is created.
Write one step of DDPM ancestral sampling.
xt−1=αt1(xt−1−αˉtβtεθ(xt,t))+σtz, with z∼N(0,I) for t>1 and z=0 at t=1.
For which data is σt2=β~t exact, and for which is σt2=βt exact?
β~t: data that are a single point. βt: unit-variance Gaussian data, x0∼N(0,I).
Why must the forward steps of DDPM be small?
Only for small steps is the true reverse conditional q(xt−1∣xt) close to Gaussian; for large steps it can be multimodal, and a Gaussian reverse step cannot fit it.
"Derive the DDPM loss." ELBO; rewrite q(x1:T∣x0) with forward posteriors (the ratios
telescope); KL between Gaussians; ε-form of the mean; drop the weights.
"Why predict the noise and not the mean?" With the ε-form, the KL becomes an ε-MSE with a
unit-scale target at every t: denoising score matching. Ho et al. (Table 2) report that predicting
μ~t directly works only with the true bound, and that training it with an unweighted MSE was unstable.
"Why 1000 steps?" A Gaussian reverse step is accurate only for small steps.
"Is DDPM a VAE?" A hierarchical VAE with a fixed encoder, latents of the data dimension, and one
decoder network shared across steps (it takes t as input).
"What does σt2 change?" Almost nothing for samples with T=1000; it matters for the
likelihood. β~t is exact for a point mass, βt for N(0,I) data.
"How do you get xt during training?" In one line from x0 and one Gaussian draw (Theorem 1);
the chain is never run during training.
The forward and reverse processes, the closed-form marginal and the noise-prediction loss, with clear animations.
Open on YouTube · the player loads from youtube-nocookie.com when you press play
The full derivation of this lesson: the ELBO, its simplification into KL terms, and the step from the ELBO to an L2 loss.
Open on YouTube · the player loads from youtube-nocookie.com when you press play
A slower walk through the DDPM paper and its math, including the forward posterior.
Open on YouTube · the player loads from youtube-nocookie.com when you press play
The big picture of diffusion for images and video, with excellent visual intuition.
Open on YouTube · the player loads from youtube-nocookie.com when you press play
Ho, Jain and Abbeel, Denoising Diffusion Probabilistic Models
(2020): §2 (eqs. 1–7), §3.2 (eqs. 8–12 and the two choices of σt2), §3.4 (Lsimple),
Algorithms 1–2, Tables 1–2, Appendix A.