Author: Oankar Patil
Five stochastic processes with closed-form ground truth: scalar OU, Brownian motion, geometric Brownian motion, a vector OU / stochastic oscillator, and a 1D stochastic heat equation
These are used to train and, more importantly, analyze denoising diffusion models, through every stage of the pipeline: data, forward process, filter, training loss, sampler, output statistics.
Main Findings: First, in five separately documented instances the training loss sat exactly on its analytic optimum while calibrated sample statistics measured real distributional biases between
The pipeline follows the reading-group note "A Fully Worked 1D Example: From a Scalar Wiener Process to a U-Net Diffusion Model" (Algorithms 1–5); the additional process beyond scalar OU, the verification classes, and the findings below are this repository's additions. This is part of a larger effort on autoregressive / space–time diffusion project.
This project focuses on the data sources are chosen so that the dataset has exact statistics.
| process | dynamics | new difficulty |
|---|---|---|
ou |
baseline | |
bm |
nonstationary, singular cov | |
gbm |
non-Gaussian, positive | |
vou / osc
|
matrix dynamics, |
|
heat |
spatial field, stiff spectrum |
All five sit behind one abstraction (ou_diffusion/processes/): a Process is an exact trajectory sampler plus its own ground truth, validation targets, the exact one-step transition kernel
| Stage | Math | Module |
|---|---|---|
| 1. Data | exact process sampler; |
ou_diffusion/processes/ |
| 2. Forward diffusion |
|
schedule.py |
| 3. Filtering (OU demo) | scalar Kalman predict/update on |
kalman.py |
| 4. Reverse process | 1D U-Net |
unet1d.py, train.py, sample.py
|
| Validation | per-process targets, oracle, floors, calibrated z-statistics |
processes/, oracle.py
|
The U-Net is the note's 3-resolution design (--lr-final); --normalize adds exactly-invertible per-channel standardization with the printed loss floor rescaled consistently.
Two clocks: Physical time
Loss floor: For Gaussian data oracle.gaussian_loss_floor, any Gaussian process, scalar or vector.)
Analytic oracle: The optimal noise predictor for Gaussian data is linear and known: scripts/verify_optimal_denoiser.py) isolates sampler/schedule error from learning error, a decomposition usually impossible in generative modeling. For non-Gaussian processes the linear-denoiser bound (Gaussian floor of the empirical covariance) plays the complementary role: a loss below it proves the network beats every linear denoiser.
Calibrated statistics: Output statistics are checked against exact targets, and because the deviation statistics are norms with strictly positive null expectation, raw percentages conflate estimator noise with model bias. Every vector-process check is therefore calibrated against exact-sampler replications at the same sample size: the report's target column is the finite-sample noise-floor mean.
Worked demonstration (scalar OU,
| marginal variance | lag-1 autocorrelation | |
|---|---|---|
| exact OU target | 0.5000 | 0.9512 |
| analytic oracle |
0.491 | 0.9500 |
| trained 1D U-Net | 0.4877 | 0.9494 |
Training loss plateaus at 0.10–0.12 around the 0.1071 floor (per-step wander is minibatch composition: the per-$k$ floor spans ≈1 at
The note suggests
| oracle marginal variance (target 0.5) | ||
|---|---|---|
| 200 | 0.132 | 0.365 (−27%) |
| 1000 | 0.491 (−1.8%) |
This reproduces the zero-terminal-SNR issue known in literature (Lin et al., 2024) with the learning component ruled out. All commands thus instead below default to
Summary: Across all three vector-valued processes the conv-U-Net + uniform-$k$
I'd suggest making a venv first and then activating it and doing the following:
pip install -r requirements.txt # numpy, torch, matplotlib
# Full runs (GPU with --device cuda):
python -m scripts.run --process ou --K 1000 --steps 6000 --save-samples samples.npy
python -m scripts.run --process bm --mu 0.3 --K 1000 --steps 6000
python -m scripts.run --process gbm --K 1000 --steps 6000 --baseline
python -m scripts.run --process vou --K 1000 --steps 16000
python -m scripts.run --process osc --K 1000 --steps 16000 --base-channels 64 --normalize --lr-final 2e-5
python -m scripts.run --process heat --K 1000 --steps 16000 --base-channels 64 --n-samples 10000
# Optional: Kalman filtering demo on noisy measurements (OU)
python -m scripts.run --process ou --K 1000 --steps 6000 --kalman-demo --R 0.5ou_diffusion/
processes/ data sources with exact targets (the Process interface)
base.py exact_sample / validate / mean / covariance / transition
ou.py Ornstein-Uhlenbeck (stationary, Gaussian)
brownian.py Brownian motion +- drift (nonstationary, Gaussian)
gbm.py geometric Brownian motion (non-Gaussian, positive, skewed)
vector_ou.py vector OU + stochastic oscillator (matrix dynamics, d = 2)
heat.py 1D stochastic heat equation (spatial field, stiff mode spectrum)
baseline.py FittedGaussianBaseline: moment-matched control model
normalize.py ChannelNormalizer: exactly-invertible per-channel standardization
oracle.py AnalyticGaussianDenoiser + gaussian_loss_floor (any Gaussian process)
ou_process.py Stage 1: exact OU sampler (Algorithm 1)
schedule.py Stage 2: DDPM schedule + q_sample (Eq. 6-8)
kalman.py Stage 3: scalar Kalman filter (Algorithm 3)
unet1d.py Stage 4: 1D U-Net eps-predictor (channels = state dims)
train.py Stage 4: training loop (Algorithm 4) + EMA + cosine LR decay
sample.py Stage 4: ancestral sampler (Algorithm 5)
validate.py OU statistics + irreducible loss floor (Phase-A interface)
scripts/
run.py process-agnostic end-to-end pipeline
run_ou.py Phase-A alias (forwards to run.py --process ou)
verify_optimal_denoiser.py analytic oracle per process, K sweep
plot_samples.py real-vs-generated figure
tests/ per-stage and per-process unit tests
Current: Five exactly-verified processes (scalar OU, Brownian motion, geometric Brownian motion, vector OU / stochastic oscillator, 1D stochastic heat equation).
Next: autoregressive diffusion on the same processes, validated against the exact conditionals every process already exposes through transition() one step ahead
- Reading-group note: A Fully Worked 1D Example: From a Scalar Wiener Process to a U-Net Diffusion Model (2026) — pipeline design (Algorithms 1–5).
- Ho, Jain, Abbeel. Denoising Diffusion Probabilistic Models. NeurIPS 2020.
- Lin, Liu, Li, Yang. Common Diffusion Noise Schedules and Sample Steps are Flawed. WACV 2024 — zero terminal SNR.
- Särkkä. Bayesian Filtering and Smoothing. CUP 2013 — Kalman filtering background.
- Chen et al. Diffusion Forcing: Next-token Prediction Meets Full-Sequence Diffusion. NeurIPS 2024; Ruhe et al. Rolling Diffusion Models. ICML 2024 — next-phase directions.