Generating images by diffusion

David I. Inouye

Dynamic Content · Last Updated: November 11, 2026

Arc 7 · Image generation and evaluation

Noisy scores → learned fields → multiple levels → SDE/ODE sampling

A denoising autoencoder predicts the clean input

Clean input branches to a corruption process and the reconstruction loss; an encoder and decoder reconstruct from the corrupted input.

\[\widetilde{\boldsymbol{x}}_\sigma=\boldsymbol{x}+\sigma\boldsymbol{\epsilon},\qquad \boldsymbol{\epsilon}\sim\mathcal N(\boldsymbol 0,I),\qquad \widehat{\boldsymbol{x}}=g_\theta(f_\phi(\widetilde{\boldsymbol{x}}_\sigma)).\]

Input: corrupted image. Target: original clean image.

Denoising needs a predictor, not a required bottleneck

\[\widehat{\boldsymbol{x}}=D_\theta(\widetilde{\boldsymbol{x}}_\sigma),\qquad \min_\theta\;\mathbb E\!\left[\|\boldsymbol{x}-D_\theta(\boldsymbol{x}+\sigma\boldsymbol{\epsilon})\|^2\right].\]

  • Directly map a noisy image to a clean-image prediction of the same shape.
  • We can use any suitable neural network; an explicit latent code is optional.
  • An encoder–decoder or U-Net can still be a useful architecture.

Predicting the clean image and predicting its noise are equivalent

For \(\widetilde{\boldsymbol{x}}_\sigma=\boldsymbol{x}+\sigma\boldsymbol{\epsilon}\) at a fixed \(\sigma>0\):

\[\widehat{\boldsymbol{x}}=\widetilde{\boldsymbol{x}}_\sigma-\sigma\epsilon_{\theta,\sigma}(\widetilde{\boldsymbol{x}}_\sigma), \qquad \widehat{\boldsymbol{\epsilon}}=\frac{\widetilde{\boldsymbol{x}}_\sigma-D_{\theta,\sigma}(\widetilde{\boldsymbol{x}}_\sigma)}{\sigma}.\]

The squared errors differ by a constant:

\[\|\boldsymbol{x}-\widehat{\boldsymbol{x}}\|^2 =\sigma^2\|\boldsymbol{\epsilon}-\widehat{\boldsymbol{\epsilon}}\|^2.\]

Same prediction problem; a different output parameterization.

The noise we draw becomes a supervised target

Clean input and drawn noise form a noisy input; predicted noise and the known drawn noise meet at squared error.

\[J(\theta)=\mathbb E_{\mathbf{x},\boldsymbol{\epsilon}} \left[\|\boldsymbol{\epsilon}-\epsilon_{\theta,\sigma}(\boldsymbol{x}+\sigma\boldsymbol{\epsilon})\|^2\right].\]

No noise labels need to be collected: we constructed the corruption.

One minibatch update learns noise prediction at one level

Fix \(\sigma>0\). For each batch of \(B\) clean images:

Step Computation, \(i=1,\ldots,B\)
Draw noise \(\boldsymbol{\epsilon}_i\sim\mathcal N(\boldsymbol 0,I)\) independently
Corrupt \(\widetilde{\boldsymbol{x}}_{\sigma,i}=\boldsymbol{x}_i+\sigma\boldsymbol{\epsilon}_i\)
Predict \(\widehat{\boldsymbol{\epsilon}}_i=\epsilon_{\theta,\sigma}(\widetilde{\boldsymbol{x}}_{\sigma,i})\)
Average loss \(\widehat J=\frac1B\sum_i\|\boldsymbol{\epsilon}_i-\widehat{\boldsymbol{\epsilon}}_i\|^2\)
Update \(\theta\leftarrow\theta-\eta\nabla_\theta\widehat J\)

Can this one denoiser also turn random noise into a clean image?

From denoising to noisy scores

Denoising learns the score of the noisy distribution

\[\widetilde{\boldsymbol{x}}_\sigma=\boldsymbol{x}+\sigma\boldsymbol{\epsilon}, \qquad p_\sigma=p_{\mathrm{data}}*\mathcal N(\boldsymbol0,\sigma^2I).\]

\(*\) denotes convolution: adding independent Gaussian noise smooths the clean-data distribution.

At the noisy input \(\widetilde{\boldsymbol{x}}_\sigma\), the score points toward increasing noisy-data log density:

\[s_\sigma(\widetilde{\boldsymbol{x}}_\sigma)=\nabla_{\widetilde{\boldsymbol{x}}_\sigma}\log p_\sigma(\widetilde{\boldsymbol{x}}_\sigma) =-\frac{\epsilon^*_\sigma(\widetilde{\boldsymbol{x}}_\sigma)}{\sigma} \ \approx\ -\frac{\epsilon_{\theta,\sigma}(\widetilde{\boldsymbol{x}}_\sigma)}{\sigma}.\]

Exact for the ideal squared-error predictor; approximate for the trained network.

Small noise approaches the clean score where that score exists

Smooth three-Gaussian clean density and its score compared with scores after noise of standard deviation0.1,1 and10; the small-noise score approaches the clean score.

For a smooth positive clean density, under suitable regularity: \(\nabla\log p_\sigma(\widetilde{\boldsymbol{x}}_\sigma)\to\nabla\log p_{\mathrm{data}}(\widetilde{\boldsymbol{x}}_\sigma)\) as \(\sigma\to0\).

Small-noise training leaves poorly constrained scores away from data

Clean data: uniform on a radius-10 circle. Train a small MLP at \(\sigma=1\).

Actual sigma1 noise-predictor training on the radius10 circle: training inputs occupy a narrow band; learned scores agree near that band but substantially underestimate magnitudes far inside and outside it.

Measured failure here: wrong magnitudes off the ring; directions mostly remain radial.

Large noise improves coverage but changes the score being learned

Same architecture and training budget, now \(\sigma=10\).

Actual sigma10 training covers a broad region; learned scores closely follow the ideal smoothed density score, which points inward rather than toward the clean ring.

A good estimate of \(\nabla\log p_{10}\) is still not the clean-data score.

What would perfect single-level sampling produce?

Suppose the \(\sigma=10\) score is exact and the sampler correctly targets its density.

What would more accurate sampling recover?

A. The clean radius-10 circle

B. The broad noisy distribution \(p_{10}\)

C. One conditional-mean point

B. Better approximation cannot change the distribution the score describes.

Learning across noise levels

Multiple noise levels connect broad coverage to fine detail

Noisy scores → discrete noise levels → continuous SDE/ODE sampling

Now \(t\) denotes noise variance: \(\sigma_t=\sqrt t\), \(\widetilde{\boldsymbol{x}}_t=\boldsymbol{x}+\sqrt t\,\boldsymbol{\epsilon}\), and \(\widetilde{\boldsymbol{x}}_0=\boldsymbol{x}\).

  1. Large noise: learn directions across a broad region.
  2. Intermediate noise: change the target toward cleaner structure.
  3. Small noise: resolve detail near the clean data.

Every time slice is a distribution over possible noisy samples

Left: three narrow Gaussian modes. Center: cividis density map with sample value vertical and noise variance horizontal; each vertical slice is p_t. Right: exact high-noise density almost coincides with a single Gaussian.

\[p_t(\widetilde{x}_t)=\sum_{j=1}^{3}w_j\,\mathcal N(\widetilde{x}_t;\mu_j,\,0.09+t),\qquad (\mu_1,\mu_2,\mu_3)=(-3,0,3).\]

Independent standard-normal steps make noise variance add

\[\widetilde{\boldsymbol{x}}_t=\widetilde{\boldsymbol{x}}_{t-1}+\boldsymbol{\eta}_t, \qquad\boldsymbol{\eta}_t\overset{\mathrm{iid}}{\sim}\mathcal N(\boldsymbol0,I).\]

Samples initially on the radius-10 circle spread under independent standard Gaussian steps; accumulated noise standard deviations are 0,1,5,10 at times 0,1,25,100.

After \(t\) steps: noise variance \(t\); noise standard deviation \(\sqrt t\).

Any noisy training input needs only one Gaussian draw

\[p_t(\widetilde{\mathbf{x}}_t\mid\boldsymbol{x})=\mathcal N(\widetilde{\mathbf{x}}_t;\boldsymbol{x},tI), \qquad \widetilde{\boldsymbol{x}}_t=\boldsymbol{x}+\sqrt t\,\boldsymbol{\epsilon}, \quad\boldsymbol{\epsilon}\sim\mathcal N(\boldsymbol0,I).\]

  • Independent Gaussian variances add: \(I+\cdots+I=tI\).
  • Select \(t\) and construct its noisy input directly.
  • For large \(T\), the noise dominates: start generation approximately from \(\mathcal N(\boldsymbol0,TI)\).

One network learns noise prediction at every level

Add the noise level to the input: \(\widehat{\boldsymbol{\epsilon}}_i=\epsilon_\theta(\widetilde{\boldsymbol{x}}_{t_i},t_i)\).

Step Computation for each image in a batch
Draw level and noise \(t_i\sim\operatorname{Uniform}\{1,\ldots,T\}\), \(\boldsymbol{\epsilon}_i\sim\mathcal N(\boldsymbol0,I)\)
Construct input \(\widetilde{\boldsymbol{x}}_{t_i}=\boldsymbol{x}_i+\sqrt{t_i}\,\boldsymbol{\epsilon}_i\)
Predict and score \(\widehat J=\frac1B\sum_i\|\boldsymbol{\epsilon}_i-\epsilon_\theta(\widetilde{\boldsymbol{x}}_{t_i},t_i)\|^2\)
Update shared parameters \(\theta\leftarrow\theta-\eta\nabla_\theta\widehat J\)

One sampled level per image; the same parameters across levels.

Reverse generation needs small conditional steps, not one clean guess

A clean-image estimate uses the whole predicted noise:

\[\widehat{\boldsymbol{x}}=\widetilde{\boldsymbol{x}}_t-\sqrt t\,\epsilon_\theta(\widetilde{\boldsymbol{x}}_t,t).\]

For the additive walk, the previous-step conditional mean instead uses

\[\widehat{\boldsymbol{\mu}}_{t-1}=\widetilde{\boldsymbol{x}}_t- \frac{1}{\sqrt t}\epsilon_\theta(\widetilde{\boldsymbol{x}}_t,t).\]

Generation follows \(T\to T-1\to\cdots\to0\) with fixed learned parameters.

A mean is not a full distribution: a reverse sampler must also handle uncertainty.

A stochastic reverse step denoises, then adds fresh noise

Move from current noise variance \(t\) to a lower variance \(s\geq0\). The step size is \(h=t-s>0\): how much we reduce the noise variance.

A DDPM-style step in our additive units is

\[\widetilde{x}_s=\underbrace{\widetilde{x}_t-\frac{h}{\sqrt t}\epsilon_\theta(\widetilde{x}_t,t)}_{m:\ \text{previous-level mean}} +\underbrace{\sqrt{\frac{sh}{t}}\,\xi}_{\text{fresh noise}},\qquad \xi\sim\mathcal N(0,1).\]

  • The correction uses \(h/t\) of the predicted clean-data correction.
  • For small \(h\) relative to \(t\), the added variance is approximately \(h\).
  • This Gaussian step approximates the reverse conditional distribution.

Mean correction narrows the distribution; noise spreads it again

The same three-mode mixture before the step, after mean correction alone, and after adding fresh noise. Dashed curves show the target marginal. A local Gaussian variance shrinks by about twice the desired amount, then noise adds one amount back.

“Denoise two, add back one” describes local variance change—not a time reversal.

Diffusion as a continuous process

Continuous noising is the small-step limit of the Gaussian walk

Discrete diffusion → continuous SDE → probability-flow ODE → solver choices

\[d\widetilde{\boldsymbol{x}}_t=d\mathbf{w}_t,\qquad \widetilde{\boldsymbol{x}}_0=\boldsymbol{x}.\]

  • An SDE adds random increments: \(\Delta\mathbf{w}\sim\mathcal N(\boldsymbol0,hI)\) over an interval \(h\).
  • Our time label is noise variance: \(\sigma(t)=\sqrt t\).
  • Its marginal remains \(\widetilde{\boldsymbol{x}}_t=\boldsymbol{x}+\sqrt t\,\boldsymbol{\epsilon}\) in distribution.

Continuous-time training still needs one noise draw per example

Draw \(t\sim\rho\) on \([t_{\min},T]\), \(t_{\min}>0\), then form \(\widetilde{\boldsymbol{x}}_t=\boldsymbol{x}+\sqrt t\,\boldsymbol{\epsilon}\).

\[\min_\theta\ \mathbb E\!\left[\lambda(t) \|\boldsymbol{\epsilon}-\epsilon_\theta(\widetilde{\boldsymbol{x}}_t,t)\|^2\right], \qquad s_\theta(\widetilde{\boldsymbol{x}}_t,t)=-\frac{\epsilon_\theta(\widetilde{\boldsymbol{x}}_t,t)}{\sqrt t}.\]

No simulated SDE trajectory and no SDE solver are required for this training loss.

The reverse SDE repeatedly combines score drift and random increments

Let generation time \(\tau=T-t\) increase while noise variance \(t\) decreases:

\[d\widetilde{\boldsymbol{x}}_{T-\tau} =s_\theta(\widetilde{\boldsymbol{x}}_{T-\tau},T-\tau)\,d\tau+d\overline{\mathbf{w}}_\tau.\]

A small numerical step is

\[\widetilde{\boldsymbol{x}}_{t-h}\approx\widetilde{\boldsymbol{x}}_t +h\,s_\theta(\widetilde{\boldsymbol{x}}_t,t)+\sqrt h\,\boldsymbol{\xi}.\]

Feed the new state into the next step; keep the network parameters fixed.

What if we delete the fresh noise from this sampler?

Keep the random initialization and the same mean correction.

What should we expect if every \(\xi\) is set to zero?

A. The same distribution, computed faster

B. A generally different output distribution

C. The same output on every run

B. A valid deterministic sampler also changes the correction.

One model, different sample paths

The probability-flow ODE transports the same density without fresh noise

Using the same score predictor and increasing reverse clock \(\tau\):

\[\frac{d\widetilde{\boldsymbol{x}}_{T-\tau}}{d\tau} =\frac12\,s_\theta(\widetilde{\boldsymbol{x}}_{T-\tau},T-\tau).\]

  • An ODE gives a deterministic trajectory once the initial sample is drawn.
  • Half the additive-process drift replaces the SDE’s drift-plus-noise balance.
  • Exact score + exact initial distribution + exact integration ⇒ same marginals \(p_t\).

We can vary stochasticity without retraining the score model

For \(0\leq\beta\leq1\), one family in our reverse clock is

\[d\widetilde{\boldsymbol{x}}_{T-\tau} =\frac{1+\beta^2}{2}\,s_\theta(\widetilde{\boldsymbol{x}}_{T-\tau},T-\tau)\,d\tau +\beta\,d\overline{\mathbf{w}}_\tau.\]

\(\beta=0\) \(0<\beta<1\) \(\beta=1\)
Probability-flow ODE Intermediate stochastic sampler Reverse diffusion SDE

Change the drift together with the noise amplitude to preserve the ideal marginals.

Different sample paths can pass through the same marginal distributions

Identical density backgrounds with time increasing left to right; generation runs right to left. Three panels compare probability flow, intermediate stochasticity and reverse SDE trajectories with identical starts and one highlighted path.

A vertical slice describes a population of samples, not one trajectory.

Many sampled paths recover the target density at each time

Histograms of 12000 DDPM-style, flow and DDIM samples at four noise levels, each overlaid with the known analytic mixture density; paired rows share axis ranges.

Compare the distributions at matched times—not matched outputs from one seed.

DDIM reuses the predicted noise direction without drawing fresh noise

First predict clean data, then retain the noise appropriate for \(s<t\):

\[\widehat x=\widetilde{x}_t-\sqrt t\,\epsilon_\theta(\widetilde{x}_t,t),\qquad \widetilde{x}_s=\widehat x+\sqrt s\,\epsilon_\theta(\widetilde{x}_t,t).\]

Therefore

\[\widetilde{x}_s=\widetilde{x}_t+(\sqrt s-\sqrt t)\epsilon_\theta(\widetilde{x}_t,t) \ \approx\ \widetilde{x}_t-\frac{h}{2\sqrt t}\epsilon_\theta(\widetilde{x}_t,t).\]

Deterministic DDIM approaches probability flow as steps become small.

An image follows one path through a distribution over whole images

Actual stochastic and flow sampling trajectories for a toy Gaussian mixture around three MNIST images, sharing an initial noisy image and analytic predictor; each row shows decreasing noise, ending in a digit-like image.

The 1D value \(\widetilde{x}_t\) becomes an image array \(\widetilde{\boldsymbol{x}}_t\); \(p_t\) is not a pixel histogram.

Choosing a numerical sampler

Numerical integration turns the learned field into a practical sampler

Write the reverse ODE drift as \(b(\widetilde{\boldsymbol{x}}_t,t)=\tfrac12s_\theta(\widetilde{\boldsymbol{x}}_t,t)\).

Euler proposal: \[\widetilde{\boldsymbol{x}}^{\mathrm E}_{t-h} =\widetilde{\boldsymbol{x}}_t+h\,b(\widetilde{\boldsymbol{x}}_t,t).\]

Heun correction: \[\widetilde{\boldsymbol{x}}_{t-h}=\widetilde{\boldsymbol{x}}_t+ \frac h2\left[b(\widetilde{\boldsymbol{x}}_t,t) +b(\widetilde{\boldsymbol{x}}^{\mathrm E}_{t-h},t-h)\right].\]

Evaluate two slopes instead of one; compare cost in network evaluations.

A better solver can improve sampling with exactly the same predictor

Measured endpoint errors for Euler and Heun on the same analytic mixture ODE versus network-equivalent field evaluations, plus an adaptive SciPy Runge–Kutta result.

This isolates solver error. Image quality must also be measured downstream.

Training and sampling are separate design choices with shared constraints

Learn the noisy score Turn that score into samples
Data, architecture and conditioning ODE, SDE or intermediate stochasticity
Noise-level distribution and loss weighting Noise grid and integration variable
Prediction target and input/output scaling Solver order, evaluation budget and endpoint

Hold training fixed to compare samplers; evaluate final quality, diversity and cost.

NVIDIA: Elucidating the Design Space of Diffusion-Based Generative Models — Karras et al., NeurIPS 2022

Conditioning makes denoising depend on the requested output

For an image paired with a condition \(c\):

\[\widetilde{\boldsymbol{x}}_t=\boldsymbol{x}+\sqrt t\,\boldsymbol{\epsilon},\qquad \widehat{\boldsymbol{\epsilon}}=\epsilon_\theta(\widetilde{\boldsymbol{x}}_t,t,c).\]

  • Train: retain \(c\) with each image while learning noise prediction.
  • Generate: supply the same request at every reverse step.
  • A class label, text embedding, or layout can provide \(c\); request adherence needs testing.

Latent diffusion performs the repeated steps in a compressed image space

Training encodes an image then adds noise to its code; generation starts with noisy code, repeats conditioned denoising in code space, and decodes once to an image.

Encode for training; repeatedly denoise codes; decode once after generation.

The codec and denoiser create different sources of error

Check What it isolates
Real image \(\to\) encode \(\to\) decode Detail lost by the codec
Noise \(\to\) latent denoising \(\to\) decode End-to-end generation quality and diversity
Repeat requests across seeds Consistency and condition adherence

Smaller latent arrays can reduce repeated computation, with a compression tradeoff.

Generative families differ in how a sample is produced

Model Generation procedure Main computation to budget
VAE Sample a latent code, then decode Decoder evaluation
Diffusion Start with noise, then follow reverse steps Repeated denoiser evaluations
Autoregressive Sample the next symbol conditioned on the prefix Sequential symbol-generation steps

A vanilla AE or fixed-level DAE does not specify a generator by itself.

A plausible image still needs evidence for its intended use

Suppose the generator illustrates specified objects in a teaching worksheet.

Intended value Evidence to collect
Correct requested objects and counts Independent request set; structured human checks
Useful variety without broken examples Multiple seeds per request; inspect failures by slice
Practical classroom use Readability at final size, generation time, and review effort

Next: turn these checks into an evaluation protocol and compare models fairly.