17

Diffusion: from noise to image

How is an image created by removing noise step by step?

12 min

Diffusion: from noise to image

With voice. You can pause and jump to any step.

Lesson complete

Subtitles

This is static: sixty-four random pixels. Watch closely: in a few seconds, a tiny network turns it into a seven that never existed.

Voice

No voice: the lesson advances on its own with subtitles.

The voice for this lesson is being recorded: for now it advances on its own with subtitles.

0:00 / 0:00

What you will achieve

  • Explain the forward process (mixing an image with noise, step by step, until only static is left) and why undoing it in one jump is impossible but in many small steps is not.
  • Describe, piece by piece, what the network in a diffusion model takes in and returns (noisy image and step → estimated noise) and how generation starts from pure static.
  • Recognize what classifier-free guidance does (exaggerating the hint, at the cost of variety) and what latent diffusion does (diffusing in a space of codes, which is far cheaper).

Key ideas

  1. The forward process mixes an image with noise, step by step, on a fixed schedule, until only static is left. It learns nothing, and in the end every image ends up as the same kind of static, which is easy to make.
  2. Undoing the noise in one jump is impossible: the same static could have come from any image, and the best possible guess is a blurry average. A small step, by contrast, can be estimated.
  3. The network takes the noisy image and the step number, and estimates the noise. It is trained on examples that never run out: we make the noise ourselves, so we know the answer.
  4. Generating means starting from pure static and removing a little of the estimated noise, many times. Different static gives a different result: nothing was stored.
  5. Classifier-free guidance exaggerates the difference between the estimate with the hint and without it: more fidelity, less variety. Latent diffusion does all of this in a much smaller space of codes and decodes at the end; that is how Stable Diffusion works.

What many people believe

Common belief The network “cleans up” an image that was already hidden in the static: it just uncovers it.

What is true There is no image in the static. Step by step, the network decides what drawing is plausible given what it learned from the data; with different static, or a different hint, a different drawing comes out.

Check yourself

Four questions. No grade, no account: they just show whether the idea stuck.

ConceptWhat does the network in a diffusion model learn?
ConceptWhy not remove all the noise in a single jump?
CalculationA system generates each image with 50 steps and classifier-free guidance. Each network evaluation takes 0.02 s. How long does one image take, not counting decoding?
ApplicationA marketing team turns the guidance scale way up so the images match the request more closely. What should it expect?

Under the hoodFor those who want the math and the code. You do not need it to follow the course.

The forward process

With a noise schedule β1,…,βT\beta_1,\dots,\beta_T, let αt=1−βt\alpha_t = 1-\beta_t and αˉt=∏s≤tαs\bar\alpha_t = \prod_{s\le t}\alpha_s. Each step is q(xt∣xt−1)=N(αt xt−1, βtI)q(x_t\mid x_{t-1}) = \mathcal N\big(\sqrt{\alpha_t}\,x_{t-1},\ \beta_t I\big), and chaining them gives a closed form for any step:

xt=αˉt x0+1−αˉt ε,ε∼N(0,I).x_t = \sqrt{\bar\alpha_t}\,x_0 + \sqrt{1-\bar\alpha_t}\,\varepsilon,\qquad \varepsilon\sim\mathcal N(0,I).

The lesson’s bar shows αˉt\bar\alpha_t (the share of the mix’s “energy” that is still image) and 1−αˉt1-\bar\alpha_t (the share that is noise). The lesson uses T=50T = 50 and the cosine schedule of Nichol and Dhariwal (2021), αˉ(t)∝cos⁡2 ⁣(t/T+s1+s⋅π2)\bar\alpha(t) \propto \cos^2\!\big(\tfrac{t/T + s}{1+s}\cdot\tfrac{\pi}{2}\big) with s=0.008s = 0.008, clipping each βt\beta_t to at most 0.35 (with so few steps, the last cosine β\beta values approach 1). So αˉ\bar\alpha is 0.899 at step 10, 0.494 at 25, 0.094 at 40, and 0.003 at 50. Pixels are first mapped to the range −1…1-1\ldots 1; on screen they are clipped to 0…10\ldots 1.

Why not in one jump

The network is trained with squared error, and what minimizes squared error is the conditional mean E[x0∣xt]\mathbb E[x_0\mid x_t]. At t=Tt = T the static keeps almost no information, so E[x0∣xT]≈E[x0]\mathbb E[x_0\mid x_T]\approx \mathbb E[x_0]: the average of all the digits, the lesson’s smudge. By contrast, if each βt\beta_t is small, the reverse step q(xt−1∣xt)q(x_{t-1}\mid x_t) is nearly Gaussian, with the same form as the forward step (Sohl-Dickstein et al., 2015, citing Feller, 1949): estimating its mean is enough.

What the network learns and how it is trained

The network εθ(xt,t,c)\varepsilon_\theta(x_t, t, c) estimates the noise. The simplified loss of Ho et al. (2020) is

L(θ)=Ex0, t, ε[ ∥ε−εθ(αˉt x0+1−αˉt ε, t)∥2 ].L(\theta) = \mathbb E_{x_0,\,t,\,\varepsilon}\big[\,\lVert \varepsilon - \varepsilon_\theta(\sqrt{\bar\alpha_t}\,x_0 + \sqrt{1-\bar\alpha_t}\,\varepsilon,\ t)\rVert^2\,\big].

Thanks to the closed form, training does not need to walk through the steps: it jumps straight to a random tt. The lesson’s pixel network has 53,056 parameters (three layers of 128 neurons with residual connections and SiLU; inputs: the 64 pixels, 16 numbers encoding the step, and the label in 11 slots, the last one meaning “no hint”) and was trained for 30,000 rounds with batches of 256 images: 7,680,000 noisy versions of lesson 15’s 1,500 training digits. With the seven at step 20, its noise estimate has a mean squared error of 0.135 per pixel; if it said “there is no noise,” the error would be 0.864.

Sampling

DDPM’s original sampler starts from xT∼N(0,I)x_T\sim\mathcal N(0,I) and, for t=T,…,1t=T,\dots,1, computes

xt−1=1αt(xt−βt1−αˉt ε^)+βt z,z∼N(0,I),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,\qquad z\sim\mathcal N(0,I),

with a little fresh noise zz at each step (except the last). The scene uses the deterministic variant of Song et al. (2021), DDIM with η=0\eta = 0, with the same network trained as in DDPM:

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

That is: the noise estimate gives the clean image it implies, which is then mixed again with the share of noise that belongs to the previous step. With no fresh noise, each point on the plane follows its arrow exactly and the same static always gives the same result; different static gives a different one.

Classifier-free guidance

A single network is trained with the label cc and, with probability 0.15, without it (∅\varnothing). When sampling, they are combined:

ε^=εθ(xt,∅)+s (εθ(xt,c)−εθ(xt,∅)).\hat\varepsilon = \varepsilon_\theta(x_t,\varnothing) + s\,\big(\varepsilon_\theta(x_t,c)-\varepsilon_\theta(x_t,\varnothing)\big).

With s=0s=0 it is the estimate without the hint (the hint is ignored); with s=1s=1, the conditional, which follows the hint as is; with s>1s>1 the hint’s direction is exaggerated. It is the same convention as in lesson 18. Ho and Salimans (2022) write the same with w=s−1w = s-1: ε~=(1+w) εθ(xt,c)−w εθ(xt)\tilde\varepsilon = (1+w)\,\varepsilon_\theta(x_t,c) - w\,\varepsilon_\theta(x_t). Each guided step costs two network evaluations. On the lesson’s plane, with the hint “seven” and two hundred points (reader: lesson 15’s logistic regression), 26 are read as sevens with s=0s = 0, 199 with s=1s = 1, and 200 with s=5s = 5. At the same time, the real sevens left with no new point within 0.3 number 4 of 154 with s=1s = 1, 48 with s=2s = 2, 95 with s=3s = 3, and 144 with s=5s = 5: the points crowd onto the edge of the group farthest from the other digits. The pixel network generates its sevens with s=3s = 3.

Latent diffusion

An autoencoder compresses the image into a code z=E(x)z=E(x); diffusion happens in zz and at the end x=D(z)x=D(z) is decoded (Rombach et al., 2022). In the lesson, zz is the two numbers of lesson 15’s VAE, multiplied by 1.6 before diffusing (Stable Diffusion also rescales its codes by a fixed factor), and the plane network has 10,370 parameters. In Stable Diffusion v1, the autoencoder shrinks each side 8 times and outputs 4 channels: a 512×512×3=786,432512\times512\times3 = 786{,}432-number image becomes a 64×64×4=16,38464\times64\times4 = 16{,}384-number code, 48 times fewer.

In code

import numpy as np

T, s = 50, 0.008
f = lambda t: np.cos((t / T + s) / (1 + s) * np.pi / 2) ** 2
a_full = f(np.arange(T + 1)) / f(0)
betas = np.clip(1 - a_full[1:] / a_full[:-1], 1e-4, 0.35)   # noise schedule
alphas = 1 - betas
abar = np.cumprod(alphas)
print('image share of the mix (%):', [round(float(100 * abar[t - 1]), 1) for t in (10, 25, 40, 50)])

# Toy data: a single number that is -1 or +1. For it, the best possible
# noise estimator can be written by hand (in the lesson a network learns it).
def estimated_noise(x, i):
    a, b = np.sqrt(abar[i]), np.sqrt(1 - abar[i])
    x0 = np.tanh(a * x / b**2)          # mean of x0 given x_t
    return (x - a * x0) / b

rng = np.random.default_rng(0)
x = rng.standard_normal(10_000)        # pure static
for i in reversed(range(T)):           # fifty steps back (DDPM)
    e = estimated_noise(x, i)
    x = (x - betas[i] / np.sqrt(1 - abar[i]) * e) / np.sqrt(alphas[i])
    if i > 0:
        x += np.sqrt(betas[i]) * rng.standard_normal(x.size)

print('within 0.1 of -1 or +1:', round(float(np.mean(np.abs(np.abs(x) - 1) < 0.1)), 3))
print('share at +1:', round(float(np.mean(x > 0)), 3))
# image share of the mix (%): [89.9, 49.4, 9.4, 0.3]
# within 0.1 of -1 or +1: 1.0
# share at +1: 0.499

What comes next

Lesson 18 shows how a sentence becomes the hint that guides diffusion (CLIP and text conditioning). Later on, the transformer (lessons 21 and 22) replaces the convolutional network in many modern diffusion models.

Decision lens

What this idea means if your job is to decide, not to code.

  • The cost of generating is steps × network evaluations × images. Classifier-free guidance doubles the evaluations per step: for large campaigns, estimate the volume and compare setups with fewer steps or lower resolution.
  • The guidance scale is a business dial: higher gives results more faithful to the request, but more alike. Try several scales on your own cases before settling on one.
  • Apparent quality is deceiving: check details (text inside the image, hands, logos) and keep human review before publishing.
  • These models learn from large collections of real images: ask the vendor where the data comes from, what licenses cover it, and what usage and synthetic-image labeling policy it offers.

Terms in this lesson

Full transcript
CommentsThis lesson’s public conversation: questions, facts to check, ideas.

Comments live in GitHub Discussions, in the course’s public repository; writing one requires a GitHub account. They load from giscus.app when you open this section. The course reviewers read them, and if a change is accepted, it is applied in both languages. Open the thread on GitHub

Sources