Reproduction of DDPM (Ho et al. 2020, NeurIPS 2020) and DDIM (Song et al. 2020, ICLR 2021) from pretrained DDPM weights.
We recommend using uv for a faster setup.
Linux / macOS
uv venv
source .venv/bin/activate
uv pip install -r requirements.txt
uv pip install -e .
Windows
uv venv
.venv\Scripts\activate
uv pip install -r requirements.txt
uv pip install -e .
Tested with Python 3.10+, PyTorch 2.1+, CUDA 13.0.
Each notebook can be executed end-to-end:
# Notebook 1: sanity checks, noise schedule, DDIM vs DDPM at fixed seed
jupyter nbconvert --to notebook --execute notebooks/01_foundations.ipynb
# Notebook 2: η × NFE sweep, FID table, Pareto plots (LONG TO RUN!! check parameters in configs)
jupyter nbconvert --to notebook --execute notebooks/02_eta_nfe_sweep.ipynb
# Notebook 3: DDIM inversion, PSNR curve, SLERP/LERP interpolation
jupyter nbconvert --to notebook --execute notebooks/03_inversion_and_interpolation.ipynb
DiffusersDDPM.
The following results were obtained using 3072 samples (configurable via configs/cifar10.yaml: sampling.num_samples_fid).
| NFE | 10 | 20 | 50 | 100 |
|---|---|---|---|---|
| $\eta=0.0$ (DDIM) | 22.00 | 15.21 | 12.97 | 12.52 |
| $\eta=0.2$ | 22.54 | 15.55 | 12.97 | 12.42 |
| $\eta=0.5$ | 24.44 | 15.96 | 13.38 | 12.62 |
| $\eta=1.0$ (DDPM) | 49.35 | 25.92 | 16.13 | 13.55 |
(For reference, see Song et al. 2020, Table 1, 50K samples)
Hardware Note: For $\eta = 1$ and NFE = 10, we recorded an unusually high execution time. This anomaly is likely due to hardware thermal throttling during that specific run.
DDIM inversion exploits the fact that the deterministic ($\eta=0$) sampling process is invertible. We can run the DDIM forward (noise-adding) direction using the learned model $\epsilon_\theta$ to obtain a latent $x_T$, such that running DDIM sampling backward from $x_T$ successfully reconstructs $x_0$.
The forward DDIM step (Song et al. 2020, implicit Eq. 12 reversed, $\eta=0$) is defined as:
$$x_t = \sqrt{\frac{\alpha_t}{\alpha_{t-1}}} \cdot x_{t-1} + \sqrt{1 - \alpha_t} \cdot \left( 1 - \sqrt{ \frac{\alpha_t}{\alpha_{t-1}} \cdot \frac{1-\alpha_{t-1}}{1-\alpha_t} } \right) \cdot \epsilon_\theta(x_{t-1}, t-1)$$
Equivalently, this acts as an explicit Euler method on the probability-flow ODE in the forward (increasing $t$) direction. The approximation inherently improves with more steps. Below is the inversion of 4 real CIFAR-10 training images to $x_T$, followed by their resampling:

By sampling two latents $z_1, z_2 \sim \mathcal{N}(0,I)$ and interpolating between them via Spherical Linear Interpolation (SLERP), we reproduce Fig. 8 of Song et al. 2020. The semantic content transitions smoothly because the DDIM ($\eta=0$) process acts as a continuous, invertible mapping.
SLERP Formula:
$$\text{slerp}(z_1, z_2, \alpha) = \frac{\sin((1-\alpha)\theta)}{\sin(\theta)} \cdot z_1 + \frac{\sin(\alpha\theta)}{\sin(\theta)} \cdot z_2$$

We use clean-fid with mode="legacy_pytorch", not mode="clean".
Why legacy_pytorch? The DDIM and DDPM papers compute FID using a PyTorch
implementation with bilinear resizing. clean-fid in legacy_pytorch mode
reproduces this exact resize kernel, making our numbers directly comparable to
Song et al. 2020 Table 1.
| Dataset | Source | Image size | EMA |
|---|---|---|---|
| CIFAR-10 | VainF/Diff-Pruning release v0.0.1 | 32×32 | ✓ |
| LSUN Church | google/ddpm-ema-church-256 (HF) | 256×256 | ✓ |
| LSUN Bedroom | google/ddpm-ema-bedroom-256 (HF) | 256×256 | ✓ |
All models use a linear β schedule (β_start=1e-4, β_end=0.02, T=1000) and predict ε (noise).
CIFAR-10: The original Ho et al. 2020 EMA checkpoint converted to diffusers format by VainF. It is downloaded automatically on first use.
subfolder parameterdiffusers stores models in two layouts, which affect how they are loaded:
Standalone model format — used by the Google checkpoints
Pipeline format — used by the VainF CIFAR-10 checkpoint
src/models.py handles both cases automatically; callers never need to specify
a subfolder.
Ho et al. 2020 — "Denoising Diffusion Probabilistic Models", NeurIPS 2020. https://arxiv.org/abs/2006.11239
Song et al. 2020 — "Denoising Diffusion Implicit Models", ICLR 2021. https://arxiv.org/abs/2010.02502
Song et al. 2021 — "Score-Based Generative Modeling through Stochastic Differential Equations", ICLR 2021. https://arxiv.org/abs/2011.13456
16 commits
2 commits
Jupyter Notebook
99.6%
Reproduction of DDPM (Ho et al. 2020, NeurIPS 2020) and DDIM (Song et al. 2020, ICLR 2021) from pretrained DDPM weights.
We recommend using uv for a faster setup.
Linux / macOS
uv venv
source .venv/bin/activate
uv pip install -r requirements.txt
uv pip install -e .
Windows
uv venv
.venv\Scripts\activate
uv pip install -r requirements.txt
uv pip install -e .
Tested with Python 3.10+, PyTorch 2.1+, CUDA 13.0.
Each notebook can be executed end-to-end:
# Notebook 1: sanity checks, noise schedule, DDIM vs DDPM at fixed seed
jupyter nbconvert --to notebook --execute notebooks/01_foundations.ipynb
# Notebook 2: η × NFE sweep, FID table, Pareto plots (LONG TO RUN!! check parameters in configs)
jupyter nbconvert --to notebook --execute notebooks/02_eta_nfe_sweep.ipynb
# Notebook 3: DDIM inversion, PSNR curve, SLERP/LERP interpolation
jupyter nbconvert --to notebook --execute notebooks/03_inversion_and_interpolation.ipynb
DiffusersDDPM.
The following results were obtained using 3072 samples (configurable via configs/cifar10.yaml: sampling.num_samples_fid).
| NFE | 10 | 20 | 50 | 100 |
|---|---|---|---|---|
| $\eta=0.0$ (DDIM) | 22.00 | 15.21 | 12.97 | 12.52 |
| $\eta=0.2$ | 22.54 | 15.55 | 12.97 | 12.42 |
| $\eta=0.5$ | 24.44 | 15.96 | 13.38 | 12.62 |
| $\eta=1.0$ (DDPM) | 49.35 | 25.92 | 16.13 | 13.55 |
(For reference, see Song et al. 2020, Table 1, 50K samples)
Hardware Note: For $\eta = 1$ and NFE = 10, we recorded an unusually high execution time. This anomaly is likely due to hardware thermal throttling during that specific run.
DDIM inversion exploits the fact that the deterministic ($\eta=0$) sampling process is invertible. We can run the DDIM forward (noise-adding) direction using the learned model $\epsilon_\theta$ to obtain a latent $x_T$, such that running DDIM sampling backward from $x_T$ successfully reconstructs $x_0$.
The forward DDIM step (Song et al. 2020, implicit Eq. 12 reversed, $\eta=0$) is defined as:
$$x_t = \sqrt{\frac{\alpha_t}{\alpha_{t-1}}} \cdot x_{t-1} + \sqrt{1 - \alpha_t} \cdot \left( 1 - \sqrt{ \frac{\alpha_t}{\alpha_{t-1}} \cdot \frac{1-\alpha_{t-1}}{1-\alpha_t} } \right) \cdot \epsilon_\theta(x_{t-1}, t-1)$$
Equivalently, this acts as an explicit Euler method on the probability-flow ODE in the forward (increasing $t$) direction. The approximation inherently improves with more steps. Below is the inversion of 4 real CIFAR-10 training images to $x_T$, followed by their resampling:

By sampling two latents $z_1, z_2 \sim \mathcal{N}(0,I)$ and interpolating between them via Spherical Linear Interpolation (SLERP), we reproduce Fig. 8 of Song et al. 2020. The semantic content transitions smoothly because the DDIM ($\eta=0$) process acts as a continuous, invertible mapping.
SLERP Formula:
$$\text{slerp}(z_1, z_2, \alpha) = \frac{\sin((1-\alpha)\theta)}{\sin(\theta)} \cdot z_1 + \frac{\sin(\alpha\theta)}{\sin(\theta)} \cdot z_2$$

We use clean-fid with mode="legacy_pytorch", not mode="clean".
Why legacy_pytorch? The DDIM and DDPM papers compute FID using a PyTorch
implementation with bilinear resizing. clean-fid in legacy_pytorch mode
reproduces this exact resize kernel, making our numbers directly comparable to
Song et al. 2020 Table 1.
| Dataset | Source | Image size | EMA |
|---|---|---|---|
| CIFAR-10 | VainF/Diff-Pruning release v0.0.1 | 32×32 | ✓ |
| LSUN Church | google/ddpm-ema-church-256 (HF) | 256×256 | ✓ |
| LSUN Bedroom | google/ddpm-ema-bedroom-256 (HF) | 256×256 | ✓ |
All models use a linear β schedule (β_start=1e-4, β_end=0.02, T=1000) and predict ε (noise).
CIFAR-10: The original Ho et al. 2020 EMA checkpoint converted to diffusers format by VainF. It is downloaded automatically on first use.
subfolder parameterdiffusers stores models in two layouts, which affect how they are loaded:
Standalone model format — used by the Google checkpoints
Pipeline format — used by the VainF CIFAR-10 checkpoint
src/models.py handles both cases automatically; callers never need to specify
a subfolder.
Ho et al. 2020 — "Denoising Diffusion Probabilistic Models", NeurIPS 2020. https://arxiv.org/abs/2006.11239
Song et al. 2020 — "Denoising Diffusion Implicit Models", ICLR 2021. https://arxiv.org/abs/2010.02502
Song et al. 2021 — "Score-Based Generative Modeling through Stochastic Differential Equations", ICLR 2021. https://arxiv.org/abs/2011.13456
16 commits
2 commits
Jupyter Notebook
99.6%