Score matching, the reverse-time SDE and the probability-flow ODE
Before this lesson: SDEs, Euler–Maruyama and the Fokker–Planck equation (lesson 12); the multivariate Gaussian and Gaussian conditioning (probability 05). For the machine-learning side of diffusion models (networks, training in practice), see generative models 06, 07 and 09; this lesson focuses on the mathematics and does not repeat them. Time: about 110 minutes, plus the notebook.
Why this matters #
- Ensemble weather forecasts. GenCast (Price et al., Nature 2025) produces each ensemble member of a 15-day global forecast as one sample of a conditional diffusion model, conditioned on the two most recent weather states. The cost of an ensemble is members × sampler steps × network cost, so the choice of sampler matters.
- Downscaling and super-resolution. Conditional diffusion models generate fine-scale fields (precipitation, wind) that are consistent with a coarse simulation, with realistic small-scale variability instead of a blurred mean.
- Priors for inverse problems and data assimilation. By Bayes' rule, the score of a posterior is the score of the prior plus the score of the likelihood. A learned score is a prior for the state of the atmosphere or the subsurface (score-based data assimilation, Rozet and Louppe 2023).
- Seismic waveforms. Denoising diffusion models generate synthetic earthquake records conditioned on magnitude, distance and site (Palgunadi et al. 2024; Jung et al. 2025).
- Every practical choice in these systems (SDE or ODE, which solver, how many steps, how to weight the loss over noise levels) follows from the three theorems of section 3.
1. Predict first #
2. The picture #
The score points toward high density #
The score of a density on is the vector field
A Gaussian example. For in 1D, , so . The score points toward the mean, and it is stronger when the variance is smaller. The constant disappears under the derivative.
This is true in general. If with an unknown normalising constant , then , and does not depend on . So . A score model never needs . This removes the main difficulty of energy-based models (generative models 06).
Noise smooths the data #
Add Gaussian noise of level : , with (the data) and . The density of is the convolution : every data point is smeared into a small Gaussian cloud.
- For small , is close to the data distribution.
- For large , is close to a wide Gaussian , which is easy to sample.
A diffusion model walks from large down to small and uses the score of at every level. For a Gaussian mixture everything is exact: noising keeps a mixture, , and its score is a weighted average of Gaussian scores,
The weights are the responsibilities: the probability that came from component . All figures and the notebook of this lesson use such closed forms instead of a trained network.
Move the noise level and drag the yellow point. Shading: the density of a noised 2D mixture with three components. Grey arrows: the direction of the score (long arrows are capped). The orange arrow starts at the point and has length ; it ends at the denoised point (Tweedie's formula, section 3). Notice two things: at small the field is strong and points to the nearest component; at large it is smooth and weak and points to the overall centre.
The score is a denoiser #
Section 3 proves Tweedie's formula:
The left side is the best guess (in mean squared error) of the clean sample, given the noisy one. So the score at a noisy point, times , is the step from that point to the average clean point it came from. Learning to denoise and learning the score are the same task.
Drag the noisy point and change . The data are (blue). Grey dashed: the noised density . Orange: the posterior of the clean value (scaled) and its mean, which is exactly . Bottom: the denoiser for every . For small it is close to the identity; for large it snaps every toward one of the two modes, with a jump between them. The preset worked example is section 4: , gives .
Sampling with the score: Langevin dynamics #
Lesson 12 showed that the SDE has as its stationary density. Its Euler–Maruyama discretisation is the unadjusted Langevin algorithm (ULA):
So a score alone is enough to sample. But Langevin dynamics with the score of the clean data has two problems. Between separated modes the density is almost zero, the score carries no information there, and a chain rarely crosses from one mode to another. And the chain needs a very long time to reach the right weights of the modes. Smoothing the target with noise fixes both problems, at the price of sampling a blurred distribution. The solution of diffusion models is to use all noise levels in sequence, from large to small.
Press Run, then compare the presets. 600 Langevin chains with the exact score of all start at , in the smaller mode. Top: three chains over the iterations. Bottom: the histogram of all chains against the target (blue). Sharp target: the chains stay in the left mode; the share with stays far below 0.7. Smoothed target: they mix quickly. Step too large: the histogram is too wide, because ULA has a bias of order (a weak error, lesson 12).
What is the score of in 1D?
, and its derivative is . It points toward the mean. The third option is itself (without the constant), not its derivative; the last one is the noise-prediction target written with the wrong scale.
3. Definitions and main results #
Score matching #
We want a model of the score of . The natural loss is explicit score matching (ESM):
We cannot compute it, because the target is unknown. Hyvärinen (2005) removed the target by integration by parts; the result needs the trace of the Jacobian of , which costs backward passes in dimension . Denoising score matching avoids both problems.
Theorem 1 (denoising score matching; Vincent 2011) #
Let be the noising kernel. Its score is . Define the denoising score matching loss
If for , then , where does not depend on .
Why this is true (intuition). A noisy point could have come from many clean points . Each one gives a different target . The model cannot know which was used, so the best it can do is predict the average target at . That average is exactly the score of (step 3 below).
Proof
- Expand both squares: , with the target .
- The terms are equal in the two losses, because in both has the law .
- Key identity. Differentiate under the integral and use : . Divide by ; the factor is the posterior by Bayes' rule:
The marginal score is the posterior mean of the conditional score. 4. The cross terms are equal. By step 3 and the tower property : . 5. The remaining terms do not contain , so .
Consequences.
- Both losses have the same gradient in , so DSM trains toward the true score of . Over all functions, the minimiser is the conditional mean .
- The loss does not go to zero. Its minimum is , the conditional variance of the target given : . No model can predict the part of the noise that does not reveal.
- Tweedie's formula. From and step 3, , and this equals . One derivative more gives the posterior covariance, .
- All noise levels at once. Train one network , draw at random (for example log-uniform), and weight the loss by : . This is -prediction: a network predicts the noise and . The DDPM loss is the same loss for the kernel (generative models 08 compares the parameterisations).
Data in 1D, noise level . A noisy sample is . What does Tweedie's formula give for ?
, so and . Gaussian conditioning agrees: with equal variances 1 (data) and 1 (noise) the posterior mean is halfway between and the prior mean 2.
Noising SDEs and their marginals #
A diffusion model adds noise continuously with a forward SDE
with a drift , a scalar diffusion coefficient , and marginal densities . Two choices are standard (Song et al. 2021):
- Variance exploding (VE): . Then with . In this lesson, as in the EDM convention of Karras et al. (2022), , so and the noise level equals the time: .
- Variance preserving (VP): , . This is an OU process with a time-dependent rate (lesson 12): with .
In both cases is the data distribution scaled and convolved with a Gaussian, so a training sample is drawn in one step and the DSM loss applies at every .
Data are noised with the VE SDE . What is ?
The added variance is , and a Gaussian convolved with keeps its mean and adds the variances. The first option uses instead of . The last option forgets the data variance.
Theorem 2 (reverse-time SDE; Anderson 1982) #
Let solve the forward SDE on with marginals . Assume , and are smooth, , and the Fokker–Planck equation has a unique solution for a given initial density. In the reversed clock , the process
has for every . Written in the original clock (so ), this is the familiar form
Why the extra term. Running the forward SDE backward would undo the drift but would add more noise, not remove it. The term pushes every particle up the density, toward the data, strongly enough to undo the spreading of the noise and to compensate the fresh noise of the reverse process.
Proof (through the Fokker–Planck equation)
- In dimensions, with noise , the forward marginals solve (lesson 12, the -dimensional form).
- Let . Then .
- A candidate SDE has the Fokker–Planck equation .
- Make the two right-hand sides equal: we need . Use . Then the right side is , and works.
- Both processes start from and solve the same Fokker–Planck equation, so by uniqueness they have the same marginals.
This proof shows that the marginals agree, which is all a sampler needs. Anderson proved more: the law of the whole reversed path equals the law of the forward path run backward.
Euler–Maruyama for the reverse SDE. For the VE SDE of this lesson (, ), on a decreasing grid with and :
Press Play. First half: 1500 particles from are noised forward with (aqua paths); the histogram spreads into one wide bump. Second half: 1500 new particles drawn from run the reverse-time SDE with the exact score (orange paths, Euler–Maruyama, 200 steps). At every time the histogram follows the exact (blue), and at both modes come back with the weights 0.3 and 0.7.
Theorem 3 (probability-flow ODE; Song et al. 2021) #
The ODE
has the same marginals as the forward SDE, in either direction of time.
Proof
- Write the diffusion term as a flux: , because .
- The Fokker–Planck equation becomes . This is a continuity equation with the velocity , and no diffusion term.
- A continuity equation is exactly the density equation of the ODE (lesson 12 with ). Same equation, same initial density, so the same marginals.
For the VE SDE of this lesson the PF-ODE is . It has no noise, so a higher-order solver works well. Heun's method (two score evaluations per step) has global error : with and a step (negative when sampling),
Change the number of steps and press New noise. The same 1500 start points feed the reverse SDE (jagged paths, Euler–Maruyama) and the probability-flow ODE (smooth paths, Heun). The thick paths start at the same point and end at different places. Bottom: both end histograms match (blue). New noise changes only the SDE: the ODE result is a fixed map from noise to data. With 5–10 steps Heun on the ODE is more accurate. Switch the start to (the practical choice, slightly different from ): the SDE partly corrects the wrong start, the ODE keeps the error.
A family of samplers. The same flux trick shows that, for every , the backward process has the marginals . With you get the reverse SDE; with you get the PF-ODE. The amount of noise is a free design choice.
ODE or SDE?
- The ODE is a deterministic bijection between noise and data. It gives encodings, and exact log-likelihoods through the instantaneous change of variables (as for neural ODEs, lesson 03). With Heun and a good time grid it needs few steps (tens).
- The SDE adds fresh noise. The noise and the score drift pull samples back toward , so earlier errors (score errors, a wrong start distribution) are partly forgotten. It usually needs more steps; plain Euler–Maruyama is the usual solver.
- The time grid is geometric in (a constant ratio ), because the score changes on the scale of itself.
- The start. You cannot sample exactly. You start from , which is close to when is much larger than the data scale (the prior mismatch error).
In the probability-flow ODE , what is the coefficient ?
The flux rewrite gives the factor . The reverse SDE has because half of its score term undoes the forward diffusion and the other half compensates its own fresh noise; the ODE has no noise to compensate. With and no noise, samples come out too narrow (section 5).
4. Worked example #
(a) A Gaussian. Data in 1D, noise level .
- Noised density: variances add, so .
- Score at : .
- Tweedie: , that is .
- Check with Gaussian conditioning: prior variance 1, noise variance 1, so the posterior mean is . ✓
- Posterior variance from Tweedie's second-order formula: , so . Gaussian conditioning: . ✓
- DSM floor: . Here , so . Even the exact score has .
- PF-ODE with : and . Separate variables: , so and .
- From and : . One noise value gives one data value: this is the deterministic decoder.
(b) A mixture. and .
- Noising adds to each variance: .
- At , the two Gaussian scores are and .
- The responsibility of the right component: the log-densities differ by , that is . So and .
- Score: .
- Tweedie: . This is almost the posterior mean inside the right component alone, .
Far from both components, both Gaussian densities underflow to 0 in floating point (at each is about ), and becomes . Compute the responsibilities from the log-densities with a log-sum-exp (a softmax in log space).
5. In code #
The mixture score in closed form against a finite difference of , Tweedie's formula, Theorem 1 by Monte Carlo, the PF-ODE map of the worked example, and a check of the factor :
import numpy as np
from scipy.special import logsumexp
from scipy.integrate import solve_ivp
w, m, v0 = np.array([0.5, 0.5]), np.array([-2.0, 2.0]), 0.25 # p_0 = 0.5 N(-2, 0.25) + 0.5 N(2, 0.25)
def log_p(x, sigma):
"""log p_sigma(x): each component variance grows by sigma^2."""
V = v0 + sigma**2
return logsumexp(np.log(w) - 0.5 * np.log(2 * np.pi * V) - (x - m)**2 / (2 * V))
def score(x, sigma):
"""Closed form: responsibility-weighted Gaussian scores, responsibilities in log space."""
V = v0 + sigma**2
lw = np.log(w) - (x - m)**2 / (2 * V)
r = np.exp(lw - logsumexp(lw))
return np.sum(r * (-(x - m) / V))
sigma, x = 0.5, 1.0
fd = (log_p(x + 1e-5, sigma) - log_p(x - 1e-5, sigma)) / 2e-5
print(f"{score(x, sigma):.5f} {fd:.5f}") # 1.99732 1.99732
print(f"{x + sigma**2 * score(x, sigma):.4f}") # Tweedie: E[x0 | x = 1] = 1.4993
# Theorem 1 by Monte Carlo: p_0 = N(2, 1), sigma = 1. For every linear model s(x) = a x + b,
# J_DSM - J_ESM is the same constant 1/sigma^2 - 1/(1 + sigma^2) = 0.5.
rng = np.random.default_rng(0)
x0 = 2 + rng.standard_normal(2_000_000)
eps = rng.standard_normal(2_000_000)
xs = x0 + eps # samples of p_sigma = N(2, 2)
for a, b in [(0.0, 0.0), (-0.5, 1.0), (1.0, -3.0)]:
s = a * xs + b
J_dsm = np.mean((s + eps / 1.0)**2) # target -eps / sigma
J_esm = np.mean((s + (xs - 2) / 2)**2) # target: the true score of N(2, 2)
print(f"a = {a:4.1f}, b = {b:4.1f}: J_DSM - J_ESM = {J_dsm - J_esm:.3f}")
# a = 0.0, b = 0.0: J_DSM - J_ESM = 0.500
# a = -0.5, b = 1.0: J_DSM - J_ESM = 0.500
# a = 1.0, b = -3.0: J_DSM - J_ESM = 0.502
# PF-ODE dx/dt = -t * score for p_0 = N(2, 1) under dx = sqrt(2t) dW, so p_t = N(2, 1 + t^2)
sol = solve_ivp(lambda t, y: t * (y - 2) / (1 + t**2), (10.0, 0.0), [12.0], rtol=1e-10, atol=1e-12)
print(f"{sol.y[0, -1]:.4f} {2 + 10 / np.sqrt(101):.4f}") # 2.9950 2.9950
The third Monte Carlo value differs from 0.5 only by sampling error. Now the factor . In the reversed clock , a sampler changes the variance by . The right variance is that of , , so :
t = np.linspace(0.1, 5, 50)
V, dV_dtau = 1 + t**2, -2 * t # tau = T - t runs backward
g2 = 2 * t
kappa = -g2 / V # g^2 * score = kappa * (y - 2)
for name, kap, c2 in [("reverse SDE", kappa, g2), ("PF-ODE", kappa / 2, 0 * t), ("PF-ODE without 1/2", kappa, 0 * t)]:
print(f"{name:20s} max residual {np.max(np.abs(2 * kap * V + c2 - dV_dtau)):.1e}")
# reverse SDE max residual 1.8e-15
# PF-ODE max residual 8.9e-16
# PF-ODE without 1/2 max residual 1.0e+01
Both correct samplers keep the variance of exactly. Without the the residual is : the variance shrinks too fast, and the samples come out too narrow.
6. Where it shows up #
- Diffusion models. DDPM, score SDEs and EDM are all DSM plus a sampler for the reverse SDE or the PF-ODE. Fast samplers such as DDIM and DPM-Solver are ODE solvers for the PF-ODE; DPM-Solver is an exponential integrator that treats the linear part exactly (the idea from lesson 02; details in generative models 09).
- Weather and climate. GenCast (Price et al., Nature 2025) samples each ensemble member with a conditional diffusion model on the sphere, conditioned on the two most recent atmospheric states, and rolls forward in 12-hour steps. As of 2026, diffusion-based ensembles are one of the main families of ML weather models (lesson 16).
- Seismology. Denoising diffusion models generate three-component earthquake waveforms conditioned on magnitude, distance and site parameters (Palgunadi et al. 2024; Jung et al. 2025). The loss is the DSM loss of this lesson with the conditions as extra inputs: .
- Data assimilation and inverse problems. By Bayes' rule,
the normaliser drops out. A learned score is a prior for the state; the likelihood score comes from the observation model. Score-based data assimilation (Rozet and Louppe 2023) and diffusion posterior sampling (Chung et al. 2023) use Tweedie's formula to approximate cheaply. Compare with the classical filters of lesson 06 and the inverse problems of lesson 04.
- Physics. For a Boltzmann density , the score is the force divided by . Langevin dynamics has as stationary density (lesson 12). It is the sampler family above with , (so does not change) and .
7. Common mistakes #
- Wrong sign or wrong clock in the reverse SDE. In the original clock the drift is and ; in the reversed clock it is with . Mixing the two gives a process that adds noise instead of removing it.
- Dropping the in the PF-ODE. With drift and no noise, the samples contract too fast and come out too narrow (section 5).
- Using the loss value as a quality measure. The DSM loss has a floor that depends on and on the data. Compare against a closed-form score when you can.
- One noise level, or uniform on a linear scale. Most samples then sit at large . Use a log-uniform (or log-normal) and a geometric sampling grid.
- Dividing by zero at . The score scales like . Stop the sampler at a small and let the network predict (unit scale) instead of the score.
- Mixture responsibilities in linear space. They underflow far from the components. Use log-sum-exp.
- Judging samplers with small samples. A distance between two independent samples of the same distribution (for example the energy distance) is not zero. Compare against that noise floor.
8. Check yourself #
- Why does a score model not need the normalising constant of ?
Answer
If , then , and does not depend on . So . - Data in 1D, noise level , weight 1. What is the minimum value of ?
Answer
, where is the data variance. It is reached by the exact score of . - Write the probability-flow ODE of the variance-preserving SDE .
Answer
and , so . - A network predicts the noise. Give the score and the denoiser in terms of .
Answer
, and by Tweedie . - In step 4 of the proof of Theorem 2, why does follow?
Answer
We need . Since , the right side is , so works. - Why can the PF-ODE give exact log-likelihoods while the reverse SDE cannot do so directly?
Answer
The ODE flow is a bijection, so the instantaneous change of variables applies: . The SDE map is random, not a bijection, so there is no such formula.
Define the score of a density .
, a vector field that points toward higher density.
Why does a score model not need the normalising constant of ?
, and does not depend on .
Write the denoising score matching loss at noise level .
; it equals the explicit score matching loss plus a constant.
State Tweedie's formula.
.
Why does DSM learn the marginal score although its target is the conditional score ?
The marginal score is the posterior mean of the conditional score, , and a squared loss is minimised by the conditional mean.
Write the reverse-time SDE of .
, run backward from to .
What is the drift of the probability-flow ODE?
.
VE and VP noising SDEs: give and .
VE: , (here , so ). VP: , .
When would you sample with the PF-ODE instead of the reverse SDE?
For few steps (with a higher-order solver such as Heun), for deterministic encodings, and for exact likelihoods; the SDE forgets earlier errors better but needs more steps.
9. Interview angle #
- "What does a diffusion model actually learn?" The score of the noised data at every noise level, by denoising. Equivalently the noise , or the denoiser ; these are one function seen through linear maps.
- "Why add noise at all instead of doing score matching on clean data?" Data lie near a low-dimensional set, where the clean score is undefined or badly estimated away from the data. Noise fills the space and connects the modes, so sampling can move between them.
- "You have a budget of about 20 network evaluations. Which sampler?" The PF-ODE with a second-order solver (Heun) on a geometric (EDM) time grid; the SDE needs more steps.
- "Why does DSM work without the true score?" DSM = ESM + a constant (Theorem 1): the cross terms match because the marginal score is the posterior mean of the conditional score.
- "What is Tweedie's formula and where is it used?" ; in denoisers, and in likelihood approximations for posterior sampling in inverse problems and data assimilation.
10. Practice #
The notebook for this lesson runs in Colab or in the browser. It has five exercises, each with a check cell and a folded solution:
- The closed-form score of a noised 2D Gaussian mixture (responsibilities with log-sum-exp), checked against finite differences of .
- Tweedie's denoiser; check it on the worked example and against Gaussian conditioning.
- Theorem 1 by Monte Carlo: the DSM and ESM losses differ by the same constant for several models.
- Two samplers with the exact score: the reverse SDE (Euler–Maruyama) and the PF-ODE (Heun); compare their samples with the data by the energy distance and its noise floor.
- Learn the score from samples: fit a model that is linear in its parameters (random Fourier features) to the DSM targets by least squares, then sample with it.
11. Watch and read #
- Song, Sohl-Dickstein, Kingma, Kumar, Ermon and Poole, Score-Based Generative Modeling through Stochastic Differential Equations (ICLR 2021): §3.2 (reverse SDE), §3.3 (the training loss), §3.4 (VE and VP SDEs), §4.3 and Appendix D (probability-flow ODE).
- Yang Song, Generative Modeling by Estimating Gradients of the Data Distribution (blog post): the sections on perturbing data with an SDE, reversing the SDE and the probability-flow ODE.
- Holderrieth and Erives, An Introduction to Flow Matching and Diffusion Models (MIT 6.S184 notes): conditional and marginal scores, the SDE extension trick, and score matching = denoising score matching + a constant.
- Vincent, A Connection Between Score Matching and Denoising Autoencoders (2011): the original proof of Theorem 1. Hyvärinen, Estimation of Non-Normalized Statistical Models by Score Matching (JMLR 2005): explicit score matching by integration by parts.
- Karras, Aittala, Aila and Laine, Elucidating the Design Space of Diffusion-Based Generative Models (EDM, 2022): the convention, Heun sampling and the time grid.
- Applications: Price et al., Probabilistic weather forecasting with machine learning (GenCast, Nature 2025); Rozet and Louppe, Score-based Data Assimilation (2023); Chung et al., Diffusion Posterior Sampling for General Noisy Inverse Problems (2023); Palgunadi et al., High Resolution Seismic Waveform Generation using Denoising Diffusion (2024); Jung et al., Broadband Ground Motion Synthesis by Diffusion Model with Minimal Condition (ICML 2025).
Runs in your browser with nothing to install. The notebook repeats the key demos and has exercises with checks; solutions are inside, folded.
No Google account needed: Python runs inside your browser. The first start downloads about 40 MB; your changes are saved in this browser only.