Diffusion models

Introduction
Diffusion models draw inspiration from non-equilibrium thermodynamics. They add noise to the data and then learn a reverse process that generates samples from noise.
Specifically, a diffusion process is applied to gradually convert the observed data into a noisy version by repeatedly passing the data through a stochastic encoder . After enough steps, we end up with , or any other convenient reference distribution. Then, a reverse process is learned by passing the noise through steps of a decoder until is generated again.
These models are similar to hierarchical VAEs, in the sense that they have an encoder and a decoder and follow a sequence of steps or hierarchies, and also to normalizing flows, since they apply a sequence of transformations to the data.
Remember the image from the beginning of the course? It should make much more sense now.

In diffusion models, the forward process in which we add noise is not learned but instead follows a fixed procedure, and the latent variable has the same dimensionality as the original data. On the other hand, the decoder is shared across all steps.
Several diffusion-based generative models have been proposed, including diffusion probabilistic models[sohl2015deep], noise-conditioned score network[song2019generative], denoising diffusion probabilistic models[ho2020denoising], and variational diffusion models[kingma2021variational].
Encoder (forward diffusion)
Forward diffusion is the easy part because it doesn't involve training any model. It is a fixed procedure in which we decide how to add noise.
The process is usually defined as a simple linear Gaussian model:
where the values of are chosen according to a noise scheduler.
Intuitively, controls how much noise we add at each step :
- if is small, the image changes very little
- if is large, we add a lot of noise at once
The noise scheduler decides how that amount of noise grows throughout the process. Adding a lot of noise from the start is not the same as adding it slowly and accelerating toward the end.
The joint distribution over the latent states is:
The distribution is known as the diffusion kernel. Applying this to the input data distribution and then computing the resulting unconditional marginals is equivalent to Gaussian convolution:
As increases, the signal-to-noise ratio decreases and the marginals approach a simple distribution. In images, this process first removes high-frequency content (i.e., low-level details, such as texture), and then low-frequency content (high-level or "semantic" information, such as shape).

Decoder (reverse diffusion)
The ultimate goal of a diffusion model is for the reverse process (decoder) to learn the original data distribution, .
By adding noise in steps, a sequence of intermediate distributions is created, where is the original data with an increasing amount of noise.
Generating a full image from scratch is hard, so the problem is reformulated to consist 'only' of removing a bit of noise from a given image. By doing it in several steps, we turn a complicated task into many simple ones.
In other words, to generate a new sample we don't know , so we train a model to approximate the reverse distribution:
The corresponding joint distribution over all generated variables is given by:
To generate data from the model, a point is sampled and then the Markov chain is run backward, sampling until a sample is obtained in the original data space, .

Training
We have already defined the two processes that make up a diffusion model: the forward process adds noise through known transitions, and the reverse process progressively tries to recover the data. What's left is to learn the parameters of each reverse transition .
During training we start from a clean sample , so we can generate any noisy state and compute what the step toward should look like. The goal is to get the learned transition to approximate that reverse process. This idea is formulated probabilistically through the ELBO and ends up producing a simple noise-prediction loss.
The ELBO as a starting point
We want to maximize the log-likelihood of the data, , but computing it requires integrating over all latent states . As in a VAE, we use the forward process as the variational distribution and minimize the negative ELBO:
*VLB stands for "Variational Lower Bound".
This expression can be decomposed into a sum of local problems:
- compares the last state of the forward process with the Gaussian prior and does not depend on if the noise scheduler is fixed.
- Each compares the true reverse step, which we can compute during training because we know , with the learned reverse step.
- corresponds to the final reconstruction step toward the data.
The distribution is Gaussian and its mean can be expressed using the noise with which we constructed :
If we fix the variance of the reverse process and parameterize its mean using a network , each KL term that depends on becomes, up to constants, a squared-error noise-prediction term:
where is a weight determined by the noise scheduler and by the variance chosen for .
Simplified loss
Ho et al.[ho2020denoising] observed that dropping the weights and sampling uniformly produced better samples. This variant is known as :
This is the loss function we will assume for the rest of the chapter. It is a reweighted version of the variational objective that keeps the same denoising problem, but it is no longer exactly the original ELBO because it assigns the same explicit weight to every timestep.
In summary, during training:
- We take an image .
- We pick a random step .
- We add a known amount of noise to obtain .
- We feed to the model.
- The network predicts the noise it believes is in the image, , and we minimize .
Example: Stable Diffusion
The original Stable Diffusion family[rombach2022high] popularized latent diffusion. Instead of running the process directly on pixels, it runs it on a compressed latent space, which substantially reduces the computational cost.
This makes it a latent diffusion model.
The motivation is very practical. A image with 3 channels has a very large dimensionality, so performing diffusion over all those pixels is expensive. Stable Diffusion first compresses the image to a smaller representation, performs the denoising process in that compressed space, and, at the end, decodes the result back to pixels.
Overview
We can think of Stable Diffusion as three main blocks:
- Text encoder: converts the text prompt into a numerical representation.
- Image generator: generates a latent representation of the image guided by the text.
- Image decoder: reconstructs the latent representation into the target image dimension.

Text encoder: CLIP
First, the model needs to convert prompts into vectors that a neural network can use.

In the original Stable Diffusion, this block is CLIP's text encoder[radford2021learning]. CLIP jointly trains an image encoder and a text encoder to learn representations where an image and its description end up close together in vector space.
During training, image-text pairs are passed through their respective encoders and the embeddings are compared using cosine similarity. At the start, the similarity will be low, even if the text correctly describes the image, simply because the vector spaces of each encoder are different. What is then done is to update the weights of both networks so that, next time, the resulting embeddings are similar.
By repeating this operation, by the end of training the encoders end up producing embeddings in which, for example, an image of a pangolin and the phrase "a photo of a pangolin" end up in similar regions of the latent space.

The text encoder is used to convert the prompt into a sequence of embeddings that contain contextual representations of the tokens. The generator will use it to guide the appearance of objects, styles, and relationships.
Example: if the prompt says "a dog with sunglasses on the beach", the text encoder generates a representation that will help the image generator know that concepts like dog, sunglasses, beach, outdoor light, sand, etc., should appear.
Image generator
The name "image generator" can be misleading because, in the Stable Diffusion family, this component does not produce pixels directly, but rather a matrix in latent space.
The core block is a U-Net. This network receives:
- a noisy latent
- the timestep
- the textual conditioning produced by CLIP
And predicts the noise that should be subtracted:
Then, a scheduler uses that prediction to compute a slightly less noisy latent:
This process is repeated many times until a clean latent is obtained. This is not a visible image, so it is passed through the decoder of a VAE to convert it into pixels, .

The U-Net uses cross-attention mechanisms to mix the visual information of the latent with the textual information of the prompt. Thanks to this, the model can decide which parts of the image should attend to which parts of the text.
Training
During training, the model mainly learns to remove noise in the latent space.
The typical process is:
- A real image and its associated text are taken.
- The image is encoded with the VAE's encoder to obtain a latent .
- The text is encoded with CLIP to obtain the conditioning .
- A random timestep is chosen.
- Noise is added to the latent to obtain .
- The U-Net receives and predicts the added noise.
- The real noise is compared with the predicted noise.
The loss is the same we just defined, but applied in the latent space and conditioned on the text:
In many implementations, the VAE and the text encoder are already pretrained, so they are kept frozen. The trainable part consists of the U-Net's parameters for the denoising process.

Inference
Here we want to use the already-trained model to generate a new image.
The typical flow is:
- We write a prompt.
- CLIP converts the prompt into text embeddings .
- We sample a random initial latent .
- The U-Net predicts the noise in the current latent, conditioned on .
- The scheduler subtracts the predicted noise from the latent to make it slightly less noisy.
- We repeat steps 4 and 5 for several timesteps.
- The decoder converts the final latent into an image.

Relationship to Flow Matching
Diffusion models and Flow Matching are closely related. Both start from a simple distribution, usually Gaussian noise, and learn to transform it into a target distribution. The most common way of presenting them differs in which parametrization the model uses to express that same objective, although, as we'll see, all of them are convertible into one another.
In diffusion, the model learns to predict the noise:
That is, it receives a noisy sample and predicts which part of that sample corresponds to the added noise.
In Flow Matching, the model learns a velocity:
That is, it receives an intermediate point and predicts in which direction it should move to advance from the initial distribution toward the target distribution.
During training
In diffusion, we construct noisy examples by adding known noise to real data:
Since we know , we train the network to predict that noise.
In Flow Matching, we construct intermediate points between an initial sample and a data point :
And we train the network to predict the velocity that would follow that path:
In both cases we build a supervised problem: we artificially generate an intermediate state and we know what the correct answer should be. In diffusion this target can also be expressed as a score, a clean sample , or a velocity .
These parametrizations are not independent: given , they are related by
Given and any one of the four quantities (noise , score , clean data , or velocity ), the others can be obtained without retraining the model. They are different parametrizations of the same training objective.
During generation
In diffusion, we start from noise and apply denoising steps:
In Flow Matching, we start from noise and follow a velocity field:
Generation also proceeds from noise to data, but the mathematical starting point changes. Diffusion can be implemented as a stochastic chain or via its probability-flow ODE; Flow Matching directly defines and learns a velocity field over a probability path. The two frameworks are closely related.