VerifiedarXiv:2006.1123925 min
Diffusion · Generative models

DDPM: Denoising Diffusion Probabilistic Models

Destroy an image with noise, then learn to reverse it.

A fixed process adds a little Gaussian noise to an image, 1000 times, until only static is left. A single network is trained to predict the noise in a partly noised image. Sampling starts from fresh static and uses that network 1000 times to remove noise step by step.

Explaining the paperDenoising Diffusion Probabilistic ModelsHo, Jain, Abbeel · UC Berkeley · NeurIPS 2020 · arXiv:2006.11239 ↗

Ho, Jain and Abbeel took a 2015 model class that had never produced good samples, reduced its training loss to a mean-squared error on Gaussian noise, and reached an FID of 3.17 on CIFAR-10.

In 2020 the sharpest generated images came from GANs (see the GAN explainer): a generator trained against a discriminator. GAN training is a two-player game with no single loss going down, and it often collapses onto a few kinds of output. Likelihood-based models (autoregressive models, normalizing flows, and variational autoencoders) train by minimizing one well-defined loss, but their samples were visibly worse. A third family, diffusion probabilistic models, had been proposed by Sohl-Dickstein et al. in 2015, and as this paper puts it, there had been no demonstration that they could generate high-quality samples.

The method has two halves. The forward half takes a training image and adds a small amount of Gaussian noise, then a little more, for 1000 steps, until it cannot be told apart from random static. This half has no parameters. The learned half is one neural network that takes a noisy image and the step number and predicts the noise that was added. To generate, start from pure static and apply that network 1000 times, each time subtracting a little of the predicted noise and adding back a smaller amount of fresh noise.

Five ideas explain why this works and why the loss is so short: the forward noising chain; a closed form that noises an image to any step in one draw; a reverse chain trained with a variational bound; the Gaussian target inside that bound, which is available only because the clean image is known during training; and the change of variables that turns the bound into a mean-squared error on noise. After those come sampling, the code, and the results. The headline result is an FID of 3.17 on unconditional CIFAR-10. FID (Fréchet Inception Distance) compares the statistics of generated and real images in the feature space of an image classifier; lower is better, and 3.17 was better than every unconditional model the paper compares against.

The forward process adds noise on a fixed schedule

Treat an image as a vector. A CIFAR-10 image is 32×32×332\times32\times3, so it is a vector x0\mathbf{x}_0 of D=3072D=3072 numbers, with pixel values in {0,…,255}\{0,\dots,255\} scaled linearly to [−1,1][-1,1]. The forward process (the paper also calls it the diffusion process) is a Markov chain x0→x1→⋯→xT\mathbf{x}_0 \to \mathbf{x}_1 \to \dots \to \mathbf{x}_T with T=1000T=1000 steps: each image in the chain is computed from the previous one alone. Each step is one Gaussian:

q(xt∣xt−1):=N ⁣(xt; 1−βt xt−1, βtI)q(\mathbf{x}_t \mid \mathbf{x}_{t-1}) := \mathcal{N}\!\big(\mathbf{x}_t;\ \sqrt{1-\beta_t}\,\mathbf{x}_{t-1},\ \beta_t\mathbf{I}\big)
(2)

One step scales the previous image down slightly, by 1−βt\sqrt{1-\beta_t}, then adds independent Gaussian noise with variance βt\beta_t to every pixel. The numbers β1,…,βT\beta_1,\dots,\beta_T are the variance schedule. DDPM fixes them in advance and never learns them: βt\beta_t rises linearly from β1=10−4\beta_1=10^{-4} to βT=0.02\beta_T=0.02. The paper chose these values to be small relative to data in [−1,1][-1,1], so that each reverse step stays close to Gaussian, while leaving as little signal as possible at xT\mathbf{x}_T. It set T=1000T=1000 without a sweep, so that sampling uses the same number of network evaluations as earlier work. The whole chain factors into those steps:

q(x1:T∣x0):=∏t=1Tq(xt∣xt−1)q(\mathbf{x}_{1:T} \mid \mathbf{x}_0) := \prod_{t=1}^{T} q(\mathbf{x}_t \mid \mathbf{x}_{t-1})

The scale factor 1−βt\sqrt{1-\beta_t} keeps the variance bounded. Suppose a pixel of xt−1\mathbf{x}_{t-1} has variance vv. After one step its variance is (1−βt) v+βt(1-\beta_t)\,v + \beta_t, which equals 1 when v=1v=1 and moves toward 1 from either side otherwise. Without the scale factor each step would add βt\beta_t and nothing would remove any, so after 1000 steps the variance would have grown by ∑tβt=10.05\sum_t\beta_t = 10.05 and the endpoint would depend on the schedule's total. With it, every image ends near the same distribution, a standard Gaussian N(0,I)\mathcal{N}(\mathbf{0},\mathbf{I}), which is where sampling will start. Later work named this shrink-then-add design "variance-preserving"; the name comes from Song et al.'s SDE paper, not from DDPM.

Drag the step below and watch a point cloud shaped like the letters "ip" shrink toward the origin while noise spreads it out. The two numbers in the corner are the signal and noise weights that the next section derives.

Figure 1 · the forward process
t = 1
Drag step t from 1 to 1000. The data points are scaled toward the origin and buried under Gaussian noise. At t = 1000 the cloud is indistinguishable from a standard Gaussian, whatever shape it started as.

Noising to any step in one draw

Training will need noisy images at randomly chosen steps, for example x700\mathbf{x}_{700}. Running 700 sequential steps for every training example would be slow. It is also unnecessary, because a chain of Gaussian steps composes into a single Gaussian. Define αt:=1−βt\alpha_t := 1-\beta_t, the per-step factor, and αˉt:=∏s=1tαs\bar\alpha_t := \prod_{s=1}^{t}\alpha_s, the running product. Then

q(xt∣x0)=N ⁣(xt; αˉt x0, (1−αˉt)I)q(\mathbf{x}_t \mid \mathbf{x}_0) = \mathcal{N}\!\big(\mathbf{x}_t;\ \sqrt{\bar\alpha_t}\,\mathbf{x}_0,\ (1-\bar\alpha_t)\mathbf{I}\big)
(4)

Two steps show where this comes from. Write each step with its own standard-normal noise:

x2=α2(α1 x0+β1 ϵ1)+β2 ϵ2=α1α2 x0+(α2β1 ϵ1+β2 ϵ2)\mathbf{x}_2 = \sqrt{\alpha_2}\big(\sqrt{\alpha_1}\,\mathbf{x}_0 + \sqrt{\beta_1}\,\boldsymbol{\epsilon}_1\big) + \sqrt{\beta_2}\,\boldsymbol{\epsilon}_2 = \sqrt{\alpha_1\alpha_2}\,\mathbf{x}_0 + \big(\sqrt{\alpha_2\beta_1}\,\boldsymbol{\epsilon}_1 + \sqrt{\beta_2}\,\boldsymbol{\epsilon}_2\big)x2=α2(α1 x0+β1 ϵ1)+β2 ϵ2=α1α2 x0+(α2β1 ϵ1+β2 ϵ2)\begin{aligned} \mathbf{x}_2 &= \sqrt{\alpha_2}\big(\sqrt{\alpha_1}\,\mathbf{x}_0 + \sqrt{\beta_1}\,\boldsymbol{\epsilon}_1\big) + \sqrt{\beta_2}\,\boldsymbol{\epsilon}_2 \\ &= \sqrt{\alpha_1\alpha_2}\,\mathbf{x}_0 + \big(\sqrt{\alpha_2\beta_1}\,\boldsymbol{\epsilon}_1 + \sqrt{\beta_2}\,\boldsymbol{\epsilon}_2\big) \end{aligned}

The signal coefficient is α1α2=αˉ2\sqrt{\alpha_1\alpha_2}=\sqrt{\bar\alpha_2}. The two noise terms are independent, so their variances add: α2β1+β2\alpha_2\beta_1+\beta_2. Substituting β=1−α\beta=1-\alpha gives

α2(1−α1)+(1−α2)=1−α1α2=1−αˉ2\alpha_2(1-\alpha_1) + (1-\alpha_2) = 1-\alpha_1\alpha_2 = 1-\bar\alpha_2

and the same substitution works at every further step, so the noise variance after tt steps is 1−αˉt1-\bar\alpha_t. In the form used in code, draw one ϵ\boldsymbol\epsilon and compute

xt=αˉt x0+1−αˉt ϵ,ϵ∼N(0,I)\mathbf{x}_t = \sqrt{\bar\alpha_t}\,\mathbf{x}_0 + \sqrt{1-\bar\alpha_t}\,\boldsymbol{\epsilon}, \qquad \boldsymbol{\epsilon}\sim\mathcal{N}(\mathbf{0},\mathbf{I})

The squares of the two weights, αˉt\bar\alpha_t and 1−αˉt1-\bar\alpha_t, always sum to 1. Their ratio αˉt/(1−αˉt)\bar\alpha_t/(1-\bar\alpha_t) is the signal-to-noise ratio (SNR). With the paper's schedule:

At t=1000t=1000 a pixel at +1 contributes 0.0064 to a sum whose noise has standard deviation 0.99998. The paper computes the leftover mismatch between q(xT∣x0)q(\mathbf{x}_T\mid\mathbf{x}_0) and N(0,I)\mathcal{N}(\mathbf{0},\mathbf{I}) as about 10−510^{-5} bits per dimension. Drag the step and read the SNR; notice that SNR 1 arrives at about a quarter of the chain, so most steps work on images that are more noise than signal.

Figure 2 · the noise schedule
SNR = 1.00
The signal weight √ᾱₜ falls from 1 toward 0 and the noise weight √(1−ᾱₜ) rises. They cross near t ≈ 259, where the SNR is 1. Drag step t to read the SNR at any step: about 8.7 at t = 100, 0.085 at t = 500.

For training, (4) turns "noise this image to step 700" into one multiply-add over 3072 numbers with αˉ700\bar\alpha_{700} read from a precomputed table of 1000 values.

The reverse process and the bound that trains it

Generation runs the chain the other way: start at xT∼N(0,I)\mathbf{x}_T\sim\mathcal{N}(\mathbf{0},\mathbf{I}) and step down to x0\mathbf{x}_0. The exact reverse step q(xt−1∣xt)q(\mathbf{x}_{t-1}\mid\mathbf{x}_t) is unknown. To compute it you would have to average over every clean image that could have produced xt\mathbf{x}_t, weighted by how likely each is, and that requires the data distribution the model is trying to learn.

DDPM approximates each reverse step with a Gaussian. The justification is a result the paper takes from Sohl-Dickstein et al.: when every βt\beta_t is small, the forward and reverse processes have the same functional form, so the true reverse step is close to Gaussian. The largest βt\beta_t here is 0.02. The reverse chain, or reverse process, is

pθ(x0:T):=p(xT)∏t=1Tpθ(xt−1∣xt),pθ(xt−1∣xt):=N ⁣(xt−1; μθ(xt,t), Σθ(xt,t))p_\theta(\mathbf{x}_{0:T}) := p(\mathbf{x}_T)\prod_{t=1}^{T} p_\theta(\mathbf{x}_{t-1}\mid\mathbf{x}_t), \qquad p_\theta(\mathbf{x}_{t-1}\mid\mathbf{x}_t) := \mathcal{N}\!\big(\mathbf{x}_{t-1};\ \boldsymbol{\mu}_\theta(\mathbf{x}_t,t),\ \boldsymbol{\Sigma}_\theta(\mathbf{x}_t,t)\big)pθ(x0:T):=p(xT)∏t=1Tpθ(xt−1∣xt),pθ(xt−1∣xt):=N ⁣(xt−1; μθ(xt,t), Σθ(xt,t))\begin{aligned} p_\theta(\mathbf{x}_{0:T}) &:= p(\mathbf{x}_T)\prod_{t=1}^{T} p_\theta(\mathbf{x}_{t-1}\mid\mathbf{x}_t), \\ p_\theta(\mathbf{x}_{t-1}\mid\mathbf{x}_t) &:= \mathcal{N}\!\big(\mathbf{x}_{t-1};\ \boldsymbol{\mu}_\theta(\mathbf{x}_t,t),\ \boldsymbol{\Sigma}_\theta(\mathbf{x}_t,t)\big) \end{aligned}
(1)

with p(xT)=N(0,I)p(\mathbf{x}_T)=\mathcal{N}(\mathbf{0},\mathbf{I}). A network computes the mean μθ\boldsymbol\mu_\theta. DDPM does not learn the covariance: it sets Σθ=σt2I\boldsymbol\Sigma_\theta=\sigma_t^2\mathbf{I} with σt2\sigma_t^2 a fixed number per step, because learning it made training unstable and samples worse; the two fixed values it uses appear in the sampling section.

Training uses the same tool as a variational autoencoder. The noisy images x1:T\mathbf{x}_{1:T} play the role of latent variables, the forward process plays the role of the encoder (fixed, with no parameters), and the reverse process is the decoder. Jensen's inequality gives an upper bound on the negative log-likelihood, which training minimizes:

E ⁣[−log⁡pθ(x0)]≤Eq ⁣[−log⁡pθ(x0:T)q(x1:T∣x0)]=:L\mathbb{E}\!\left[-\log p_\theta(\mathbf{x}_0)\right] \le \mathbb{E}_q\!\left[-\log \frac{p_\theta(\mathbf{x}_{0:T})}{q(\mathbf{x}_{1:T}\mid\mathbf{x}_0)}\right] =: L
(3)

Minimizing LL is the same as maximizing the evidence lower bound (ELBO) of a VAE; only the sign differs. Both chains factor over steps, and after a rewrite with Bayes' rule (the paper's Appendix A, from Sohl-Dickstein et al.) the bound splits into one term per step. Each term is a KL divergence DKLD_{\mathrm{KL}}, a measure of how far one distribution is from another that is zero only when the two match:

L=Eq[DKL ⁣(q(xT∣x0) ∥ p(xT))⏟LT+∑t>1DKL ⁣(q(xt−1∣xt,x0) ∥ pθ(xt−1∣xt))⏟Lt−1  − log⁡pθ(x0∣x1)⏟L0]L = \mathbb{E}_q\Big[\underbrace{D_{\mathrm{KL}}\!\big(q(\mathbf{x}_T\mid\mathbf{x}_0)\,\|\,p(\mathbf{x}_T)\big)}_{L_T} + \sum_{t>1}\underbrace{D_{\mathrm{KL}}\!\big(q(\mathbf{x}_{t-1}\mid\mathbf{x}_t,\mathbf{x}_0)\,\|\,p_\theta(\mathbf{x}_{t-1}\mid\mathbf{x}_t)\big)}_{L_{t-1}} \;\underbrace{-\,\log p_\theta(\mathbf{x}_0\mid\mathbf{x}_1)}_{L_0}\Big]L=Eq[DKL ⁣(q(xT∣x0) ∥ p(xT))⏟LT+∑t>1DKL ⁣(q(xt−1∣xt,x0) ∥ pθ(xt−1∣xt))⏟Lt−1− log⁡pθ(x0∣x1)⏟L0]\begin{aligned} L = \mathbb{E}_q\Big[&\underbrace{D_{\mathrm{KL}}\!\big(q(\mathbf{x}_T\mid\mathbf{x}_0)\,\|\,p(\mathbf{x}_T)\big)}_{L_T} \\ &+ \sum_{t>1}\underbrace{D_{\mathrm{KL}}\!\big(q(\mathbf{x}_{t-1}\mid\mathbf{x}_t,\mathbf{x}_0)\,\|\,p_\theta(\mathbf{x}_{t-1}\mid\mathbf{x}_t)\big)}_{L_{t-1}} \\ &\underbrace{-\,\log p_\theta(\mathbf{x}_0\mid\mathbf{x}_1)}_{L_0}\Big] \end{aligned}
(5)

LTL_T contains no parameters, since the forward process is fixed and p(xT)p(\mathbf{x}_T) is a fixed Gaussian; it is the 10−510^{-5} bits per dimension quoted above, a constant that training ignores. L0L_0 scores the last step as a discrete decoder that assigns probability to each of the 256 pixel values (the paper's equation (13)). The remaining 999 terms each compare the model's reverse step with q(xt−1∣xt,x0)q(\mathbf{x}_{t-1}\mid\mathbf{x}_t,\mathbf{x}_0): the reverse step of the forward process when the clean image is also given. Conditioning on x0\mathbf{x}_0 makes the target computable, as the next section shows.

The target: the reverse step given x₀

Given both the clean image x0\mathbf{x}_0 and the noisy xt\mathbf{x}_t, the distribution of the in-between xt−1\mathbf{x}_{t-1} is proportional to q(xt∣xt−1) q(xt−1∣x0)q(\mathbf{x}_t\mid\mathbf{x}_{t-1})\,q(\mathbf{x}_{t-1}\mid\mathbf{x}_0), a product of two Gaussians in xt−1\mathbf{x}_{t-1}, so it is itself Gaussian. This forward-process posterior is

q(xt−1∣xt,x0)=N ⁣(xt−1; μ~t(xt,x0), β~tI)q(\mathbf{x}_{t-1}\mid\mathbf{x}_t,\mathbf{x}_0) = \mathcal{N}\!\big(\mathbf{x}_{t-1};\ \tilde{\boldsymbol{\mu}}_t(\mathbf{x}_t,\mathbf{x}_0),\ \tilde{\beta}_t\mathbf{I}\big)
(6)
μ~t(xt,x0):=αˉt−1 βt1−αˉt x0+αt (1−αˉt−1)1−αˉt xt,β~t:=1−αˉt−11−αˉt βt\tilde{\boldsymbol{\mu}}_t(\mathbf{x}_t,\mathbf{x}_0) := \frac{\sqrt{\bar{\alpha}_{t-1}}\,\beta_t}{1-\bar{\alpha}_t}\,\mathbf{x}_0 + \frac{\sqrt{\alpha_t}\,(1-\bar{\alpha}_{t-1})}{1-\bar{\alpha}_t}\,\mathbf{x}_t, \qquad \tilde{\beta}_t := \frac{1-\bar{\alpha}_{t-1}}{1-\bar{\alpha}_t}\,\beta_tμ~t(xt,x0):=αˉt−1 βt1−αˉt x0+αt (1−αˉt−1)1−αˉt xt,β~t:=1−αˉt−11−αˉt βt\begin{aligned} \tilde{\boldsymbol{\mu}}_t(\mathbf{x}_t,\mathbf{x}_0) &:= \frac{\sqrt{\bar{\alpha}_{t-1}}\,\beta_t}{1-\bar{\alpha}_t}\,\mathbf{x}_0 + \frac{\sqrt{\alpha_t}\,(1-\bar{\alpha}_{t-1})}{1-\bar{\alpha}_t}\,\mathbf{x}_t, \\ \tilde{\beta}_t &:= \frac{1-\bar{\alpha}_{t-1}}{1-\bar{\alpha}_t}\,\beta_t \end{aligned}
(7)

The mean is a weighted sum of the clean image and the noisy one. The xt\mathbf{x}_t coefficient uses the per-step αt\sqrt{\alpha_t}, the x0\mathbf{x}_0 coefficient uses the cumulative αˉt−1\sqrt{\bar\alpha_{t-1}}. With the paper's schedule:

With the model's variance fixed at σt2\sigma_t^2, the KL divergence between two Gaussians in (5) reduces to a scaled squared distance between their means, plus a constant CC that does not depend on θ\theta:

Lt−1=Eq ⁣[12σt2∥μ~t(xt,x0)−μθ(xt,t)∥2]+CL_{t-1} = \mathbb{E}_q\!\left[\frac{1}{2\sigma_t^2}\big\lVert \tilde{\boldsymbol{\mu}}_t(\mathbf{x}_t,\mathbf{x}_0) - \boldsymbol{\mu}_\theta(\mathbf{x}_t,t)\big\rVert^2\right] + C
(8)

Equation (8) is a regression: the network sees xt\mathbf{x}_t and tt, and its output is scored against a target that also depends on x0\mathbf{x}_0, which the network never sees. At sampling time there is no x0\mathbf{x}_0. For squared-error regression, the loss at each input is minimized by the average of the targets that occur with that input. Many clean images could have produced a given xt\mathbf{x}_t. Averaging μ~t(xt,x0)\tilde{\boldsymbol\mu}_t(\mathbf{x}_t,\mathbf{x}_0) over them, weighted by q(x0∣xt)q(\mathbf{x}_0\mid\mathbf{x}_t), gives exactly the mean of the true reverse step, because

q(xt−1∣xt)=Eq(x0∣xt)[ q(xt−1∣xt,x0) ]q(\mathbf{x}_{t-1}\mid\mathbf{x}_t) = \mathbb{E}_{q(\mathbf{x}_0\mid\mathbf{x}_t)}\big[\,q(\mathbf{x}_{t-1}\mid\mathbf{x}_t,\mathbf{x}_0)\,\big]

So the network is trained with targets it can compute only because x0\mathbf{x}_0 is known, and it converges toward a step that does not need x0\mathbf{x}_0. The true reverse step is a mixture of Gaussians, one per possible clean image, and the model step is a single Gaussian with the mixture's mean. The figure makes this exact on a dataset with two points, x0=−1x_0=-1 and x0=+1x_0=+1, in one dimension. It shows the two conditional Gaussians (6), each scaled by how likely its x0x_0 is given xtx_t, their sum, which is the true reverse step, and the single Gaussian a DDPM step can represent. The jump slider generalizes (6) from a one-step jump to a kk-step jump, from tt to s=t−ks=t-k, using the same formula with αˉs\bar\alpha_s and αˉt/αˉs\bar\alpha_t/\bar\alpha_s in place of αˉt−1\bar\alpha_{t-1} and αt\alpha_t.

Figure 3 · one reverse step, exactly
t = 500
k = 1
0.35
At the default (t = 500, jump k = 1) the two conditional Gaussians are 0.006 apart with standard deviation 0.10, so the true step is one Gaussian and the model step matches it. Raise jump k: as the jump's endpoint s nears 0, the true step splits into two bumps near −1 and +1, and the Gaussian with the same mean sits between them. Move noisy xₜ to shift the weights p(x₀ | xₜ).

The overlap readout measures how much probability the Gaussian model step shares with the true step. With k=1k=1 it stays near 100% at every tt and xtx_t, which is the small-β\beta argument for a Gaussian reverse step, checked numerically. From t=500t=500 at the default xtx_t, a 100-step jump still overlaps 96%, a 250-step jump 79%, a jump to s=100s=100 21%, and a jump to s=1s=1 0%. Jumps that stay at high noise remain nearly Gaussian (from t=1000t=1000 to s=645s=645 the overlap is above 99%), because both data points are still buried in noise there. The Gaussian form fails when one step spans the range of noise levels over which the data points become distinguishable, which is why DDPM keeps all 1000 small steps.

Predicting the noise instead of the mean

The most direct choice is a network that outputs μ~t\tilde{\boldsymbol\mu}_t. The paper instead rewrites the target in terms of the noise. From (4), the clean image is determined by xt\mathbf{x}_t and the noise that was added:

x0=1αˉt(xt−1−αˉt ϵ)\mathbf{x}_0 = \frac{1}{\sqrt{\bar\alpha_t}}\big(\mathbf{x}_t - \sqrt{1-\bar\alpha_t}\,\boldsymbol{\epsilon}\big)

Substitute this into μ~t\tilde{\boldsymbol\mu}_t from (7). Two terms now multiply xt\mathbf{x}_t, and their coefficients add to (βt+αt(1−αˉt−1))/(αt(1−αˉt))\big(\beta_t+\alpha_t(1-\bar\alpha_{t-1})\big)/\big(\sqrt{\alpha_t}(1-\bar\alpha_t)\big). The numerator is 1−αt+αt−αˉt=1−αˉt1-\alpha_t+\alpha_t-\bar\alpha_t=1-\bar\alpha_t, which cancels the denominator's 1−αˉt1-\bar\alpha_t and leaves 1/αt1/\sqrt{\alpha_t}. The target mean becomes 1αt(xt−βt1−αˉtϵ)\tfrac{1}{\sqrt{\alpha_t}}\big(\mathbf{x}_t-\tfrac{\beta_t}{\sqrt{1-\bar\alpha_t}}\boldsymbol\epsilon\big), and the only unknown in it is ϵ\boldsymbol\epsilon. So DDPM trains a network ϵθ(xt,t)\boldsymbol{\epsilon}_\theta(\mathbf{x}_t,t) to predict the noise and assembles the mean from it:

μθ(xt,t)=1αt ⁣(xt−βt1−αˉt ϵθ(xt,t))\boldsymbol{\mu}_\theta(\mathbf{x}_t,t) = \frac{1}{\sqrt{\alpha_t}}\!\left(\mathbf{x}_t - \frac{\beta_t}{\sqrt{1-\bar{\alpha}_t}}\,\boldsymbol{\epsilon}_\theta(\mathbf{x}_t,t)\right)
(11)

At t=500t=500 this reads μθ=1.00506 (xt−0.01046 ϵθ)\boldsymbol\mu_\theta = 1.00506\,(\mathbf{x}_t - 0.01046\,\boldsymbol\epsilon_\theta): subtract about 1% of the predicted noise vector, then undo that step's shrink by multiplying by 1/α5001/\sqrt{\alpha_{500}}. The prefactor uses the per-step αt\alpha_t; the noise coefficient uses the cumulative αˉt\bar\alpha_t, because ϵθ\boldsymbol\epsilon_\theta estimates all of the noise accumulated since x0\mathbf{x}_0, and a single step removes only its share.

Predicting ϵ\boldsymbol\epsilon, predicting x0\mathbf{x}_0, and predicting μ~t\tilde{\boldsymbol\mu}_t carry the same information once xt\mathbf{x}_t is known. The figure draws (4) for a single point: the clean x0\mathbf{x}_0 is scaled to αˉt x0\sqrt{\bar\alpha_t}\,\mathbf{x}_0, and the noise arrow 1−αˉt ϵ\sqrt{1-\bar\alpha_t}\,\boldsymbol\epsilon carries it to xt\mathbf{x}_t. The network's output is ϵ\boldsymbol\epsilon, that arrow's direction and length before scaling.

Figure 4 · the noise-prediction target
t = 300
The clean x₀ is scaled to √ᾱₜ·x₀, then the added noise √(1−ᾱₜ)·ε moves it to xₜ. Drag step t: the same ε produces a short arrow at small t and a long one at large t, while the signal point slides toward the origin.

Substituting (11) into (8) gives a squared error between the true and predicted noise, with a weight that depends on tt:

Lt−1−C=Ex0,ϵ ⁣[βt22σt2 αt (1−αˉt) ∥ϵ−ϵθ(αˉt x0+1−αˉt ϵ, t)∥2]L_{t-1} - C = \mathbb{E}_{\mathbf{x}_0,\boldsymbol\epsilon}\!\left[\frac{\beta_t^2}{2\sigma_t^2\,\alpha_t\,(1-\bar\alpha_t)}\,\big\lVert \boldsymbol\epsilon - \boldsymbol\epsilon_\theta\big(\sqrt{\bar\alpha_t}\,\mathbf{x}_0+\sqrt{1-\bar\alpha_t}\,\boldsymbol\epsilon,\ t\big)\big\rVert^2\right]Lt−1−C=Ex0,ϵ ⁣[βt22σt2 αt (1−αˉt)∥ϵ−ϵθ(αˉt x0+1−αˉt ϵ, t)∥2]L_{t-1} - C = \mathbb{E}_{\mathbf{x}_0,\boldsymbol\epsilon}\!\left[\begin{aligned}&\frac{\beta_t^2}{2\sigma_t^2\,\alpha_t\,(1-\bar\alpha_t)} \\ &\big\lVert \boldsymbol\epsilon - \boldsymbol\epsilon_\theta\big(\sqrt{\bar\alpha_t}\,\mathbf{x}_0+\sqrt{1-\bar\alpha_t}\,\boldsymbol\epsilon,\ t\big)\big\rVert^2\end{aligned}\right]
(12)

The paper's main training objective drops that weight:

Lsimple(θ):=Et, x0, ϵ ⁣[∥ϵ−ϵθ(αˉt x0+1−αˉt ϵ, t)∥2]L_{\text{simple}}(\theta) := \mathbb{E}_{t,\,\mathbf{x}_0,\,\boldsymbol{\epsilon}}\!\left[\big\lVert \boldsymbol{\epsilon} - \boldsymbol{\epsilon}_\theta\big(\sqrt{\bar{\alpha}_t}\,\mathbf{x}_0 + \sqrt{1-\bar{\alpha}_t}\,\boldsymbol{\epsilon},\ t\big)\big\rVert^2\right]
(14)

with tt uniform on {1,…,1000}\{1,\dots,1000\}. A training step samples an image, a step and a noise vector, builds xt\mathbf{x}_t with one use of (4), and regresses the network's output onto the noise. Nothing is sampled from the model during training, and no chain is unrolled. The regression target ϵ\boldsymbol\epsilon has unit variance at every tt, so the network's output has the same scale at every noise level. A μ~t\tilde{\boldsymbol\mu}_t target is nearly a copy of the input (at t=500t=500 it is 0.9941 xt+0.0031 x00.9941\,\mathbf{x}_t+0.0031\,\mathbf{x}_0), so the informative part of the output would be a small correction on top of that copy. The authors also tried predicting x0\mathbf{x}_0 and found it gave worse samples early in their experiments.

The ε-parameterization also connects DDPM to score-based models. The score of a density is the gradient of its log, which points toward higher probability. From (4), ∇xtlog⁡q(xt∣x0)=−ϵ/1−αˉt\nabla_{\mathbf{x}_t}\log q(\mathbf{x}_t\mid\mathbf{x}_0) = -\boldsymbol\epsilon/\sqrt{1-\bar\alpha_t}, so ϵ\boldsymbol\epsilon points away from the clean image and −ϵθ/1−αˉt-\boldsymbol\epsilon_\theta/\sqrt{1-\bar\alpha_t} estimates the score of the noisy data. That the least-squares denoiser recovers the score of the noisy density is Tweedie's formula (Robbins, 1956); DDPM does not cite it. The paper's own statement is that (12) resembles denoising score matching over multiple noise scales indexed by tt (training a network on noised data to output the score of the noised density), the objective of Song and Ermon's NCSN, and that its sampler resembles Langevin dynamics (repeatedly stepping along the score and adding noise) with ϵθ\boldsymbol\epsilon_\theta as a learned gradient of the data density.

What dropping the weights changes

With σt2=βt\sigma_t^2=\beta_t, the weight in (12) simplifies to wt=βt/(2αt(1−αˉt))w_t = \beta_t/\big(2\alpha_t(1-\bar\alpha_t)\big). It is largest at the start of the chain, where 1−αˉt1-\bar\alpha_t is tiny: w2=0.273w_2=0.273, w100=0.0101w_{100}=0.0101, a minimum of 0.00497 near t=349t=349, and w1000=0.0102w_{1000}=0.0102. Step 2 is weighted 27 times more than step 1000. The true bound therefore spends much of its training signal on steps where the image has almost no noise, and LsimpleL_{\text{simple}} spreads it evenly.

The figure plots the cumulative share of the weight held by steps 2 through a cutoff cc (step 1 is the decoder term L0L_0 and is left out). At c=100c=100, 10% of the steps, the bound puts 34.1% of its weight there with σt2=βt\sigma_t^2=\beta_t and 39.2% with σt2=β~t\sigma_t^2=\tilde\beta_t; LsimpleL_{\text{simple}} puts 9.9% there, the share of steps.

Figure 5 · where the loss puts its weight
c = 100
The variational bound (12) rises steeply at small t; L_simple (14) is the diagonal. Drag cutoff c to read the two shares, and switch the tab to see that the choice of σₜ² changes the bound's curve only slightly.

The paper's explanation: the small-tt terms train the network to remove very small amounts of noise, so down-weighting them lets the network focus on the more difficult denoising tasks at larger tt. The paper calls LsimpleL_{\text{simple}} a weighted variational bound; it is no longer the tightest bound on likelihood. The ablation on CIFAR-10 (Table 2, Inception Score / FID) measures both effects. Fixed isotropic Σ\boldsymbol\Sigma means σt2I\sigma_t^2\mathbf{I} with a constant σt2\sigma_t^2:

Predicting μ~\tilde{\boldsymbol\mu} works only on the true bound; predicting ε works on the true bound and works much better on LsimpleL_{\text{simple}}. The likelihood moves the other way. The LsimpleL_{\text{simple}} model's negative log-likelihood is at most 3.75 bits per dimension on the test set; the model trained on the true bound reaches at most 3.70. FID drops from 13.51 to 3.17 for a 0.05 bits/dim loss in likelihood.

Sampling with Algorithm 2

To generate an image, draw xT∼N(0,I)\mathbf{x}_T\sim\mathcal{N}(\mathbf{0},\mathbf{I}) and for t=T,…,1t=T,\dots,1 compute the mean (11) from the network's noise prediction and add fresh noise:

xt−1=1αt ⁣(xt−1−αt1−αˉt ϵθ(xt,t))+σt z,z∼N(0,I) if t>1, else z=0\mathbf{x}_{t-1} = \frac{1}{\sqrt{\alpha_t}}\!\left(\mathbf{x}_t - \frac{1-\alpha_t}{\sqrt{1-\bar{\alpha}_t}}\,\boldsymbol{\epsilon}_\theta(\mathbf{x}_t,t)\right) + \sigma_t\,\mathbf{z}, \qquad \mathbf{z}\sim\mathcal{N}(\mathbf{0},\mathbf{I})\ \text{if } t>1,\ \text{else } \mathbf{z}=\mathbf{0}xt−1=1αt ⁣(xt−1−αt1−αˉt ϵθ(xt,t))+σt z,z∼N(0,I) if t>1, else z=0\begin{gathered} \mathbf{x}_{t-1} = \frac{1}{\sqrt{\alpha_t}}\!\left(\mathbf{x}_t - \frac{1-\alpha_t}{\sqrt{1-\bar{\alpha}_t}}\,\boldsymbol{\epsilon}_\theta(\mathbf{x}_t,t)\right) + \sigma_t\,\mathbf{z}, \\ \mathbf{z}\sim\mathcal{N}(\mathbf{0},\mathbf{I})\ \text{if } t>1,\ \text{else } \mathbf{z}=\mathbf{0} \end{gathered}

The coefficient 1−αt1-\alpha_t is βt\beta_t, so the first term is (11). The last step adds no noise and returns the mean. For σt2\sigma_t^2 the paper tried two values and found similar results: σt2=βt\sigma_t^2=\beta_t, which is optimal if the data were a standard Gaussian, and σt2=β~t\sigma_t^2=\tilde\beta_t, which is optimal if the data were a single fixed point. The two are nearly equal for most of the chain (0.01004 and 0.01003 at t=500t=500).

At any step the sampler also has an estimate of the final image. Rearranging (4) with the predicted noise gives

x^0=1αˉt(xt−1−αˉt ϵθ(xt))\hat{\mathbf{x}}_0 = \frac{1}{\sqrt{\bar\alpha_t}}\big(\mathbf{x}_t - \sqrt{1-\bar\alpha_t}\,\boldsymbol\epsilon_\theta(\mathbf{x}_t)\big)
(15)

which the paper tracks while sampling CIFAR-10 images: large-scale features appear first and details appear last. Early in the chain xt\mathbf{x}_t is mostly noise, so the best estimate is an average over many possible images; each step narrows that set.

The figure runs Algorithm 2 on six points in 2D, arranged as two groups of three. In place of a trained network it uses the exact optimal noise predictor for this dataset, so any failure in the figure comes from the sampler, not from training error. The default view is the end of a 1000-step run; press Play to watch it from xT\mathbf{x}_T, and turn on show x̂₀ to see each particle's current estimate (15). The estimates first sit at the centre of the data, then split into the left and right groups, then separate into single points.

Figure 6 · Algorithm 2, step by step
100%
T = 1000
Press Play or drag the scrubber. Particles start as Gaussian noise and end on the data points; the readout reports how many land on one. Drag steps T down to 10, 2 and 1, and switch to no noise, to see the two ways this sampler fails.

The step-count slider compares models with different TT. Each uses the paper's αˉ\bar\alpha curve sampled at TT evenly spaced points, which amounts to a separately trained model per TT; an exact predictor makes that free in the toy. With T=1000T=1000 every particle lands on a data point and all six are reached. With T=10T=10 about 80% land on one. With T=1T=1 every particle lands at the same place near the centre: one step from pure noise returns x^0\hat{\mathbf{x}}_0 at t=1000t=1000, where xT\mathbf{x}_T carries almost no information, so the estimate is the average of the data. Large jumps fail for the reason Figure 3 shows: the true reverse step becomes multimodal, and a Gaussian with the right mean puts its mass between the modes.

Set σt=0\sigma_t=0 and keep all 1000 steps, and every particle ends on one of the two inner points; the four outer points get none. Each mean step pulls particles toward the current x^0\hat{\mathbf{x}}_0 and removes some of their spread, and σtz\sigma_t\mathbf{z} puts back the spread that the true reverse step has. Without it the cloud contracts toward the centre while x^0\hat{\mathbf{x}}_0 is still the average of all six points, and by the time the points are distinguishable every particle is closest to an inner one. The DDIM sampler reaches a deterministic update by changing the coefficients as well as setting the noise to zero, which is a different update from this one.

Each step is one network call and the steps are sequential, so an image costs 1000 forward passes. The paper reports 17 seconds for a batch of 256 CIFAR-10 images and 300 seconds for a batch of 128 images at 256×256256\times256, on a TPU v3-8 (similar to 8 V100 GPUs). A GAN produces a batch in one forward pass.

Training and sampling in code

The network ϵθ\boldsymbol\epsilon_\theta is a U-Net similar to an unmasked PixelCNN++, built from Wide ResNet blocks with group normalization and self-attention at the 16×1616\times16 resolution. It takes a 3×32×323\times32\times32 noisy image and returns a tensor of the same shape, one noise estimate per pixel value. The same weights serve every step; the step tt enters as the sinusoidal position embedding from the Transformer, added inside each residual block. The CIFAR-10 model has 35.7 million parameters, and the LSUN and CelebA-HQ models have 114 million.

Take one CIFAR-10 image, 3072 values in [−1,1][-1,1], and suppose the sampled step is t=400t=400. The table gives αˉ400≈0.195\bar\alpha_{400}\approx0.195, so the signal weight is 0.44 and the noise weight is 0.90: x400=0.44 x0+0.90 ϵ\mathbf{x}_{400}=0.44\,\mathbf{x}_0+0.90\,\boldsymbol\epsilon, already mostly noise. The U-Net receives (x400,400)(\mathbf{x}_{400}, 400) and returns 3072 numbers; the loss is their mean squared difference from ϵ\boldsymbol\epsilon. The gradient flows into the U-Net's weights only; x400\mathbf{x}_{400} is data, built without any parameters. In a batch, every image gets its own tt and ϵ\boldsymbol\epsilon:

# Algorithm 1: one training step (batch of B images, D = 3072 values each)
x0   = next_batch()                    # (B, 3, 32, 32), scaled to [-1, 1]
t    = randint(1, T + 1, size=B)       # one uniform step per image
eps  = randn_like(x0)                  # the target
a    = abar[t].view(B, 1, 1, 1)        # abar precomputed for t = 1..1000
xt   = sqrt(a) * x0 + sqrt(1 - a) * eps          # eq (4); no gradient here
loss = ((eps - eps_theta(xt, t)) ** 2).mean()   # L_simple, eq (14)
loss.backward()                        # gradient reaches eps_theta's weights only
opt.step(); ema.update()               # Adam at 2e-4, EMA decay 0.9999

The settings from the paper's Appendix B: Adam at learning rate 2×10−42\times10^{-4} for CIFAR-10 (2×10−52\times10^{-5} at 256×256256\times256), batch size 128 (64 at 256×256256\times256), an exponential moving average of the weights with decay 0.9999, dropout 0.1 on CIFAR-10, and random horizontal flips on every dataset except LSUN Bedroom. The CIFAR-10 model trains at 21 steps per second and reaches 800k steps in 10.6 hours on the TPU v3-8. Reported scores come from the checkpoint with the lowest FID during training.

# Algorithm 2: sampling (1000 sequential network calls)
x = randn(B, 3, 32, 32)                          # x_T ~ N(0, I)
for t in range(T, 0, -1):                        # t = 1000, 999, ..., 1
    e    = eps_theta(x, t)                       # predicted noise
    mean = (x - beta[t] / sqrt(1 - abar[t]) * e) / sqrt(alpha[t])  # eq (11)
    z    = randn_like(x) if t > 1 else 0         # no noise on the last step
    x    = mean + sqrt(sigma2[t]) * z            # sigma2 = beta or beta_tilde
return x                                         # x_0, a new image

The released TensorFlow sampler differs from this listing in one respect. It converts the predicted noise into x^0\hat{\mathbf{x}}_0 with (15), clips x^0\hat{\mathbf{x}}_0 to [−1,1][-1,1], and then takes the posterior mean (7) at the clipped value. When the clip changes nothing this is the same as (11); when the network predicts an out-of-range image, the code pulls it back into range and Algorithm 2 does not.

Every step above scales and adds real-valued vectors, so DDPM applies to continuous data. The paper uses only images: CIFAR-10 at 32×3232\times32, and CelebA-HQ and LSUN Bedroom, Church and Cat at 256×256256\times256. Discrete data such as text does not fit directly: adding 0.3 to token id 4017 does not give a token. Diffusion models for language diffuse a continuous embedding of the tokens or define a discrete corruption process instead; both are later work.

Results: sharp samples, average likelihood

On unconditional CIFAR-10 the LsimpleL_{\text{simple}} model reaches an Inception Score of 9.46 (a score for how confidently and how diversely an ImageNet classifier labels the samples; higher is better) and an FID of 3.17. The paper computes FID against the training set, as is standard; against the test set the score is 5.24. The paper reports 3.17 as state of the art for unconditional generation and says the model beats most models in the literature, including class-conditional ones. In its Table 1, unconditional StyleGAN2 with ADA scores 3.26; the class-conditional StyleGAN2 with ADA scores 2.67 and is better than DDPM.

At 256×256256\times256, the paper describes LSUN sample quality as similar to ProgressiveGAN. Its Table 3 gives FIDs of 6.36 on LSUN Bedroom (4.90 for a larger 256-million-parameter model), 7.89 on Church and 19.75 on Cat, against 8.34, 6.42 and 37.52 for ProgressiveGAN; StyleGAN2 scores 3.86 on Church and 6.93 on Cat. CelebA-HQ appears only as samples.

As a likelihood model DDPM is not competitive. Bits per dimension is the average number of bits needed to encode one pixel value under the model, so lower is better. At 3.75 bits per dimension (an upper bound, from (5)) it beats the estimates reported for energy-based models and score matching but trails the best autoregressive models and flows. The paper splits the codelength of its best model into a rate (bits transmitted by the reverse steps) of 1.78 bits/dim and a distortion of 1.97 bits/dim, where the distortion corresponds to an RMSE of 0.95 on the 0 to 255 pixel scale. More than half of the lossless codelength therefore describes differences too small to see. Its rate-distortion table shows where the bits go during sampling: after 900 of the 1000 reverse steps the rate is 0.12 bits/dim and the RMSE is 12.0; the last 100 steps add 1.66 bits/dim to bring the RMSE down to 0.95.

The 1000 sequential network calls set the agenda for the next few years. DDIM reused a trained DDPM with a sampler that skips steps, matching 1000-step quality in 20 to 100 steps. Dhariwal and Nichol improved the architecture and added classifier guidance, and classifier-free guidance removed the classifier. Latent diffusion ran the same process in the compressed latent space of an autoencoder to cut the cost of each step, which is the basis of Stable Diffusion. Song et al. recast the discrete chain as a stochastic differential equation, with DDPM's forward process as its variance-preserving case.

Provenance Verified against primary literatureHow we verify
DDPM (Ho, Jain, Abbeel, 2020)The closed-form marginal (4) with ᾱ notation, the ε-parameterization (11), L_simple (14), the fixed reverse variances and fixed linear schedule, Algorithms 1 and 2, and all CIFAR-10, LSUN and CelebA-HQ results. Checked against arXiv v2 and the NeurIPS 2020 proceedings.
Official codehojonathanho/diffusion (TensorFlow). diffusion_utils_2.py: linear β schedule (get_beta_schedule, line 27), posterior coefficients of (7) (lines 80–81), x̂₀ from ε and its clip to [−1, 1] (lines 151, 159–160). scripts/run_cifar.py:136 sets model_var_type fixedlarge (σₜ² = βₜ); the LSUN and CelebA-HQ scripts use diffusion_utils.py, whose sampler returns the posterior variance β̃ₜ (line 174).
Sohl-Dickstein et al. (2015)The diffusion probabilistic model, the same single-step forward kernel, and the bound (5). That paper learns the reverse mean and covariance and learns β₂…β_T; DDPM fixes the variances and the schedule.
Song & Ermon (2019)Denoising score matching over many noise levels, sampled with annealed Langevin dynamics. DDPM shows its ε-objective (12) resembles this and its sampler resembles Langevin dynamics.
Robbins (1956), "Tweedie’s formula"The optimal Gaussian denoiser is determined by the score of the noisy density. This page uses it to connect ε-prediction and the score; DDPM itself never names it.
Song et al. (2021)The name "variance-preserving" for the shrink-then-add forward process. The name does not appear in DDPM.
correctionPaper vs. code. Algorithm 2 computes the mean (11) directly from ε_θ. The released sampler (diffusion_utils_2.py, clip_denoised=True by default) instead forms x̂₀ = (xₜ − √(1−ᾱₜ)·ε_θ)/√ᾱₜ, clips it to [−1, 1], and returns the posterior mean (7) at the clipped x̂₀. That equals (11) only when the clip changes nothing, and Algorithm 2 has no clip. The sampling variance also differs by script: CIFAR-10 uses σₜ² = βₜ, LSUN and CelebA-HQ use σₜ² = β̃ₜ. An earlier version of this page said the code matches (11) and Algorithm 2 exactly and that the code samples with βₜ everywhere; both claims were too broad.

Questions you might still have

?

Why does x_T end up as plain N(0, I), whatever the image?
The closed form (4) multiplies the image by √ᾱₜ and adds noise of variance 1 − ᾱₜ. With the paper’s schedule ᾱ₁₀₀₀ ≈ 4.04×10⁻⁵, so √ᾱ₁₀₀₀ ≈ 0.0064: a pixel at +1 contributes 0.0064 against noise with standard deviation 0.99998. The KL between q(x_T | x₀) and N(0, I) is about 10⁻⁵ bits per dimension, which is why the paper treats L_T as a constant.

?

The training target uses the clean image. How can the sampler work without it?
The loss (8) is a squared error, and a squared-error regression learns the average of its targets. For a given noisy xₜ, the targets μ̃ₜ(xₜ, x₀) come from every clean image that could have produced xₜ, weighted by how likely each one is. That weighted average is the mean of the true reverse step q(xₜ₋₁ | xₜ), which needs no x₀. The same argument applies to ε: ε_θ learns the average noise over those images.

?

Why predict the noise ε instead of the clean image x₀ or the mean μ̃?
Given xₜ, any one of the three determines the other two through (4) and (7), so all three are valid parameterizations of the same Gaussian step. They train differently. ε has unit variance at every t, so the regression target has the same scale at every noise level. In the ablation, ε-prediction with L_simple reached FID 3.17; μ̃-prediction trained well only on the true bound (FID 13.22), and x₀-prediction gave worse samples in the authors’ early experiments.

?

If L_simple drops the weights of the true bound, is it still a principled objective?
It is a reweighted version of the bound, not the bound. The weights it drops are largest at small t (step 2 is weighted 27 times more than step 1000 when σₜ² = βₜ), so L_simple down-weights the small-noise steps and gives more of the training signal to the harder, larger-t steps. The cost is likelihood: the L_simple model gets 3.75 bits/dim against 3.70 for the model trained on the bound, while its FID improves from 13.51 to 3.17.

?

Can a trained DDPM sample in fewer than 1000 steps?
Not with Algorithm 2 as written: each step is a small Gaussian step, and the Gaussian form holds only when steps are small. In October 2020, DDIM (covered in its own explainer on this site) keeps the trained network and changes the sampler, reaching comparable quality in 20 to 100 steps, a 10 to 50 times wall-clock speedup.

?

Is the 3.17 FID measured on the CIFAR-10 test set?
No. As is standard, it is computed against the training set. Against the test set the same model scores 5.24.

Footnotes & further reading

  1. The paper: Ho, Jain, Abbeel, Denoising Diffusion Probabilistic Models (UC Berkeley, NeurIPS 2020). Official code (TensorFlow).
  2. The framework DDPM builds on: Sohl-Dickstein, Weiss, Maheswaranathan, Ganguli, Deep Unsupervised Learning using Nonequilibrium Thermodynamics (2015). Explainer.
  3. Denoising score matching over noise levels: Song, Ermon, Generative Modeling by Estimating Gradients of the Data Distribution (NCSN, 2019; explainer), and Vincent, A Connection Between Score Matching and Denoising Autoencoders (2011).
  4. The faster sampler: Song, Meng, Ermon, Denoising Diffusion Implicit Models (DDIM, 2020). Explainer.
  5. The continuous-time view: Song, Sohl-Dickstein, Kingma, Kumar, Ermon, Poole, Score-Based Generative Modeling through Stochastic Differential Equations (2021). Explainer.
  6. Architecture improvements and classifier guidance: Dhariwal, Nichol, Diffusion Models Beat GANs on Image Synthesis (2021). Explainer.
  7. Diffusion in a compressed latent space, the basis of Stable Diffusion: Rombach, Blattmann, Lorenz, Esser, Ommer, High-Resolution Image Synthesis with Latent Diffusion Models (2022). Explainer.