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.

Advertisement

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) )  =  0

It 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) ||^2

Because ∇_θ 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_0

The 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.

Advertisement

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 x

The 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.

Flow matching turns generation into solving an ODE: learn a velocity field 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.