Custom (from-scratch) implementation of Denoising Diffusion Probabilistic Models (DDPM) with U-Net architecture, built entirely from the ground up for deep learning research and experimentation.
AleDiffuser is a complete, educational implementation of diffusion models that demonstrates the inner workings of state-of-the-art generative AI. Every componentβfrom the U-Net architecture to the diffusion processβis implemented without relying on high-level abstractions, making it perfect for learning and experimentation.
- β¨ Complete DDPM Implementation - Full forward and reverse diffusion processes
- ποΈ Custom U-Net Architecture - ResNet blocks, spatial attention, and skip connections
- π― Conditional Generation - Class-conditional image synthesis with classifier-free guidance
- π Flexible Configuration - YAML/JSON config system for reproducible experiments
- π§ Modular Design - Clean, extensible codebase for research and development
- π Production Ready - Training scripts, checkpointing, and evaluation utilities
The core diffusion model implements the mathematical framework from Ho et al. 2020:
Forward Process (Noise Addition):
q(x_t | x_0) = π(x_t; βαΎ±_t x_0, (1 - αΎ±_t)I)
Reverse Process (Denoising):
p_ΞΈ(x_{t-1} | x_t) = π(x_{t-1}; ΞΌ_ΞΈ(x_t, t), Ξ£_ΞΈ(x_t, t))
Custom implementation featuring:
- Encoder Path: Progressive downsampling with ResNet blocks
- Bottleneck: Self-attention layers for global context
- Decoder Path: Symmetric upsampling with skip connections
- Time Embedding: Sinusoidal positional encoding for timestep information
- Conditional Embedding: Optional class conditioning for controlled generation
Input (3Γ32Γ32)
β
Conv + ResNet Blocks (128)
β
Downsample + Attention (256)
β
Downsample + Attention (512)
β
Bottleneck + Self-Attention
β
Upsample + Attention (256)
β
Upsample + Attention (128)
β
Output (3Γ32Γ32)
# Clone the repository
git clone https://github.com/AlejandroParedesLT/alediffuser
cd alediffuser
# Create virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install dependencies
pip install torch torchvision matplotlib pyyaml numpy- Python 3.8+
- PyTorch 2.0+
- torchvision
- matplotlib
- PyYAML
- numpy
Create a config file configs/cifar10_experiment.yaml:
# Model Architecture
TIME: 1000
in_channels: 3
out_channels: 3
num_classes: 10
recommended_steps: [1, 2, 2, 2]
recommended_attn_step_indexes: [1, 2, 3]
p_cond: 0.2
# Training Hyperparameters
EPOCHS: 100
batch_size: 128
lr: 0.001
weight_decay: 0.001
beta1: 0.9
beta2: 0.999
# Learning Rate Schedule
alpha_max: 0.0006
alpha_min: 0.000006
T_w: 1000
T_c: 15000
# Output
PATH_TO_SAVE_MODEL: './checkpoints/exp1_T1000_epochs100.pth'
ckpt_path: './outputs'
prefix_name_experiment: 'cifar10_ddpm'
# Hardware
device: 'cuda'
dtype: 'float32'
mixed_precision: false
seed: 42# Basic training
python train.py --config configs/cifar10_experiment.yaml
# With overrides
python train.py --config configs/cifar10_experiment.yaml \
--batch_size 256 \
--learning_rate 0.0005 \
--num_epochs 200
# Debug mode
python train.py --config configs/cifar10_experiment.yaml --debug
# Resume from checkpoint
python train.py --config configs/cifar10_experiment.yaml \
--resume_from checkpoints/checkpoint_epoch_50.pthimport torch
from alediffuser.models.ddpm import DDPM
from alediffuser.models.unet import UNet
# Load trained model
device = 'cuda' if torch.cuda.is_available() else 'cpu'
model = DDPM(
T=1000,
p_cond=0.2,
eps_model=UNet(
in_channels=3,
out_channels=3,
T=1001,
num_classes=10,
device=device,
dtype=torch.float32
),
device=device,
dtype=torch.float32
)
model.load_state_dict(torch.load('checkpoints/model.pth'))
# Generate samples for each class
samples = model.sample(
n_samples=10,
size=(3, 32, 32),
classes=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
w=0.2 # Classifier-free guidance weight
)
# Save results
from torchvision.utils import save_image, make_grid
grid = make_grid(samples, nrow=10)
save_image(grid, 'generated_samples.png')alediffuser/
βββ alediffuser/
β βββ core/
β β βββ modules.py # Basic building blocks (ResNet, Attention, etc.)
β βββ models/
β β βββ ddpm.py # DDPM implementation
β β βββ unet.py # U-Net architecture
β βββ training/
β βββ data/
β β βββ cifar10.py # Data loading utilities
β βββ train.py # Training loop
βββ configs/
β βββ cifar10_experiment.yaml # Example configuration
βββ train.py # Main training script
βββ requirements.txt
βββ README.md
Sinusoidal positional encoding for timestep information:
PE(pos, 2i) = sin(pos / 10000^(2i/d_model))
PE(pos, 2i+1) = cos(pos / 10000^(2i/d_model))
Residual block with:
- Group normalization
- SiLU/Swish activation
- Dropout regularization
- Time embedding injection
- Skip connections
Multi-head self-attention mechanism for capturing global dependencies in feature maps.
Spatial resolution changes with optional convolution for learnable downsampling/upsampling.
Training:
- Samples random timestep
t - Adds noise according to schedule:
x_t = βαΎ±_tΒ·x_0 + β(1-αΎ±_t)Β·Ξ΅ - Predicts noise
Ξ΅_ΞΈ(x_t, t, c)with optional conditioning - Computes MSE loss between predicted and actual noise
Sampling:
- Starts from pure noise
x_T ~ π(0, I) - Iteratively denoises:
x_{t-1} = ΞΌ_ΞΈ(x_t, t) + Ο_tΒ·z - Supports classifier-free guidance for conditional generation
Encoder:
- Initial convolution:
3 β 128channels - 4 resolution levels with ResNet blocks
- Self-attention at specified levels
- Progressive channel increase:
128 β 256 β 512 β 1024
Bottleneck:
- ResNet β Attention β ResNet
- Maximum feature compression
Decoder:
- Symmetric to encoder with skip connections
- Progressive upsampling and channel reduction
- Attention at corresponding levels
| Parameter | Description | Default |
|---|---|---|
TIME |
Number of diffusion timesteps | 1000 |
in_channels |
Input image channels | 3 |
out_channels |
Output image channels | 3 |
num_classes |
Number of conditional classes | 10 |
recommended_steps |
Channel multipliers per level | [1, 2, 2, 2] |
recommended_attn_step_indexes |
Levels with attention | [1, 2, 3] |
p_cond |
Unconditional training probability | 0.2 |
| Parameter | Description | Default |
|---|---|---|
EPOCHS |
Training epochs | 100 |
batch_size |
Batch size | 128 |
lr |
Learning rate | 0.001 |
weight_decay |
L2 regularization | 0.001 |
beta1, beta2 |
Adam optimizer betas | 0.9, 0.999 |
| Parameter | Description |
|---|---|
alpha_max |
Peak learning rate |
alpha_min |
Minimum learning rate |
T_w |
Warmup iterations |
T_c |
Total iterations |
from torch.utils.data import Dataset, DataLoader
class CustomDataset(Dataset):
def __init__(self, data_path):
# Your data loading logic
pass
def __getitem__(self, idx):
# Return (image, label) tuple
pass
# In your training script
custom_data = DataLoader(
CustomDataset('path/to/data'),
batch_size=128,
shuffle=True
)# In DDPM.__init__
# Linear schedule (default)
beta_schedule = torch.linspace(1e-4, 0.02, T+1)
# Cosine schedule
beta_schedule = self.cosine_beta_schedule(T+1)
def cosine_beta_schedule(self, timesteps, s=0.008):
steps = timesteps + 1
x = torch.linspace(0, timesteps, steps)
alphas_cumprod = torch.cos(((x / timesteps) + s) / (1 + s) * torch.pi * 0.5) ** 2
alphas_cumprod = alphas_cumprod / alphas_cumprod[0]
betas = 1 - (alphas_cumprod[1:] / alphas_cumprod[:-1])
return torch.clip(betas, 0.0001, 0.9999)Adjust the guidance weight w during sampling:
# w = 0: Unconditional generation
# w > 0: Stronger conditioning
# w < 0: Negative conditioning (avoid class)
samples = model.sample(
n_samples=10,
size=(3, 32, 32),
classes=[5] * 10, # Generate 10 images of class 5
w=0.5 # Moderate guidance
)[Include generated sample images here]
- Final Validation Loss: ~0.015
- Training Time: ~8 hours on RTX 3090
- FID Score: [Add your FID score]
Contributions are welcome! Areas for improvement:
- Additional noise schedules (cosine, exponential)
- Latent diffusion support
- Multi-GPU training
- Evaluation metrics (FID, IS)
- Additional datasets (ImageNet, custom)
- Web interface for interactive generation
This implementation is based on:
- DDPM: Denoising Diffusion Probabilistic Models - Ho et al., 2020
- U-Net: U-Net: Convolutional Networks for Biomedical Image Segmentation - Ronneberger et al., 2015
- Classifier-Free Guidance: Classifier-Free Diffusion Guidance - Ho & Salimans, 2022
MIT License - feel free to use this code for learning, research, or production!
Built from scratch with inspiration from the diffusion models research community. Special thanks to the authors of the original DDPM paper for their groundbreaking work.
Made with by Alejandro Paredes La Torre