

Diffusion models are the state of the art in terms of generative models and I wanted to contribute in my own way with a self-complete article that summarizes the diffusion model training and sampling.
We define first some common terminology, then we describe the training and sampling process. Finally we define the most common ODE samplers used for generating data and we focus on the Classifier-Free guidance.
In this article we assume intuitive understand of what a generative model and what a diffusion models does (inject noise, denoise). We adopt the Variational Diffusion Model (VDM) formulation. To describe the noising process we adopt the convention
t=0⇒x0clean sample,t=1⇒x1pure noise∼N(0,I).So t runs forward from data to noise during the diffusion process, and the model’s job will be to run it backward.
Training a diffusion model means teaching a network parametrized by θ to predict the noise that was added at an arbitrary point along this schedule. Concretely, each training step does three things.
1. Sample a timestep.
t∼U[0,1].2. Inject noise. Given the clean sample x0 , we form the noisy sample
xt=αtx0+σtε,ε∼N(0,I),where the signal and noise coefficients αt and σt come straight from the schedule:
αt=sigmoid(−γ(t)),σt=sigmoid(γ(t)).We can see how both terms are determined by γ(⋅) , which is the log Signal-to-Noise ratio. Down below we will describe how the noise schedule γ(⋅) can be defined.
3. Predict the noise. The network outputs εθ(xt,t,c) , an estimate of the ε we just added, optionally conditioned on a context vector c (see Classifier-Free Guidance).
Noise Schedule. The schedule γt itself can take several forms. Once the endpoints γ0 and γ1 are fixed, the common choices are:
Linear:Cosine:Learned:Multivariate Learned:γ0+(γ1−γ0)t,γ0+(γ1−γ0)21(1−cos(πt)),γ0+(γ1−γ0)MLPη(t),γ0+(γ1−γ0)MLPη(t,c),where MLP(t) is a positive monotonic network, i.e.
t1>t2⟹MLP(t1)>MLP(t2).We can go one step further with a multivariate learned contextual schedule: part of γ is fixed and learned globally, while another part is estimated from the context c , letting the noise schedule adapt to the input.
With predictions in hand, the loss combines three terms:
1. Standard diffusion loss:2. Reconstruction loss:3. Prior loss:ε−ε^θ(xt,t,c),ε−εθ(x0+s,Δ,c),s→0+,ε−εθ(x1,I,c).The first term is the usual denoising objective. The last two terms anchor the endpoints of the process and, in our experience, are particularly useful when the noise schedule itself is being learned.
Once the network is trained, how do we turn pure noise back into data? That is the sampling problem. But before we get there, it’s worth pausing on the first term above — where does it actually come from, and why is it valid to leave it unweighted?
The “standard diffusion loss” is not an arbitrary design choice. It is exactly what remains of the variational lower bound (ELBO) on logpθ(x0) once the number of diffusion steps is taken to infinity — but only under a specific parameterization and a specific way of sampling t . Getting either of those wrong silently turns the training objective into something that no longer bounds the likelihood. It’s worth deriving this once end-to-end.
For a T -step discretization with adjacent timesteps s=t−1/T , the diffusion term of the discrete-time ELBO takes the form
LT=2TEε,i∼U{1,…,T}[(SNR(s)−SNR(t))x0−x^θ(xt;t)2],where SNR(t)≡αt2/σt2=e−γ(t) . Intuitively, each step penalizes the x0 -reconstruction error, weighted by how much the signal-to-noise ratio drops over that step — steps where the signal degrades sharply matter more.
As T→∞ , the finite difference (SNR(s)−SNR(t))/(t−s) converges to −SNR′(t) , and the sum over steps becomes an integral over continuous time:
L∞=21Eε,t∼U(0,1)[−SNR′(t)x0−x^θ(xt;t)2].Since SNR(t) is monotonically decreasing in t , we have SNR′(t)<0 , so −SNR′(t)>0 is a genuine, non-negative weight — larger wherever the SNR is falling fastest.
Let u=γ(t) . Since SNR(t)=e−γ(t) , the chain rule gives SNR′(t)=−γ′(t)e−γ(t)=−γ′(t)SNR(t) , so
−21SNR′(t)dt=21γ′(t)SNR(t)dt=21SNR(u)du,which turns the integral over t into an integral over log-SNR:
L∞=21Eε∫γminγmaxSNR(u)x0−x^θ(xt(u);t(u))2du.The network in our formulation predicts noise, not the clean signal directly, so we relate the two through the same forward equation: x^θ=(xt−σtε^θ)/αt . Subtracting this from the identical expression for the true x0 and ε — noting that both are evaluated at the same realized xt , so that term cancels exactly —
x0−x^θ=αtσt(ε^θ−ε)⟹x0−x^θ2=SNR(t)1ε−ε^θ2.Substituting into the integral above, the SNR(u) factor introduced by the t→γ change of variables cancels exactly against the 1/SNR(t(u)) introduced by this reparameterization — the two are reciprocal by construction. What remains is
L∞==21Eε∫γminγmaxε−ε^θ(xt(u);t(u))2du2γmax−γminEε,u∼U(γmin,γmax)[ε−ε^θ2].This is the elegant result underlying the standard diffusion loss: written in terms of noise prediction and integrated uniformly over log-SNR, the correct ELBO term is literally an unweighted mean-squared error. The catch is that “integrated uniformly over log-SNR” is doing real work here — it is not automatically satisfied just because we sample t uniformly.
The boxed identity holds only when u=γ(t) is itself distributed uniformly on [γmin,γmax] . If t∼U(0,1) , the standard 1-D change-of-variables rule tells us the induced density of u is
pU(u)=∣γ′(t)∣1t=γ−1(u).For a schedule with constant slope — the linear schedule — this density is itself constant, so sampling t uniformly happens to give u uniformly, and no correction is required. For any schedule whose slope varies with t (cosine, or a learned/contextual schedule that may saturate near the endpoints), t∼U(0,1) over-samples whichever noise levels correspond to the flattest regions of γ — wherever γ′(t) is small, 1/γ′(t) is large, so those log-SNR values get visited disproportionately often. Averaging the unweighted MSE under this mismatched sampling distribution converges to a biased quantity, not to L∞ .
There are two equivalent fixes, differing only in where the correction is paid.
Option A — importance-weight by γ′(t) . Keep t∼U(0,1) , but reweight each sample by the density ratio between the target (uniform-in- u ) and the induced (mismatched) distribution:
L∞=21Et∼U(0,1)[γ′(t)ε−ε^θ(xt,t)2].This requires the derivative of the schedule with respect to t . When γ is vector-valued — for instance, a separate log-SNR curve per output dimension — this is naturally suited to forward-mode automatic differentiation (a Jacobian-vector product): since t is a single scalar input mapping to many outputs, one JVP call recovers the entire per-element derivative in a single extra forward-like pass, exactly, without the truncation/round-off tuning that finite differences would require.
Option B — sample directly in log-SNR space. Draw u∼U(γmin,γmax) first, then invert the schedule to recover the corresponding timestep,
t=γ−1(u).Because γ is monotonic by construction, this inversion is well-posed and can always be solved reliably by bisection on [0,1] , regardless of how nonlinear γ is. Since u is now drawn directly from the target distribution, there is no density mismatch left to correct — only the constant prefactor γmax−γmin from the interval length survives, and the loss is again plain, unweighted MSE. This is the approach adopted in the original VDM paper, and it trades a derivative for a root-find.
Both estimators are unbiased for L∞ ; they simply relocate the computational cost. Option A is preferable when γ is cheap to differentiate but awkward to invert (e.g. a small MLP with no closed form); Option B is preferable when γ has a closed-form or cheaply-invertible structure (e.g. the cosine schedule), since it avoids computing a derivative altogether.
We develop two types of sampling: ancestral sampling and ODE sampling. While the first relies partially on stochastic variables, the second is purely deterministic.
To sample with the VDM we walk the schedule backward, drawing from the conditional distribution p(xs∣xt) with s<t :
p(zs∣zt)=N(μθ(zt;s,t),σQ2(s,t)I),with
μθ(zt;s,t)σQ2(s,t)=αtαs(zt+σtexpm1(γη(s)−γη(t))εθ(zt;t)),=σs2(−expm1(γη(s)−γη(t))),where expm1(⋅):=exp(⋅)−1 . Equivalently, a single ancestral step can be written explicitly as
zs=σt2σs2deterministic part(zt−σt(−expm1(γη(s)−γη(t)))εθ(zt;t))+stochastic part(1−αs2)(−expm1(γη(s)−γη(t)))ε,with ε∼N(0,1) . The first bracket pulls the sample toward the denoised estimate; the second injects fresh noise.
The stochastic sampler is simple but tends to need many steps. If we are willing to drop the noise injection, we can instead describe the reverse process as a deterministic ODE, which opens the door to fast, high-order numerical solvers.
Every diffusion process has an associated forward SDE of the form
dx=f(x,t)dt+g(t)dw,and a corresponding probability-flow ODE that shares the same marginals but is fully deterministic:
dtdx=f(x,t)−21g(t)2∇xlogpt(x).In VDM we adapt the terms f(x,t) and g(t) as follows:
f(x,t)g(t)2=dtdlogαtx,=dtdσt2−2dtdlogαtσt2.In other words, the VDM drift f(x,t) is just a time-dependent scaling of the current state, and the diffusion coefficient g(t) measures how fast variance is being pumped in net of that scaling. The only learned object is the score ∇xlogpt(x) , which we read off directly from the noise prediction:
∇xlogpt(x)≈−σtεθ(x,t).Substituting these into the probability-flow ODE gives a closed-form vector field that depends only on the schedule and the network output, which is exactly the function f(tm,zm,θ) that the solvers below will integrate.
Continuous-time diffusion models formulate the generative process x1→x0 over a continuous time domain t∈[0,1] as the path of a Stochastic Differential Equation (SDE). By mapping this SDE to an equivalent deterministic Probability-Flow Ordinary Differential Equation (ODE), we cast the generative model as a Continuous Normalizing Flow (CNF). This permits exact likelihood estimation logpθ(x0) via the instantaneous change-of-variables theorem.
Let x0∼pdata(x0) be a sample from the underlying data manifold. The forward diffusion process corrupts x0 progressively over t∈[0,1] to yield noised latents xt∈Rd , governed by the Gaussian transition kernel:
q(xt∣x0)=N(xt;αtx0,σt2I).Equivalently, this forward dynamic maps exactly to the solution of the linear It^o SDE:
dxt=f(xt,t)dt+g(t)dwt,where wt is the standard forward Wiener process. In the VDM parameter space, the drift vector field f(xt,t) and the scalar diffusion coefficient g(t) expand analytically as:
f(xt,t)=(dtdlogαt)xt,g(t)=dtdσt2−2σt2dtdlogαt.Following Anderson’s theorem, the reverse-time generation—flowing from t=1 back to t=0 —is characterized by a corresponding reverse SDE:
dxt=[f(xt,t)−g(t)2∇xtlogpt(xt)]dt+g(t)dwˉt,where wˉt denotes a reverse-time Wiener process, and ∇xtlogpt(xt) is the Stein score of the marginal density pt(xt) . Crucially, Song et al. (2021) demonstrated that there exists a deterministic probability-flow ODE sharing the identical marginal probability densities {pt(xt)}t∈[0,1] as the SDE:
dxt=f(xt,t)[f(xt,t)−21g(t)2∇xtlogpt(xt)]dt.In practice, the exact score ∇xtlogpt(xt) is intractable. We approximate it using our neural network via the standard score-to-noise parameterization, creating our parameterized ODE drift field fθ(xt,t) .
Because this ODE describes a continuous normalizing flow mapping the known prior p1(x1)≈N(0,I) to the complex targeted distribution pθ(x0) , we can invoke the instantaneous change-of-variables formula from Neural ODEs (Chen et al., 2018) to compute the exact log-likelihood:
logpθ(x0)=logp1(x1)−∫01∇xt⋅fθ(xt,t)dt,where the divergence operator ∇xt⋅fθ(xt,t)≡tr(∇xtfθ(xt,t)) acts as the infinitesimal volume expansion term, and the parameterized field defines as:
fθ(xt,t):=f(xt,t)−21g(t)2ϵθ(xt,t).Consequently, evaluating the exact likelihood condenses down to integrating the divergence of the neural ODE drift field continuously tracked along the generated trajectory.
Directly computing tr(∇xtf~θ) requires a full Jacobian and scales as O(d2) . To avoid this, we use Hutchinson’s estimator. For any matrix A∈Rd×d ,
tr(A)=Ev[v⊤Av],if E[v]=0 and E[vv⊤]=I .
To see unbiasedness, expand
v⊤Av=i=1∑dj=1∑dviAijvj.Taking expectation,
E[v⊤Av]=i=1∑dj=1∑dAijE[vivj].Because E[vivj]=δij , we obtain
E[v⊤Av]=i=1∑dAii=tr(A).In diffusion likelihood estimation this is crucial: we never materialize the full Jacobian, and instead compute Jacobian-vector products, reducing practical cost from quadratic to roughly linear in dimension per probe. In practice, averaging a small number of probes (often around 5 - 10 ) is already effective.
The projection vector v∈Rd must satisfy
E[v]=0,E[vv⊤]=I.Two common choices are:
Both satisfy the required moment conditions and therefore produce unbiased trace estimates.
Terminology. Given a step size h , we want to advance from timestep tm to tm+1 starting from our sample zm , where f(⋅) denotes the ODE vector field derived above. The different solvers below trade off accuracy against the number of function evaluations (NFE).
While computationally inexpensive, this first-order method accumulates local errors on the order of O(h2) , at a cost of 1 NFE per step.
A second-order Runge–Kutta method that estimates the vector field at the midpoint of the integration step, giving a more accurate gradient estimate:
k1k2zm+1:=f(tm,zm,θ),:=f(tm+2h,zm+2hk1,θ),=zm+hk2.Error: O(h3) , at 2 NFE.
Pushing the same idea further, RK4 blends four slope evaluations:
k1k2k3k4zm+1=f(tm,zm,θ),=f(tm+2h,zm+2hk1,θ),=f(tm+2h,zm+2hk2,θ),=f(tm+h,zm+hk3,θ),=zm+6h(k1+2k2+2k3+k4).Error: O(h5) , at 4 NFE.
So far every method uses a fixed step size. The smarter move is to let the solver pick h on the fly based on how hard the trajectory is to integrate — this is what adaptive solvers do.
This method is adaptive: the NFE depends on the local approximation error. The trick is to compute two Runge–Kutta solutions of different order (5th and 4th) from the same stages and use their difference as an error estimate. The stages are
ki=f(tm+cih,zm+hj=1∑i−1aijkj,θ),i=1,…,7,with fractional time locations
c=[0, 51, 103, 54, 98, 1, 1],and internal coefficient matrix
A=051403454465611937231689017384350409−1556−218725360−333550093265616444852474673211135000−729212176491921250−186565103−6784218708411.The two approximations are
zm+1(5)zm+1(4)=zm+hi=1∑7biki,=zm+hi=1∑7b^iki,b=[38435, 0, 1113500, 192125, −67842187, 8411],b^=[576005179, 0, 166957571, 640393, −33920092097, 2100187].Their difference gives the local error estimate
em+1=zm+1(5)−zm+1(4)=h(i=1∑7ki(bi−b^i)).We then normalize the error,
scale=atol+rtol⋅max(∣ym∣,∣ym+1(5)∣),err=scaleem+1,where atol and rtol are hyperparameters. The step is accepted if err≤1 ; when it is rejected we keep zm and shrink the step:
hnew=h⋅safety⋅err−1/5.Adaptive Heun is a lighter-weight cousin of dopri5 that combines Euler and Heun. We compute
k1k2=f(tm,zm,θ),=f(tm+h,zm+hk1,θ),and form the Euler and Heun solutions:
zm+1(1)zm+1(2)=zm+hk1,=zm+2h(k1+k2).The estimation error and its normalization mirror dopri5:
em+1=zm+1(2)−zm+1(1)=2h(k2−k1),err=scaleem+1,with scale=atol+rtol⋅max(∣ym∣,∣ym+1(2)∣) . We accept if err≤1 ; otherwise we reduce the step as
hnew=h⋅safety⋅err−1/3,where the exponent follows the rule 1/(p+1) for an order- p solution (here p=2 , with the safety factor usually around 0.6 ).
Good solvers get us samples efficiently — but so far the generation is unconditional. The last ingredient is a way to steer the model toward a desired class or behavior.
Classifier-free guidance lets us guide the generation process of a diffusion model without training a separate classifier. We denote by c the conditioning class.
During training. Instead of always estimating the conditional score εθ(xt,t,c) , with probability pdrop (typically 10 – 20% ) we replace the condition with a null token ∅ and predict εθ(xt,t,∅) . This single network thus learns both the conditional and unconditional scores.
During sampling. We evaluate both scores and combine them:
ε~θ(xt,t,c)=εθ(xt,t,∅)+w(εθ(xt,t,c)−εθ(xt,t,∅)).For w≥0 this can be rewritten as a convex-style blend
ε~θ(xt,t,c)=(1−w)εθ(xt,t,∅)+wεθ(xt,t,c),where w is the guidance strength: it dictates how strongly the generation follows the class-conditioned signal. Larger w means tighter adherence to the condition at some cost to diversity.