Diffusion from scratch
A class-conditional diffusion model written from PyTorch primitives, trained on MNIST digits and FashionMNIST clothing. Each row shows one sample of every class, all generated from the same starting noise, so every change you see comes from the setting you move.
Loading samples…
Guidance and sampler steps
0 = unconditional, 1 = plain conditional, higher = stronger pull toward the requested class.
DDIM can skip timesteps; DDPM takes all 1000 (shown at guidance 2).
Live sampling
Running against the local model. Every option is free-form here.
What the experiments show
FID is measured on 1,000 samples per setting in a small classifier's feature space (lower is better; real images score about 3), so it compares settings within this project, not with published numbers.
- DDIM matches 1000-step DDPM with 20× fewer steps. On MNIST at guidance 2, 50-step DDIM reaches the same class accuracy (99.9% vs 99.9%) at a lower FID (19.0 vs 28.0), and FashionMNIST agrees (FID 13.8 vs 24.3).
- The gap comes from DDPM's injected noise, not its step count. Turning DDIM's noise (η) up from 0 to 1 at 50 steps moves FID from 19.0 to 30.1, close to DDPM.
- Guidance trades variety for fidelity. Guidance 1 gives the best FID (8.5) at 92.7% accuracy; guidance 2 reaches 99.9% accuracy at FID 19.0.
- A cosine noise schedule helps guided sampling but hurts unguided sampling. Against a linear model trained identically, it cuts 20-step DDIM FID at guidance 2 from 17.2 to 9.5, but at guidance 1 FID rises from 9.5 to 18.8.
Full tables, the FashionMNIST results, and the schedule ablation are in the README; the math behind each sampler is in NOTES.md.