Diffusion models take a different approach to generative modeling than GANs. Instead of learning a generator directly, they learn to reverse a diffusion process: iteratively remove noise from random noise. This simple process generates high-quality images and is more stable than GANs.
Diffusion Process
Forward (diffusion):
x_0 (real image) → add noise → x_1 → add noise → ... → x_T (pure noise)
Reverse (generation): x_T (pure noise) → remove noise → x_{T-1} → ... → x_0 (generated image)
Learning: Train network to predict removed noise at each step
Mathematical Formulation
Forward process (known):
q(x_t | x_0) = N(x_t; sqrt(1-β_t) * x_{t-1}, β_t * I)
Reverse process (learn): p_θ(x_{t-1} | x_t) ≈ N(x_{t-1}; μ_θ(x_t, t), Σ_θ(x_t, t))
Loss: Predict noise added at each step L = E[||ε - ε_θ(x_t, t)||^2]
Implementation
import torch
import torch.nn as nn import math
class DiffusionModel(nn.Module): def __init__(self, image_channels=3, time_channels=128, hidden_channels=64): super().__init__() self.image_channels = image_channels
# Timestep embedding self.time_embed = nn.Sequential( nn.Linear(1, time_channels), nn.SiLU(), nn.Linear(time_channels, time_channels) )
# U-Net-like architecture self.encoder = nn.Sequential( nn.Conv2d(image_channels + time_channels, hidden_channels, 3, padding=1), nn.ReLU(), nn.Conv2d(hidden_channels, hidden_channels, 3, padding=1), nn.ReLU() )
self.decoder = nn.Sequential( nn.Conv2d(hidden_channels, hidden_channels, 3, padding=1), nn.ReLU(), nn.Conv2d(hidden_channels, image_channels, 3, padding=1) )
def forward(self, x_t, t): """ x_t: (batch, 3, height, width) noisy image at timestep t t: (batch,) timestep (0 to T-1)
Returns: predicted noise """ # Embed timestep t_embed = self.time_embed(t.unsqueeze(-1).float() / 1000.0) # (batch, time_channels)
# Expand to spatial dims t_embed = t_embed.unsqueeze(-1).unsqueeze(-1) # (batch, time_channels, 1, 1) t_embed = t_embed.expand(-1, -1, x_t.shape[2], x_t.shape[3]) # broadcast
# Concatenate image and time x = torch.cat([x_t, t_embed], dim=1) # (batch, 3 + time_channels, height, width)
# Encode encoded = self.encoder(x)
# Decode noise_pred = self.decoder(encoded)
return noise_pred
def schedule_noise(t, T=1000): """Linear noise schedule""" beta = 0.0001 + t / T * (0.02 - 0.0001) alpha = 1 - beta return alpha, beta
def add_noise(x_0, t, noise): """Add noise to image according to schedule""" alpha, beta = schedule_noise(t) alpha_cumprod = torch.cumprod(alpha, dim=0)[t]
x_t = torch.sqrt(alpha_cumprod) * x_0 + torch.sqrt(1 - alpha_cumprod) * noise return x_t
# Training model = DiffusionModel() optimizer = torch.optim.Adam(model.parameters(), lr=1e-4)
for epoch in range(100): for images in dataloader: # Sample random timestep t = torch.randint(0, 1000, (images.shape[0],))
# Sample random noise noise = torch.randn_like(images)
# Add noise to images x_t = add_noise(images, t, noise)
# Predict noise pred_noise = model(x_t, t)
# Loss loss = nn.functional.mse_loss(pred_noise, noise)
optimizer.zero_grad() loss.backward() optimizer.step()
# Sampling @torch.no_grad() def sample(model, shape, T=1000): """Generate image by reverse diffusion""" x_t = torch.randn(shape)
for t in range(T-1, 0, -1): noise_pred = model(x_t, torch.tensor(t))
# Update x_t alpha, beta = schedule_noise(t) x_t = (x_t - beta * noise_pred) / torch.sqrt(alpha)
# Add noise back (except last step) if t > 1: z = torch.randn_like(x_t) x_t = x_t + torch.sqrt(beta) * z
return x_t
Why Diffusion Models?
GANs:
- Fast generation
- Mode collapse (generates limited variety)
- Training instability
Diffusion Models:
- Slower generation (iterative)
- Better quality and diversity
- Stable training (simple MSE loss)
Modern approach: Use diffusion for training, distill to fast model for inference
Benchmarks
Image Generation (ImageNet 256×256)
BigGAN (GAN):
- FID: 9.0
- Training: Complex, unstable
Diffusion Model:
- FID: 3.85
- Training: Simple, stable
Diffusion beats GAN on quality!
Conclusion
Diffusion models revolutionized generative modeling. By learning to reverse a simple noise process, they achieve superior quality and stability. Understanding the forward/reverse diffusion process is essential for modern AI image generation. Next: exploring conditional diffusion and class-guided generation.
