Flow matching trains a generative model by teaching a neural network one thing: at any point in space and time, which way should a sample move to flow from noise toward data? Learn that velocity field and you can generate by solving an ordinary differential equation — start from a Gaussian sample and integrate. It is the ODE cousin of diffusion’s stochastic reverse process, and by choosing the path from noise to data carefully — ideally a straight line — it collapses the hundreds of denoising steps a diffusion sampler needs down to a handful. This piece builds it from first principles: the probability path and the ODE that carries it, why the obvious objective is intractable, the conditional flow matching trick that rescues it, the optimal-transport straight-line paths that power SD3 and FLUX, a worked numeric example, and exactly how it relates to the score-matching diffusion you may already know it.
From SDEs to ODEs
Diffusion models learn to reverse a noising process, and the classic sampler integrates a stochastic differential equation — each step adds a fresh dose of noise, which is why it takes many small steps to stay stable. Flow matching asks a simpler question. Forget noise injection during sampling; is there a purely deterministic vector field whose flow carries the simple prior distribution p_0 (Gaussian noise) exactly onto the data distribution p_1?
If such a field u_t(x) exists, generation becomes an ODE: draw x_0 ∼ N(0, I) and integrate dx/dt = u_t(x) from t=0 to t=1. No randomness after the initial draw, no score estimation, no reverse SDE. The entire modelling problem reduces to regressing a network v_θ(x, t) onto that velocity field. The catch — and the whole reason flow matching needed a clever idea — is that we never see u_t directly.
The ODE and continuous normalizing flows
A time-dependent velocity field defines a flow φ_t(x_0): the position at time t of a particle that started at x_0 and obeyed dφ_t/dt = u_t(φ_t). As t runs from 0 to 1, the flow pushes every point of the prior forward, transporting the whole density p_0 into some p_1. This is exactly a continuous normalizing flow (CNF).
Older CNF training maximized exact likelihood, which required the instantaneous change-of-variables formula d(log p_t)/dt = −∇·u_t and expensive divergence estimates through an ODE solver at every training step — elegant but slow. Flow matching’s contribution is to train the same ODE model with a plain regression loss and no solving during training. We match velocities directly rather than backpropagating through an integrator, which is what makes it scale to image-grade generators.
Probability paths and the continuity equation
Fix a probability path: a smooth family of densities p_t(x) interpolating the prior p_0 and the data p_1. A velocity field u_t is said to generate this path if pushing samples along its flow reproduces p_t at every time. The condition tying the two together is the continuity equation (mass conservation):
∂p_t/∂t + ∇ · ( p_t(x) u_t(x) ) = 0It says probability is neither created nor destroyed — it only flows, carried by the velocity field. Any u_t satisfying this for our chosen p_t is a valid training target. So the plan looks easy: pick a path, read off its velocity, and regress. The flow matching loss would be L_FM = E_{t, x∼p_t} || v_θ(x,t) − u_t(x) ||^2. The trouble is that both p_t(x) and u_t(x) for the marginal path are intractable — we cannot sample p_t or evaluate u_t in closed form.
Conditional flow matching: the trick
The key move is to build the marginal path as a mixture of simple conditional paths, one per data point. For each data sample x_1 ∼ q, define a conditional path p_t(x | x_1) that we design by hand and can sample from trivially, with a conditional velocity u_t(x | x_1) we can write down. The marginal is the average p_t(x) = ∫ p_t(x | x_1) q(x_1) dx_1.
The theorem behind flow matching is that the intractable marginal loss and the tractable conditional flow matching loss share the same gradient:
L_CFM = E_{ t∼U(0,1), x_1∼q, x∼p_t(·|x_1) } || v_θ(x,t) − u_t(x | x_1) ||^2Because ∇_θ L_CFM = ∇_θ L_FM, minimizing the easy loss trains the network to match the hard marginal field. The network ends up learning v_θ(x,t) ≈ E[ u_t(x|x_1) | x_t = x ] — the average conditional velocity of all data points whose path passes through x. That expectation is the ‘magic’: we only ever compute the per-sample target.
Gaussian conditional paths
The standard choice makes each conditional path a moving, shrinking Gaussian: p_t(x | x_1) = N(x; μ_t(x_1), σ_t^2 I). Sampling it is one line — draw ε ∼ N(0, I) and set x_t = μ_t(x_1) + σ_t ε. At t=0 we want the prior, so μ_0 = 0, σ_0 = 1; at t=1 we want the data point, so μ_1 = x_1 and σ_1 = σ_min (a tiny floor).
For any such Gaussian path the conditional velocity has a clean closed form obtained by differentiating the flow that produces x_t:
u_t(x | x_1) = μ_t'(x_1) + ( σ_t' / σ_t ) ( x − μ_t(x_1) )where ′ is the time derivative. Plug in a schedule for μ_t and σ_t and you have an exact regression target. Different schedules recover different generative models — including diffusion, as we will see.
Straight-line optimal-transport paths
The schedule that makes flow matching shine is the linear one: μ_t = t x_1 and σ_t = 1 − (1 − σ_min) t. Taking σ_min → 0 and pairing each data point with a noise draw x_0 ∼ N(0, I), the sample at time t is simply a linear interpolation:
x_t = (1 − t) x_0 + t x_1 target velocity: u_t = x_1 − x_0The conditional trajectory is a straight line from the noise sample to the data sample, traversed at constant velocity x_1 − x_0. This is the conditional optimal-transport path — the shortest constant-speed route between the two endpoints. Straightness is the prize: a straight path is exactly what an ODE solver integrates most accurately with the fewest steps, because the velocity does not swerve. The regression target could hardly be cheaper — subtract two vectors. This is the objective behind rectified flow and the SD3 and FLUX generators.
A worked numeric example
Take a 1-D toy. A noise sample x_0 = 2.0 is paired with a data sample x_1 = 5.0. The linear path is x_t = (1−t)·2 + t·5 = 2 + 3t, so at t = 0.5 the training point is x_0.5 = 3.5. The regression target there is the constant u = x_1 − x_0 = 3.0. During training the network sees the pair (x = 3.5, t = 0.5) and is nudged so v_θ(3.5, 0.5) → 3.0, averaged over every other path that happens to pass through 3.5.
Now sample. Start at x = 2.0 and take two Euler steps of Δt = 0.5 with the ideal velocity 3: 2.0 + 3·0.5 = 3.5, then 3.5 + 3·0.5 = 5.0. We land exactly on the data point in two steps — and because the true path is straight, even a single step of Δt = 1 would be exact. Curvature, not dimension, is what forces small steps.
Sampling: integrating the velocity field
Generation is deterministic ODE integration. Draw x_0 ∼ N(0, I) and march from t=0 to t=1, calling the network for the velocity at each step. The simplest scheme is forward Euler:
x ← x_0
for k in 0 .. N-1:
t = k / N
x = x + (1/N) · v_θ(x, t) # one network forward pass per step
return xThe number of steps N equals the number of network evaluations (NFEs) — the dominant cost. Higher-order solvers (Heun, midpoint, RK4) buy accuracy per step by spending extra evaluations, but the bigger lever is path curvature: straight paths tolerate few, large steps, so well-trained OT flow models produce good samples in 4–8 steps versus the 50–1000 a diffusion SDE sampler may need. Fewer NFEs is the practical headline of flow matching.
Relation to diffusion and score matching
Flow matching does not discard diffusion — it generalizes it. Every diffusion model has an equivalent deterministic probability-flow ODE that transports the same densities without noise, and that ODE is a flow matching model with a particular, curved Gaussian schedule (variance-preserving or variance-exploding). Its velocity is a fixed linear function of the score ∇ log p_t(x), so a score-matching model and its probability-flow velocity field are two views of one object.
The difference is design freedom. Diffusion fixes the noise schedule and therefore the path, which is bent; flow matching lets you choose the path, and the straight-line OT choice is far easier to integrate. So flow matching keeps diffusion’s stable, simple L2 regression training while trading the many-step curved sampler for a few-step straight one. Score matching answers ‘which way is density increasing?’; flow matching answers ‘which way should this sample move?’
Practical notes for CPU-scale generation
For small models on modest hardware, flow matching is attractive precisely because cost scales with NFEs. On a CPU, where each forward pass is expensive and there is no GPU parallelism to hide latency, cutting from hundreds of steps to a handful is the difference between seconds and minutes per sample. Deterministic ODE sampling is also reproducible — the same seed gives the same output — which simplifies caching, testing, and debugging.
Training is friendly too: the loss is a plain mean-squared error against a cheap target (a vector subtraction for OT paths), with no divergence estimate and no need to backpropagate through a solver, and memory stays flat because training never integrates the ODE. The main tunables are the time-sampling distribution for t (uniform is a fine default) and the solver and step count at inference, which you can raise or lower without retraining.
Common pitfalls
Direction convention. Papers disagree on whether t=0 is noise or data; a flipped sign sends samples toward noise. Pin down which endpoint is which before training. Marginal vs conditional. The network learns the averaged velocity E[u_t(x|x_1) | x_t = x], so even though every conditional path is straight, the learned marginal trajectory can be curved where paths cross — which is exactly why a ‘reflow’ step exists to straighten it further.
The variance floor. Keep σ_min small but nonzero so the conditional density stays well defined. Prediction parametrization. Regressing the velocity x_1 − x_0 is not the same as ε-prediction or x_1-prediction; they are related by linear reweighting but the effective loss weighting differs. Finally, do not over-reduce steps: too few NFEs on a still-curved field shows up as blur or drift.
v_θ(x,t) that flows Gaussian noise to data, then integrate it. The marginal field is intractable, so conditional flow matching regresses on per-sample conditional velocities that share the same gradient — and for the straight-line optimal-transport path the target is just x_1 − x_0. Because straight paths integrate accurately in very few steps, flow matching samples in a handful of network evaluations where a diffusion SDE needs hundreds, while keeping the same stable L2 training. It is a strict generalization of diffusion’s probability-flow ODE, with the freedom to choose an easier path. The wins that matter most on CPU-scale hardware are the low evaluation count and deterministic, reproducible sampling — just mind the noise/data direction, the averaged marginal field, and not starving the solver of steps.