Roadmap / Theory

Diffusion & Multimodal Models

DDPM noise schedules and the denoising loss, ViT patch embeddings and CLIP's contrastive loss, the pieces behind image generation and vision-language models.

Language models generate one token at a time. Images are generated differently: a diffusion model starts from pure noise and removes it step by step. And a model that reads images needs a way to turn pixels into tokens. This page covers both: the denoising diffusion model behind image generation, and the vision transformer and contrastive training behind vision-language models.

Diffusion: learning to remove noise

The idea of a diffusion model (Sohl-Dickstein et al., 2015; Ho, Jain and Abbeel, 2020) is easy to say: take a picture and add a little random noise, again and again, until only noise is left. Then train a network to undo one step of that. If it can undo every step, it can start from pure noise and end with a picture.

The forward process: adding noise (fixed)

Starting from a data point x0x_0 (an image), add a little Gaussian noise (random numbers from a bell-shaped distribution) at each of TT steps, with variances β1,…,βT\beta_1, \dots, \beta_T. DDPM (Denoising Diffusion Probabilistic Models) uses T=1000T = 1000 and β\beta increasing linearly from 10−410^{-4} to 0.020.02. With αt=1−βt\alpha_t = 1 - \beta_t and αˉt=∏s≤tαs\bar\alpha_t = \prod_{s \le t} \alpha_s (αˉt\bar\alpha_t is "alpha bar": the product of all the α\alpha up to step tt), any step can be sampled directly from x0x_0:

xt=αˉt x0+1−αˉt ϵx_t = \sqrt{\bar\alpha_t}\, x_0 + \sqrt{1 - \bar\alpha_t}\, \epsilon

where ϵ∼N(0,I)\epsilon \sim \mathcal{N}(0, I) means that ϵ\epsilon is standard Gaussian noise. In words: xtx_t is a mix of the clean image and noise; as tt grows the clean part shrinks and the noise part grows.

Example. A tiny schedule with T=4T = 4 and β=(0.1,0.2,0.3,0.4)\beta = (0.1, 0.2, 0.3, 0.4).

  • α=(0.9,0.8,0.7,0.6)\alpha = (0.9, 0.8, 0.7, 0.6) and αˉ=(0.9,0.72,0.504,0.3024)\bar\alpha = (0.9, 0.72, 0.504, 0.3024): each is the product of the α\alpha so far.
  • A single number x0=2x_0 = 2 with noise ϵ=1\epsilon = 1, at step 2: x2=0.72⋅2+0.28⋅1=1.697+0.529=2.226x_2 = \sqrt{0.72} \cdot 2 + \sqrt{0.28} \cdot 1 = 1.697 + 0.529 = 2.226. At step 4 the clean part would be 0.3024⋅2=1.10\sqrt{0.3024} \cdot 2 = 1.10 and the noise part 0.6976=0.84\sqrt{0.6976} = 0.84: more noise than signal.

With the real DDPM schedule, αˉ1=0.9999\bar\alpha_1 = 0.9999, αˉ100=0.897\bar\alpha_{100} = 0.897, αˉ500=0.079\bar\alpha_{500} = 0.079 and αˉ1000=4×10−5\bar\alpha_{1000} = 4 \times 10^{-5} (our computation): the signal part αˉT\sqrt{\bar\alpha_T} is 0.0060.006, so xTx_T is almost pure noise.

The reverse process: removing noise (learned)

A network ϵθ(xt,t)\epsilon_\theta(x_t, t) is trained to predict the noise that was added. The loss is a plain mean squared error, the "simple" objective of Ho et al.:

Lsimple=Et,x0,ϵ∥ϵ−ϵθ(xt,t)∥2\mathcal{L}_{\text{simple}} = \mathbb{E}_{t, x_0, \epsilon}\left\| \epsilon - \epsilon_\theta(x_t, t) \right\|^2

where E\mathbb{E} is the average over random choices of the step tt (drawn uniformly), the data point x0x_0 and the noise ϵ\epsilon, and the bars are the squared length of the difference between the true and the predicted noise. A training step is therefore: take an image, pick a random tt, noise it with the formula above, ask the network what noise was added, and compare.

Sampling starts from xT∼N(0,I)x_T \sim \mathcal{N}(0, I) (pure noise) and applies, for t=T,…,1t = T, \dots, 1:

xt−1=1αt(xt−βt ϵθ(xt,t)1−αˉt)+σtz\begin{aligned} x_{t-1} = {} & \frac{1}{\sqrt{\alpha_t}}\left(x_t - \frac{\beta_t\, \epsilon_\theta(x_t, t)}{\sqrt{1 - \bar\alpha_t}}\right) \\ & + \sigma_t z \end{aligned}

with z∼N(0,I)z \sim \mathcal{N}(0, I) (and z=0z = 0 at the last step), and σt2=βt\sigma_t^2 = \beta_t. The first line removes the predicted noise from xtx_t; the second adds a small amount of fresh noise, which keeps the samples varied.

From a noise prediction one can also estimate the clean image directly: x^0=(xt−1−αˉt ϵ^)/αˉt\hat x_0 = (x_t - \sqrt{1 - \bar\alpha_t}\,\hat\epsilon) / \sqrt{\bar\alpha_t}, where ϵ^\hat\epsilon is the predicted noise.

Example. The tiny schedule above, with x2=2.226x_2 = 2.226 made from x0=2x_0 = 2 and noise 11.

  • If the network predicts the noise exactly, ϵ^=1\hat\epsilon = 1: x^0=(2.226−0.529⋅1)/0.849=2\hat x_0 = (2.226 - 0.529 \cdot 1) / 0.849 = 2: the clean value is recovered exactly.
  • One reverse step from x2=1.0x_2 = 1.0 with a prediction ϵ^=0.5\hat\epsilon = 0.5 and a fresh noise z=0.7z = 0.7: the first line gives 10.8(1−0.2⋅0.50.28)=0.907\frac{1}{\sqrt{0.8}}\left(1 - \frac{0.2 \cdot 0.5}{\sqrt{0.28}}\right) = 0.907; the second adds 0.2⋅0.7=0.313\sqrt{0.2} \cdot 0.7 = 0.313. So x1=1.220x_1 = 1.220. At the last step (t=1t = 1) the second line is dropped.

Later work changed the details: a cosine schedule that adds noise more gradually (Nichol and Dhariwal, 2021), and latent diffusion (Rombach et al., 2022), which runs the whole process in the compressed latent space of an autoencoder (a smaller representation of the image learned by a network) instead of on pixels, making high-resolution generation much cheaper.

Conditioning and classifier-free guidance

To generate "a photo of a cat", the network also receives the condition cc (a class or a text embedding): ϵθ(xt,t,c)\epsilon_\theta(x_t, t, c). Classifier-free guidance (Ho and Salimans, 2022) trains the same network to work with and without the condition, by replacing cc with a null token ∅\varnothing in a fraction puncondp_{\text{uncond}} of the training examples. At sampling time it extrapolates away from the unconditional prediction:

ϵ~=(1+w) ϵθ(xt,c)−w ϵθ(xt,∅)\tilde\epsilon = (1 + w)\,\epsilon_\theta(x_t, c) - w\,\epsilon_\theta(x_t, \varnothing)

where ϵ~\tilde\epsilon is the guided prediction and ww the guidance weight. w=0w = 0 is the plain conditional model; larger ww follows the condition more closely and gives less varied images.

Example. For one number, the conditional prediction is 0.80.8 and the unconditional one is 0.50.5. The difference, 0.30.3, is "what the condition adds". The guided prediction is 0.5+(1+w)⋅0.30.5 + (1 + w) \cdot 0.3:

ww guided prediction
0 0.80.8 (the conditional one)
1 1.11.1
2 1.41.4
5 2.32.3

The larger ww, the further the prediction goes in the direction of the condition, past the conditional prediction itself.

Images as tokens: the vision transformer

The ViT (Vision Transformer; Dosovitskiy et al., 2021) applies the transformer of section 7 to images by cutting them into patches. An image of H×WH \times W pixels with CC channels (3 for colour: red, green, blue) becomes N=HW/P2N = HW/P^2 patches of P×PP \times P pixels ("an image is worth 16×16 words"), each flattened into a vector of P2CP^2 C numbers and mapped to the model dimension by one linear layer. A learnable [class] embedding is prepended, as in BERT (Bidirectional Encoder Representations from Transformers), and learnable 1-D position embeddings are added. From there on, the image is a sequence of tokens like any other.

Example. An image of 224×224224 \times 224 pixels with 3 channels, P=16P = 16: N=(224/16)2=142=196N = (224/16)^2 = 14^2 = 196 patches, each of 16⋅16⋅3=76816 \cdot 16 \cdot 3 = 768 numbers. A sequence of 197 tokens with the class token.

A toy image 4×44 \times 4 with one channel, numbered 0,…,150, \dots, 15 row by row, and P=2P = 2: there are 4 patches, in row-major order (left to right, top to bottom): [0,1,4,5][0, 1, 4, 5], [2,3,6,7][2, 3, 6, 7], [8,9,12,13][8, 9, 12, 13] and [10,11,14,15][10, 11, 14, 15]. The first patch is the 2×22 \times 2 square in the top-left corner, flattened row by row.

Connecting images and text: CLIP

CLIP (Contrastive Language-Image Pre-Training; Radford et al., 2021) trains an image encoder and a text encoder together on image–caption pairs from the web. In a batch of NN pairs, each image embedding should match its own caption and none of the other N−1N - 1. With both embeddings normalized to unit length, the N×NN \times N table of cosine similarities (the dot products of unit vectors: 1 if they point the same way, 0 if they are unrelated), divided by a learned temperature, is treated as logits, and the loss is the symmetric cross-entropy: once over rows (each image picks its caption) and once over columns (each caption picks its image), with the correct pairs on the diagonal. The temperature is initialized to the equivalent of 0.07.

Example. Two images, embeddings (1,0)(1, 0) and (0,1)(0, 1); two captions, embeddings (1,0.2)(1, 0.2) and (0.1,1)(0.1, 1).

  • Cosine similarities: (0.980.100.200.995)\begin{pmatrix} 0.98 & 0.10 \\ 0.20 & 0.995 \end{pmatrix}. The diagonal (the right pairs) is the largest in every row and column.
  • With a temperature of 0.50.5, the logits are the similarities times 2. Each row's cross-entropy is small, because the right caption wins by a wide margin: the loss is 0.170.17. With a temperature of 11 it is 0.360.36. With the learned temperature, 0.070.07, the logits are 14 times larger and the loss is almost 0.

A model that cannot tell the captions apart would give the loss log⁡2=0.69\log 2 = 0.69 (two equally likely choices).

The result is a shared space where text and images can be compared, used for zero-shot classification (no training for the task: compare an image with the captions "a photo of a {class}", and pick the best) and as the vision part of multimodal models.

Vision-language models

The simplest way to give a language model eyes is to project the image tokens of a pre-trained vision encoder into its embedding space. LLaVA (Large Language and Vision Assistant; Liu et al., 2023) takes the visual features of CLIP's large vision transformer with 14-pixel patches (ViT-L/14), multiplies them by a trainable projection matrix WW, and feeds the result to the language model as if they were word embeddings. A first stage trains only WW on image–caption pairs; a second fine-tunes on visual instructions (section 12). The language model never sees pixels: it sees a few hundred extra tokens.

References

Practice

0/5