Type at least 2 letters. Enter opens the first result, Esc closes.

    Generative Models · Lesson 10 · Diffusion and flow matching

    Flow matching and rectified flow

    Advanced 100 min 4 interactive figures 4 videos Colab notebook

    Before this lesson: lesson 04 (continuous flows and the continuity equation), lesson 08 (conversions between targets, Tweedie's formula) and lesson 09 (the probability-flow ODE, Euler sampling, DDIM = Euler, NFE). Optimal transport appears only in the last part; the ML for science track treats it in depth. Time: about 100 minutes, plus the notebook.


    Why this matters #

    Continuous normalizing flows (lesson 04) are trained by maximum likelihood, which needs an ODE solve and a trace estimate for every training example: slow and noisy. Flow matching (Lipman et al. 2023; Liu et al. 2023; Albergo and Vanden-Eijnden 2023, as "stochastic interpolants") removes the ODE from training. The loss is a mean squared error, as simple as the diffusion loss of lesson 07.

    Rectified-flow transformers generate images in Stable Diffusion 3 (Esser et al. 2024) and Flux; Meta's Movie Gen is trained with flow matching. In science, flow matching emulates weather fields, molecules and seismic waveforms, and Riemannian flow matching works on spheres and other manifolds. Because sampling cost is (steps) × (network cost), the straightness of the paths decides the cost of every sample. Reflow, minibatch optimal transport and distillation (lesson 12) all aim at straighter paths.

    1. Predict first #

    2. The picture #

    One pair: a straight line #

    Fix one data point x0x_0 and one noise point ε\varepsilon. The straight line

    xt=(1−t) x0+t ε,t∈[0,1],x_t = (1 - t)\,x_0 + t\,\varepsilon, \qquad t \in [0, 1],

    starts at the data (t=0t = 0) and ends at the noise (t=1t = 1). Its velocity is constant: dxtdt=ε−x0\frac{d x_t}{dt} = \varepsilon - x_0. If you knew the pair, one Euler step of size 1 from ε\varepsilon would land exactly on x0x_0. This line is called the conditional path (it is conditioned on the pair), and ε−x0\varepsilon - x_0 is the conditional velocity.

    Many pairs: the lines cross #

    Now draw many pairs: data points from pdatap_{\text{data}}, noise points from N(0,I)\mathcal N(0, I), independently. Their lines cross. At one place and one time, different lines move in different directions. But a network sees only the place xtx_t and the time tt; it does not know which pair a point came from. So it cannot follow every line.

    Interactive figure: loading…

    Move the time slider in the conditional paths view. Each yellow point moves on a straight magenta line from its noise point (green) to its data point (blue); the violet arrows show its velocity in the sampling direction (toward t=0t = 0). Near the center, close points move in very different directions. Now switch to marginal flow: one smooth velocity field moves every point, the paths bend, and the orange end points land on the modes. Compare the transport costs: about 5.6 for the random pairs, about 1.05 for the start and end points of the marginal flow. Then try minibatch OT for the pairs. The velocity of the marginal flow is computed exactly from the known mixture, not learned.

    The best guess is an average #

    What is the best single velocity at the point xx and time tt? Under the squared error, the best prediction is the conditional mean (lesson 08): the average of the velocities of all lines that pass through xx at time tt, each weighted by how likely its pair is to be there. This average is the marginal velocity

    v(x,t)=E[ε−x0∣xt=x].v(x, t) = \mathbb E[\varepsilon - x_0 \mid x_t = x].

    The next figure makes this concrete in one dimension. With the two data points ±1\pm 1, exactly two lines pass through each point (t,x)(t, x): one that ends at +1+1 and one that ends at −1-1.

    Interactive figure: loading…

    Drag the yellow point in the (t,x)(t, x) plane. The two dashed lines are the conditional paths through it; the darker one has the larger posterior weight. The grey arrows are their velocities, the violet arrow is the weighted average, the marginal velocity. Between the modes (try between the modes) the two lines have equal weight and their velocities cancel. Near a mode at little noise, one line has all the weight and the marginal velocity equals its velocity. The magenta curves are paths of the marginal ODE: they never cross, and they bend where the weights change.

    Quick check

    A training pair is x0=(1,0)x_0 = (1, 0), ε=(0.5,−1)\varepsilon = (0.5, -1), and the time is t=0.4t = 0.4. What are the network input xtx_t and the CFM regression target?

    3. Definitions and main results #

    Flows, paths and the continuity equation #

    A velocity field v(x,t)v(x, t) defines a flow: dx/dt=v(x,t)dx/dt = v(x, t). If x(1)x(1) has density p1p_1 and you solve the ODE, the density ptp_t of x(t)x(t) solves the continuity equation

    ∂tpt+∇⋅(pt v)=0\partial_t p_t + \nabla\cdot(p_t\,v) = 0

    (lesson 04). We say that vv generates the path ptp_t. A probability path is a family of densities ptp_t from the data (p0=pdatap_0 = p_{\text{data}}) to the noise (p1=N(0,I)p_1 = \mathcal N(0, I)).

    Fix the linear path: draw x0∼pdatax_0 \sim p_{\text{data}} and ε∼N(0,I)\varepsilon \sim \mathcal N(0, I) independently and set xt=(1−t) x0+t εx_t = (1 - t)\,x_0 + t\,\varepsilon. Its density ptp_t is the marginal path. If we knew a velocity u(x,t)u(x, t) that generates it, we could train a network vθv_\theta with the flow matching (FM) loss

    LFM(θ)=Et∼U[0,1], x∼pt ∥vθ(x,t)−u(x,t)∥2.L_{\text{FM}}(\theta) = \mathbb E_{t \sim \mathcal U[0, 1],\ x \sim p_t}\,\big\|v_\theta(x, t) - u(x, t)\big\|^2 .

    But we do not know uu. The next two theorems find it and remove it from the loss.

    Theorem 1 (the marginalization trick) #

    The marginal velocity v(x,t)=E[ε−x0∣xt=x]v(x, t) = \mathbb E[\varepsilon - x_0 \mid x_t = x] generates the marginal path ptp_t.

    Intuition. The density at xx changes because points flow in and out. Every pair moves with its own velocity, but for the flux of mass through xx only the average velocity of the mass at xx matters.

    Proof (weak form; φ\varphi is any smooth test function with compact support).

    1. Each pair moves on its line, so by the chain rule ddtφ(xt)=∇φ(xt)⋅(ε−x0)\frac{d}{dt}\varphi(x_t) = \nabla\varphi(x_t)\cdot(\varepsilon - x_0). Take expectations: ddtE[φ(xt)]=E[∇φ(xt)⋅(ε−x0)]\frac{d}{dt}\mathbb E[\varphi(x_t)] = \mathbb E\big[\nabla\varphi(x_t)\cdot(\varepsilon - x_0)\big].
    2. Condition on xtx_t (the tower property): ∇φ(xt)\nabla\varphi(x_t) is fixed given xtx_t, so the right side is
    E[∇φ(xt)⋅E[ε−x0∣xt]]=E[∇φ(xt)⋅v(xt,t)].\mathbb E\big[\nabla\varphi(x_t)\cdot\mathbb E[\varepsilon - x_0 \mid x_t]\big] = \mathbb E\big[\nabla\varphi(x_t)\cdot v(x_t, t)\big].
    1. In integrals: ddt∫φ pt dx=∫∇φ⋅v pt dx=−∫φ ∇⋅(ptv) dx\frac{d}{dt}\int\varphi\,p_t\,dx = \int\nabla\varphi\cdot v\,p_t\,dx = -\int\varphi\,\nabla\cdot(p_t v)\,dx (integration by parts; φ\varphi vanishes far away).
    2. This holds for every φ\varphi, so ∂tpt=−∇⋅(ptv)\partial_t p_t = -\nabla\cdot(p_t v): the continuity equation. ■\blacksquare

    When vv is regular enough (for example, Lipschitz in xx), the ODE dx/dt=v(x,t)dx/dt = v(x, t) started from x(1)∼N(0,I)x(1) \sim \mathcal N(0, I) therefore has the marginals ptp_t and ends at p0=pdatap_0 = p_{\text{data}}.

    Theorem 2 (conditional flow matching, CFM) #

    Define the conditional flow matching loss

    LCFM(θ)=Et, x0, ε ∥vθ(xt,t)−(ε−x0)∥2,xt=(1−t) x0+t ε.L_{\text{CFM}}(\theta) = \mathbb E_{t,\ x_0,\ \varepsilon}\,\big\|v_\theta(x_t, t) - (\varepsilon - x_0)\big\|^2, \qquad x_t = (1 - t)\,x_0 + t\,\varepsilon .

    Then LCFM(θ)=LFM(θ)+VL_{\text{CFM}}(\theta) = L_{\text{FM}}(\theta) + V, where u=vu = v is the marginal velocity and V≥0V \ge 0 does not depend on θ\theta. So the two losses have the same gradient and the same minimizer vθ=vv_\theta = v.

    Proof. Fix tt and write c=ε−x0c = \varepsilon - x_0.

    1. Expand: ∥vθ−c∥2=∥vθ∥2−2⟨vθ,c⟩+∥c∥2\|v_\theta - c\|^2 = \|v_\theta\|^2 - 2\langle v_\theta, c\rangle + \|c\|^2.
    2. The first term is the same in both losses, because xt∼ptx_t \sim p_t in both.
    3. The cross term, by the tower property:
    E⟨vθ(xt,t),c⟩=E⟨vθ(xt,t),E[c∣xt]⟩=E⟨vθ(xt,t),v(xt,t)⟩.\mathbb E\langle v_\theta(x_t, t), c\rangle = \mathbb E\langle v_\theta(x_t, t), \mathbb E[c \mid x_t]\rangle = \mathbb E\langle v_\theta(x_t, t), v(x_t, t)\rangle .

    This is the cross term of LFML_{\text{FM}}. 4. So LCFM−LFM=E∥c∥2−E∥v(xt,t)∥2L_{\text{CFM}} - L_{\text{FM}} = \mathbb E\|c\|^2 - \mathbb E\|v(x_t, t)\|^2, which does not contain θ\theta. Written as one term:

    V=∫01E ∥(ε−x0)−v(xt,t)∥2 dt  ≥0.■V = \int_0^1 \mathbb E\,\big\|(\varepsilon - x_0) - v(x_t, t)\big\|^2\,dt \;\ge 0 .\qquad\blacksquare

    This is the same argument as denoising score matching (lesson 06): a conditional target whose conditional mean is the marginal target. The floor VV is the variance of the direction given the position. It is zero only when no two lines cross. So the CFM loss never reaches zero for a model with crossing lines, even a perfect one; do not read its value as an error.

    Quick check

    Your flow-matching network has reached the minimum of the CFM loss, but the loss value is about 1.0, not 0. What does this tell you?

    Sampling #

    Training gives vθ≈vv_\theta \approx v. To sample, draw x∼N(0,I)x \sim \mathcal N(0, I) at t=1t = 1 and integrate dx/dt=vθ(x,t)dx/dt = v_\theta(x, t) backward to t=0t = 0. With Euler on a grid 1=t0>t1>⋯>tn=01 = t_0 > t_1 > \dots > t_n = 0:

    x←x+(tk+1−tk) vθ(x,tk)(tk+1−tk<0).x \leftarrow x + (t_{k+1} - t_k)\,v_\theta(x, t_k) \qquad (t_{k+1} - t_k < 0).

    Each step costs one NFE, as in lesson 09. Heun and other solvers work the same way.

    Interactive figure: loading…

    Choose the number of Euler steps. With 1 step every sample (orange) lands exactly at the center, the mean of the data. With 2 steps the samples form a ring of radius about 1.4, inside the data. With 4 steps about 83% are on a mode, and with 8 steps about 97%. The magenta lines are Euler paths. The velocity is exact (computed from the known mixture), so every error you see comes from the step size.

    Why one step lands on the mean. At t=1t = 1 the point x1=εx_1 = \varepsilon says nothing about x0x_0, so E[x0∣x1]=E[x0]\mathbb E[x_0 \mid x_1] = \mathbb E[x_0], and v(x,1)=x−E[x0]v(x, 1) = x - \mathbb E[x_0] (from the formula v=(x−D)/tv = (x - D)/t below). One step of size 1 gives x−v(x,1)=E[x0]x - v(x, 1) = \mathbb E[x_0]: the same point for every noise. The first velocity is an average direction toward the data mean, and the paths turn only later. This is the price of crossing lines.

    Flow matching and diffusion #

    Take a general Gaussian path xt=at x0+σt εx_t = a_t\,x_0 + \sigma_t\,\varepsilon (lessons 08–09); the linear path has at=1−ta_t = 1 - t and σt=t\sigma_t = t. Write D(x,t)=E[x0∣xt=x]D(x, t) = \mathbb E[x_0 \mid x_t = x] (the denoiser) and ε^(x,t)=E[ε∣xt=x]=(x−atD)/σt\hat\varepsilon(x, t) = \mathbb E[\varepsilon \mid x_t = x] = (x - a_t D)/\sigma_t.

    Proposition 3 (the velocity is a denoiser). The marginal velocity of the path is

    v(x,t)=a˙t D(x,t)+σ˙t ε^(x,t),and for the linear pathv(x,t)=x−D(x,t)t=−x+t ∇log⁡pt(x)1−t.v(x, t) = \dot a_t\,D(x, t) + \dot\sigma_t\,\hat\varepsilon(x, t), \qquad\text{and for the linear path}\qquad v(x, t) = \frac{x - D(x, t)}{t} = -\frac{x + t\,\nabla\log p_t(x)}{1 - t}.

    Proof.

    1. The conditional velocity is ddtxt=a˙tx0+σ˙tε\frac{d}{dt}x_t = \dot a_t x_0 + \dot\sigma_t\varepsilon. Its conditional mean given xt=xx_t = x is a˙tD+σ˙tε^\dot a_t D + \dot\sigma_t\hat\varepsilon, because the expectation is linear.
    2. Linear path: a˙t=−1\dot a_t = -1, σ˙t=1\dot\sigma_t = 1, so v=−D+(x−(1−t)D)/t=(x−D)/tv = -D + (x - (1 - t)D)/t = (x - D)/t.
    3. Tweedie's formula (lesson 08) for x=(1−t)x0+tεx = (1 - t)x_0 + t\varepsilon is D=(x+t2∇log⁡pt(x))/(1−t)D = (x + t^2\nabla\log p_t(x))/(1 - t). Put it into step 2: v=((1−t)x−x−t2∇log⁡pt)/(t(1−t))=−(x+t∇log⁡pt)/(1−t)v = \big((1 - t)x - x - t^2\nabla\log p_t\big)/\big(t(1 - t)\big) = -(x + t\nabla\log p_t)/(1 - t). ■\blacksquare

    So a velocity network, a denoiser and a score network carry the same information: they are linear maps of each other at every tt. In lesson 08's language, the velocity is one more prediction target, with x^0=xt−t v^\hat x_0 = x_t - t\,\hat v and ε^=xt+(1−t) v^\hat\varepsilon = x_t + (1 - t)\,\hat v.

    The PF-ODE is a flow-matching ODE. For the VP path, the probability-flow ODE of lesson 09 has the drift f−12g2∇log⁡ptf - \tfrac12 g^2\nabla\log p_t with f=(a˙t/at) xf = (\dot a_t/a_t)\,x and g2=dσt2dt−2a˙tatσt2g^2 = \frac{d\sigma_t^2}{dt} - 2\frac{\dot a_t}{a_t}\sigma_t^2. With ∇log⁡pt=−ε^/σt\nabla\log p_t = -\hat\varepsilon/\sigma_t this drift is a˙tatx+(σ˙t−a˙tatσt)ε^=a˙tat(x−σtε^)+σ˙tε^=a˙tD+σ˙tε^\frac{\dot a_t}{a_t}x + \big(\dot\sigma_t - \frac{\dot a_t}{a_t}\sigma_t\big)\hat\varepsilon = \frac{\dot a_t}{a_t}(x - \sigma_t\hat\varepsilon) + \dot\sigma_t\hat\varepsilon = \dot a_t D + \dot\sigma_t\hat\varepsilon, the marginal velocity of Proposition 3. So diffusion's PF-ODE is the flow-matching ODE of its own Gaussian path. Diffusion and flow matching differ in the path (at,σta_t, \sigma_t), in the loss weight over noise levels (lesson 08) and in the sampler grid, not in the kind of object they learn.

    Proposition 4 (an Euler step of flow matching is a DDIM step). For the linear path, one Euler step from tt to t′<tt' < t with the exact velocity gives the same point as the η=0\eta = 0 DDIM step with the same denoiser output.

    Proof. Euler: x+(t′−t)(x−D)/t=t′tx+t−t′tDx + (t' - t)(x - D)/t = \frac{t'}{t}x + \frac{t - t'}{t}D. DDIM (lesson 09) with a=1−ta = 1 - t, σ=t\sigma = t:

    at′D+σt′ε^=(1−t′)D+t′ x−(1−t)Dt=t′tx+(1−t′−t′(1−t)t)D=t′tx+t−t′tD.■a_{t'}D + \sigma_{t'}\hat\varepsilon = (1 - t')D + t'\,\frac{x - (1 - t)D}{t} = \frac{t'}{t}x + \Big(1 - t' - \frac{t'(1 - t)}{t}\Big)D = \frac{t'}{t}x + \frac{t - t'}{t}D. \qquad\blacksquare

    This is Theorem 3 of lesson 09 again: on the linear path, x/atx/a_t and σt/at=t/(1−t)\sigma_t/a_t = t/(1 - t) are already straight-line coordinates. Flow matching with Euler steps and DDIM are one sampler on different time grids.

    Quick check

    A model from a paper with the convention "s=0s = 0 noise, s=1s = 1 data" outputs vpaper(x,s)=(2,−1)v_{\text{paper}}(x, s) = (2, -1) at s=0.7s = 0.7. What is the velocity in this track's convention, and at which tt?

    Straight conditional paths, curved marginal paths #

    Every conditional path is a straight line. The marginal paths are not, because the average direction at a point changes with time: early (near t=1t = 1) all lines through a point point toward the data mean on average; late (near t=0t = 0) only the lines from one nearby data point carry weight. The marginal paths also cannot cross: an ODE with a Lipschitz velocity has exactly one solution through each point (x,t)(x, t), so two paths that meet at one time were the same path all along. Crossing lines are replaced by paths that bend away from each other.

    Curvature costs steps. Euler is exact on a straight path with constant speed (lesson 09: a step is exact when the slope does not change along it), and it errs where the path turns. So we want a coupling of noise and data whose lines do not cross. Two ways to get one: rectified flow and optimal transport.

    Rectified flow and reflow #

    Let (X0,X1)(X_0, X_1) be any coupling of the data and the noise (at first, the independent one), let vv be its marginal velocity, and let ZZ solve dZt/dt=v(Zt,t)dZ_t/dt = v(Z_t, t) backward from Z1=X1Z_1 = X_1. Liu, Gong and Liu (2023) call (Z0,Z1)(Z_0, Z_1) the rectified coupling. By Theorem 1, Z0Z_0 has the data distribution, so (Z0,Z1)(Z_0, Z_1) is again a coupling of the same two distributions, now a deterministic one: Z0Z_0 is a function of Z1Z_1.

    Theorem 5 (rectified flow does not increase convex transport costs). If the ODE has unique solutions, then for every convex function cc,

    E c(Z1−Z0)≤E c(X1−X0).\mathbb E\,c(Z_1 - Z_0) \le \mathbb E\,c(X_1 - X_0) .
    Proof (two uses of Jensen's inequality)
    1. Z1−Z0=∫01v(Zt,t) dtZ_1 - Z_0 = \int_0^1 v(Z_t, t)\,dt, an average over time. Jensen in tt: c(Z1−Z0)≤∫01c(v(Zt,t)) dtc(Z_1 - Z_0) \le \int_0^1 c\big(v(Z_t, t)\big)\,dt.
    2. ZtZ_t and XtX_t have the same law (Theorem 1), so E c(v(Zt,t))=E c(v(Xt,t))\mathbb E\,c(v(Z_t, t)) = \mathbb E\,c(v(X_t, t)).
    3. v(Xt,t)=E[X1−X0∣Xt]v(X_t, t) = \mathbb E[X_1 - X_0 \mid X_t], so conditional Jensen gives c(v(Xt,t))≤E[c(X1−X0)∣Xt]c(v(X_t, t)) \le \mathbb E[c(X_1 - X_0) \mid X_t].
    4. Take expectations in step 3, integrate over tt, and chain with steps 1–2: E c(Z1−Z0)≤∫01E c(X1−X0) dt=E c(X1−X0)\mathbb E\,c(Z_1 - Z_0) \le \int_0^1 \mathbb E\,c(X_1 - X_0)\,dt = \mathbb E\,c(X_1 - X_0). ■\blacksquare

    For c=∥⋅∥2c = \|\cdot\|^2 both inequalities become identities with explicit gaps (the variance decompositions of a time average and of a conditional mean):

    E∥X1−X0∥2−E∥Z1−Z0∥2=S+V,S=∫01E∥(Z1−Z0)−v(Zt,t)∥2dt,\mathbb E\|X_1 - X_0\|^2 - \mathbb E\|Z_1 - Z_0\|^2 = S + V, \qquad S = \int_0^1 \mathbb E\big\|(Z_1 - Z_0) - v(Z_t, t)\big\|^2 dt ,

    where VV is the CFM floor of Theorem 2 and SS, the straightness, measures how much the flow's velocity changes along its paths (S=0S = 0 means straight paths at constant speed, so one Euler step is exact).

    Reflow. Train a new flow-matching model on the rectified pairs (Z0,Z1)(Z_0, Z_1) instead of independent pairs. Its lines come from a deterministic, non-crossing map, so they cross much less: VV is small and the new paths are straighter. Repeating gives the kk-rectified flow. By the identity in the proof, the squared transport cost falls by S+VS + V in each round and can never fall below 0; Liu et al. derive from this that min⁡k≤KS(Zk)≤E∥X1−X0∥2/K\min_{k \le K} S(Z^k) \le \mathbb E\|X_1 - X_0\|^2/K.

    Interactive figure: loading…

    Compare the two flows and move the number of Euler steps. Before reflow, the exact magenta paths from the noise points (green) first head toward 0 and turn late; the orange Euler polylines with 1 step all end at 0 (error 1.0), with 2 steps at tanh⁡ε\tanh\varepsilon (error 0.44). Switch to after one reflow: the paths are straight lines, and Euler is exact with any number of steps. In 1D a flow keeps the order of points, so the rectified pairing sends negative noise to −1-1 and positive noise to +1+1: it is the optimal transport pairing, with cost 0.4040.404 instead of 22.

    What reflow costs. Each round must simulate the current flow to produce many pairs (pairs × steps × network cost), and it fits a model to model outputs, so errors accumulate. In practice one or two rounds are used, often followed by distillation into a one-step model (lesson 12). On CIFAR-10, Liu et al. report FID 378 for one Euler step of the 1-rectified flow, and 4.85 for the 2-rectified flow plus distillation. InstaFlow (Liu et al. 2024) applies reflow and distillation to Stable Diffusion for one-step text-to-image generation.

    Quick check

    What does one round of reflow change?

    Minibatch optimal transport and further directions

    Optimal transport pairs do not cross. Among all couplings of pdatap_{\text{data}} and N(0,I)\mathcal N(0, I), the one with the smallest E∥ε−x0∥2\mathbb E\|\varepsilon - x_0\|^2 is the optimal transport (OT) coupling; its cost is W22W_2^2. If two of its pairs met at a time t∈(0,1)t \in (0, 1), swapping their partners would lower the cost, which is impossible. (Write a=x0−x0′a = x_0 - x_0', b=ε−ε′b = \varepsilon - \varepsilon'; optimality gives ⟨a,b⟩≥0\langle a, b\rangle \ge 0, and meeting means (1−t)a+tb=0(1 - t)a + tb = 0, which forces a=b=0a = b = 0.) So under the OT coupling the lines do not cross, V=0V = 0, the marginal velocity is the line velocity, and one Euler step is exact. By the Benamou–Brenier theorem this flow also has the smallest kinetic energy ∫01E∥v∥2dt\int_0^1 \mathbb E\|v\|^2 dt of all flows between the two distributions.

    Minibatch OT (Tong et al. 2024; Pooladian et al. 2023). In each training batch, draw BB data and BB noise points and re-pair them by an exact assignment (scipy.optimize.linear_sum_assignment). The coupling lies between independent and OT. For the 8 Gaussians the mean squared distance of the pairs is about 6.0 for independent pairs, 1.7 for B=16B = 16, 1.2 for B=64B = 64 and 1.0 for B=256B = 256. Limits: an exact assignment costs about O(B3)O(B^3), and in high dimensions a batch is a coarse sample of the distributions, so the straightening is only partial. Conditional generation and large image models often see little gain.

    Beyond Euclidean data. Riemannian flow matching replaces straight lines by geodesics on a manifold (the sphere for global weather, rotation groups for molecules); discrete flow matching works on tokens. The ML for science track covers optimal transport, Sinkhorn and flow matching on the sphere.

    Answers to section 1. (1) All samples land at 00, the data mean: one Euler step gives x−v(x,1)=E[x0]x - v(x, 1) = \mathbb E[x_0] for every noise point. (2) No. The marginal ODE has exactly one path through each point (x,t)(x, t); crossing training lines are replaced by curved paths that bend away from each other. (3) No. It outputs the conditional mean E[ε−x0∣xt]\mathbb E[\varepsilon - x_0 \mid x_t], the average over all pairs that could have produced xtx_t. The loss that remains at the optimum is the floor VV of Theorem 2.

    4. Worked example #

    Data x0∈{−1,+1}x_0 \in \{-1, +1\} with probability 12\tfrac12 each, noise ε∼N(0,1)\varepsilon \sim \mathcal N(0, 1), linear path.

    (a) The marginal velocity at t=0.5t = 0.5, x=0.3x = 0.3.

    1. Given x0=±1x_0 = \pm 1, xt∼N(±(1−t),t2)=N(±0.5,0.25)x_t \sim \mathcal N(\pm(1 - t), t^2) = \mathcal N(\pm 0.5, 0.25).
    2. Posterior weights by Bayes' rule (equal priors): log⁡w+w−=(x+0.5)2−(x−0.5)22⋅0.25=2x0.5=4x=1.2\log\frac{w_+}{w_-} = \frac{(x + 0.5)^2 - (x - 0.5)^2}{2 \cdot 0.25} = \frac{2x}{0.5} = 4x = 1.2 (in general 2x(1−t)/t22x(1 - t)/t^2). So w+=1/(1+e−1.2)=0.7685w_+ = 1/(1 + e^{-1.2}) = 0.7685 and w−=0.2315w_- = 0.2315.
    3. Conditional velocities: the line to +1+1 has ε=(0.3−0.5)/0.5=−0.4\varepsilon = (0.3 - 0.5)/0.5 = -0.4, so u+=ε−x0=−1.4u_+ = \varepsilon - x_0 = -1.4; the line to −1-1 has ε=(0.3+0.5)/0.5=1.6\varepsilon = (0.3 + 0.5)/0.5 = 1.6, so u−=1.6+1=2.6u_- = 1.6 + 1 = 2.6. (Check: u±=(x∓1)/tu_\pm = (x \mp 1)/t.)
    4. Marginal velocity: v=0.7685⋅(−1.4)+0.2315⋅2.6=−1.0759+0.6018=−0.4741v = 0.7685 \cdot (-1.4) + 0.2315 \cdot 2.6 = -1.0759 + 0.6018 = -0.4741.
    5. Check with the denoiser: D=w+−w−=0.5370=tanh⁡(1.2/2)=tanh⁡(0.6)D = w_+ - w_- = 0.5370 = \tanh(1.2/2) = \tanh(0.6) ✓, and (x−D)/t=(0.3−0.5370)/0.5=−0.4741(x - D)/t = (0.3 - 0.5370)/0.5 = -0.4741 ✓.

    The velocity is negative: moving toward t=0t = 0 (sampling), xx grows toward the more likely data point +1+1.

    (b) Euler with one and two steps. At t=1t = 1, D=tanh⁡(0)=0D = \tanh(0) = 0, so v(x,1)=xv(x, 1) = x.

    • One step: x0=ε−1⋅v(ε,1)=0x_0 = \varepsilon - 1 \cdot v(\varepsilon, 1) = 0 for every ε\varepsilon.
    • Two steps: first x0.5=ε−0.5 ε=0.5 εx_{0.5} = \varepsilon - 0.5\,\varepsilon = 0.5\,\varepsilon. At t=0.5t = 0.5, D=tanh⁡(0.5ε⋅0.5/0.25)=tanh⁡εD = \tanh(0.5\varepsilon \cdot 0.5/0.25) = \tanh\varepsilon and v=(0.5ε−tanh⁡ε)/0.5=ε−2tanh⁡εv = (0.5\varepsilon - \tanh\varepsilon)/0.5 = \varepsilon - 2\tanh\varepsilon. Then x0=0.5ε−0.5(ε−2tanh⁡ε)=tanh⁡εx_0 = 0.5\varepsilon - 0.5(\varepsilon - 2\tanh\varepsilon) = \tanh\varepsilon.
    • For ε=1\varepsilon = 1: tanh⁡1=0.7616\tanh 1 = 0.7616, an error of 0.240.24 against the exact end point +1+1. The mean error over ε∼N(0,1)\varepsilon \sim \mathcal N(0, 1) is E[1−tanh⁡∣ε∣]=0.444\mathbb E[1 - \tanh|\varepsilon|] = 0.444.

    (c) Reflow in 1D. The exact flow keeps the order of points, so it sends ε<0\varepsilon < 0 to −1-1 and ε>0\varepsilon > 0 to +1+1: Z0=sign⁡(Z1)Z_0 = \operatorname{sign}(Z_1).

    • Independent pairs: E(ε−x0)2=Eε2+Ex02=1+1=2\mathbb E(\varepsilon - x_0)^2 = \mathbb E\varepsilon^2 + \mathbb E x_0^2 = 1 + 1 = 2 (the cross term vanishes by independence).
    • Rectified pairs: E(ε−sign⁡ε)2=Eε2−2 E∣ε∣+1=2−22/π=0.404\mathbb E(\varepsilon - \operatorname{sign}\varepsilon)^2 = \mathbb E\varepsilon^2 - 2\,\mathbb E|\varepsilon| + 1 = 2 - 2\sqrt{2/\pi} = 0.404, using E∣ε∣=2/π=0.798\mathbb E|\varepsilon| = \sqrt{2/\pi} = 0.798.
    • The drop 2−0.404=1.5962 - 0.404 = 1.596 equals S+VS + V of the first rectification. After reflow the lines from ε\varepsilon to sign⁡ε\operatorname{sign}\varepsilon never cross, so the new velocity is v2(x,t)=(x−sign⁡x)/tv_2(x, t) = (x - \operatorname{sign} x)/t, constant along each line, and one Euler step is exact.

    (d) Converting a velocity. A model in the reversed convention outputs vpaper=0.8v_{\text{paper}} = 0.8 at s=0.25s = 0.25 for some xx. In this track's time t=1−0.25=0.75t = 1 - 0.25 = 0.75 and v=−0.8v = -0.8. The implied clean sample at x=0.5x = 0.5 is x^0=x−t v=0.5+0.75⋅0.8=1.1\hat x_0 = x - t\,v = 0.5 + 0.75 \cdot 0.8 = 1.1, and the implied noise is ε^=x+(1−t)v=0.5−0.2=0.3\hat\varepsilon = x + (1 - t)v = 0.5 - 0.2 = 0.3. Check: (1−t)x^0+tε^=0.275+0.225=0.5=x(1 - t)\hat x_0 + t\hat\varepsilon = 0.275 + 0.225 = 0.5 = x ✓.

    5. In code #

    NumPy checks the worked example, Theorem 2, the Euler formulas, Proposition 4 and the minibatch OT costs. The notebook has these cells, a small trained model and the exercises.

    import numpy as np
    from scipy.optimize import linear_sum_assignment
    
    # Two-point data x0 in {-1, +1}, noise eps ~ N(0, 1), path x_t = (1 - t) x0 + t eps
    def v_marg(x, t):                                   # exact marginal velocity (x - D) / t
        return (x - np.tanh(x * (1 - t) / t**2)) / t
    
    # (a) the worked example at t = 0.5, x = 0.3
    t, x = 0.5, 0.3
    w_plus = 1 / (1 + np.exp(-2 * x * (1 - t) / t**2))
    u_plus, u_minus = (x - 1) / t, (x + 1) / t
    print(round(w_plus, 4), round(w_plus * u_plus + (1 - w_plus) * u_minus, 4), round(v_marg(x, t), 4))
    # 0.7685 -0.4741 -0.4741
    
    # (b) CFM = FM + constant: shift the exact v by 0.1; the CFM loss rises by exactly 0.1^2 = 0.01
    rng = np.random.default_rng(0)
    n = 2_000_000
    x0 = rng.choice([-1.0, 1.0], n)
    eps = rng.standard_normal(n)
    tt = rng.uniform(0.05, 1.0, n)                      # avoid t near 0, where v is steep
    xt = (1 - tt) * x0 + tt * eps
    target = eps - x0
    cfm = lambda v: np.mean((v - target) ** 2)
    print(round(cfm(v_marg(xt, tt)), 4), round(cfm(v_marg(xt, tt) + 0.1) - cfm(v_marg(xt, tt)), 4))
    # 1.0707 0.01   (the first number is the floor V > 0; the second is the FM loss of the shifted model)
    
    # (c) Euler from t = 1: one step gives the data mean, two steps give tanh(eps)
    e = np.array([-1.5, 0.2, 1.0])
    x1 = e - 1.0 * v_marg(e, 1.0)
    xh = e - 0.5 * v_marg(e, 1.0)
    x2 = xh - 0.5 * v_marg(xh, 0.5)
    print(x1, np.round(x2, 4), np.round(np.tanh(e), 4))  # [0. 0. 0.] [-0.9051  0.1974  0.7616] (twice)
    
    # (d) an Euler step of flow matching is a DDIM step (a_t = 1 - t, sigma_t = t)
    D, x, t, t2 = 0.4, 1.3, 0.7, 0.45                    # any denoiser output, state and two times
    euler = x + (t2 - t) * (x - D) / t
    eps_hat = (x - (1 - t) * D) / t
    ddim = (1 - t2) * D + t2 * eps_hat
    print(round(euler, 6), round(ddim, 6))              # 0.978571 0.978571
    
    # (e) minibatch OT: pair B data points with B noise points by an exact assignment
    K, s = 8, 0.15
    MU = np.array([[2 * np.cos(2 * np.pi * k / K), 2 * np.sin(2 * np.pi * k / K)] for k in range(K)])
    for B in (1, 16, 64, 256):
        costs = []
        for _ in range(4096 // B):
            xb = MU[rng.integers(0, K, B)] + s * rng.standard_normal((B, 2))
            eb = rng.standard_normal((B, 2))
            C = ((xb[:, None] - eb[None]) ** 2).sum(-1)
            r, c = linear_sum_assignment(C)
            costs.append(C[r, c].mean())
        print(B, round(np.mean(costs), 2))
    # 1 6.03 / 16 1.68 / 64 1.1 / 256 0.97   (independent pairs: E|eps|^2 + E|x0|^2 = 2 + 4.045)
    

    The CFM loss of the exact velocity is about 1.07 here: the model is perfect, but the loss is far from 0. Shifting the velocity by 0.1 raises the loss by exactly 0.120.1^2, the FM loss of the shifted model, as Theorem 2 says.

    6. Where it shows up #

    • Image and video models. Stable Diffusion 3 trains a rectified-flow transformer with the linear path and samples tt from a logit-normal distribution, shifted toward high noise for large images (Esser et al. 2024). Flux uses the same objective. Meta's Movie Gen is trained with flow matching.
    • Few-step generation. Reflow, InstaFlow and other straightening methods prepare a flow for distillation into one or a few steps (lesson 12).
    • Guidance and latent models. Classifier-free guidance (lesson 11) works on velocities as on scores, since they are linear maps of each other; most large flow models run in the latent space of an autoencoder (lesson 13).
    • Science. Flow matching emulates weather and climate fields, generates molecules and protein structures (often with Riemannian flow matching on rotations and spheres), and samples seismic waveforms. When an emulator must produce many ensemble members, the straightness of its paths sets the compute budget.
    • Likelihoods. A trained flow is a continuous normalizing flow, so its exact log-likelihood can be computed with the instantaneous change of variables of lesson 04, at the cost of an accurate ODE solve.

    7. Common mistakes #

    • Thinking the model learns ε−x0\varepsilon - x_0. It learns the conditional mean. When lines cross, the best CFM loss is V>0V > 0, and the marginal paths are curved although every training path is straight.
    • Mixing time conventions. Papers use "data at 0" or "data at 1". Converting maps t↦1−tt \mapsto 1 - t and flips the sign of the velocity. A sampler that runs the wrong way produces noise, not data.
    • Reading the CFM loss as an error. Its floor depends on the data and the coupling. Compare samples, not loss values, across couplings or datasets.
    • One large Euler step on an independent-coupling model. It lands on the data mean (blur). Use several steps, a better solver, or straighten the flow first.
    • Sampling tt only near the ends, or uniformly without thought. The distribution of tt in training is a loss weight over noise levels (lesson 08). Stable Diffusion 3 found logit-normal sampling better than uniform.
    • Minibatch OT done once, or reflow done many times. The OT pairing must be recomputed in every batch; each reflow round fits a model to model output, so errors accumulate.
    • Dividing by tt at t=0t = 0. The formula v=(x−D)/tv = (x - D)/t is singular at t=0t = 0; a network that predicts vv directly has no problem, but code that converts from a denoiser must stop at a small tmin⁡t_{\min} or take the last step to DD.

    8. Check yourself #

    1. Write the CFM loss for the linear path, and say which quantity a perfect network outputs.
      AnswerLCFM=Et,x0,ε∥vθ((1−t)x0+tε,t)−(ε−x0)∥2L_{\text{CFM}} = \mathbb E_{t, x_0, \varepsilon}\|v_\theta((1 - t)x_0 + t\varepsilon, t) - (\varepsilon - x_0)\|^2 with t∼U[0,1]t \sim \mathcal U[0, 1]. A perfect network outputs the marginal velocity v(x,t)=E[ε−x0∣xt=x]=(x−D(x,t))/tv(x, t) = \mathbb E[\varepsilon - x_0 \mid x_t = x] = (x - D(x, t))/t.
    2. Show that the CFM gradient equals the FM gradient. Which step of the proof uses the tower property?
      AnswerExpand both squares. The ∥vθ∥2\|v_\theta\|^2 terms agree because xt∼ptx_t \sim p_t. The cross term E⟨vθ(xt),ε−x0⟩\mathbb E\langle v_\theta(x_t), \varepsilon - x_0\rangle equals E⟨vθ(xt),E[ε−x0∣xt]⟩\mathbb E\langle v_\theta(x_t), \mathbb E[\varepsilon - x_0 \mid x_t]\rangle by the tower property, which is the FM cross term. The remaining terms do not depend on θ\theta.
    3. Data N(0,1)\mathcal N(0, 1) in 1D, noise N(0,1)\mathcal N(0, 1), independent coupling, linear path. Compute the marginal velocity.
      Answerxt=(1−t)x0+tεx_t = (1 - t)x_0 + t\varepsilon has variance (1−t)2+t2(1 - t)^2 + t^2. Gaussian conditioning: D=E[x0∣xt]=1−t(1−t)2+t2xD = \mathbb E[x_0 \mid x_t] = \frac{1 - t}{(1 - t)^2 + t^2}x. So v=(x−D)/t=(1−t)2+t2−(1−t)t ((1−t)2+t2)x=2t−1(1−t)2+t2xv = (x - D)/t = \frac{(1 - t)^2 + t^2 - (1 - t)}{t\,((1 - t)^2 + t^2)}x = \frac{2t - 1}{(1 - t)^2 + t^2}x. At t=1t = 1: v=xv = x; at t=12t = \tfrac12: v=0v = 0 (the variance is smallest there); at t=0t = 0: v=−xv = -x.
    4. Why can paths of the marginal ODE not cross, although the training lines do?
      AnswerWith a Lipschitz velocity the ODE has exactly one solution through each point (x,t)(x, t). If two paths met at one time, they would be the same solution at all times. The training lines are not solutions of one ODE; each follows its own pair's velocity.
    5. In the proof that reflow lowers convex costs, where is convexity used, and why twice?
      AnswerOnce in time: Z1−Z0Z_1 - Z_0 is the time average of v(Zt,t)v(Z_t, t), so Jensen gives c(Z1−Z0)≤∫c(v) dtc(Z_1 - Z_0) \le \int c(v)\,dt. Once in conditional expectation: v(Xt,t)v(X_t, t) is the conditional mean of X1−X0X_1 - X_0, so c(v)≤E[c(X1−X0)∣Xt]c(v) \le \mathbb E[c(X_1 - X_0) \mid X_t]. The equality of the laws of ZtZ_t and XtX_t links the two steps.
    6. Show that for the linear path x^0=xt−t v^\hat x_0 = x_t - t\,\hat v and ε^=xt+(1−t) v^\hat\varepsilon = x_t + (1 - t)\,\hat v.
      AnswerFrom xt=(1−t)x0+tεx_t = (1 - t)x_0 + t\varepsilon and v=ε−x0v = \varepsilon - x_0: xt−tv=(1−t)x0+tε−tε+tx0=x0x_t - t v = (1 - t)x_0 + t\varepsilon - t\varepsilon + t x_0 = x_0, and xt+(1−t)v=(1−t)x0+tε+(1−t)ε−(1−t)x0=εx_t + (1 - t)v = (1 - t)x_0 + t\varepsilon + (1 - t)\varepsilon - (1 - t)x_0 = \varepsilon. The same identities hold for the conditional means, so they hold for the predictions.
    Recall cardsAnswer in your head first, then reveal. Add the cards to your review deck to see them again just before you would forget.
    1. Give the linear conditional path of flow matching and its velocity (this track's convention).

    2. What is the marginal velocity, and what does it generate?

    3. Write the CFM loss.

    4. Why does the CFM loss have the same gradient as the FM loss?

    5. What is the minimum value of the CFM loss?

    6. Express the linear-path velocity through the denoiser D(x,t)=E[x0∣xt=x]D(x, t) = \mathbb E[x_0 \mid x_t = x].

    7. Where does one Euler step of size 1 from t=1t = 1 land, and why?

    8. What is reflow?

    9. Convert a velocity from the convention "noise at s=0s = 0, data at s=1s = 1" to this track's convention.

    Open the review →

    9. Interview angle #

    • "Flow matching or diffusion: what is the difference?" — With Gaussian paths they learn the same object up to a linear map (velocity, denoiser, score). They differ in the path (at,σta_t, \sigma_t), the loss weight over noise levels and the sampler grid. Flow matching regresses a velocity on straight lines and is simulation-free.
    • "Why is the CFM loss valid if the network never sees the marginal velocity?" — The conditional target's mean given xtx_t is the marginal velocity; by the tower property the two losses differ by a constant.
    • "Why can't you sample a flow-matching model in one step?" — Lines of independent pairs cross; the learned velocity is an average; the first step heads toward the data mean. Straighten (reflow, OT couplings) or distill.
    • "What does rectified flow guarantee?" — The rectified coupling has no higher cost for every convex cost, and repeated reflow makes the paths straight in the limit. It is not in general the optimal transport map in d≥2d \ge 2, but in 1D it is.
    • "You load a flow model from another code base and get noise. First thing to check?" — The time convention and the sign of the velocity, then the noise scale of the prior.

    10. Practice #

    The notebook for this lesson has five exercises, each with a check cell and a folded solution:

    1. Estimate the marginal velocity of the two-point data by Monte Carlo (binning xtx_t) and compare it with (x−D)/t(x - D)/t.
    2. Write the CFM batch (inputs and targets) and the loss; check Theorem 2 numerically. A demonstration then fits a small velocity model on two moons by least squares and samples it with Euler.
    3. Write a flow-matching Euler sampler for the 8 Gaussians with the exact velocity; measure the sample error against the number of steps.
    4. 1D reflow: compute the ODE map numerically for a two-Gaussian mixture and check that it equals the quantile (optimal transport) map; after reflow one step is exact.
    5. Minibatch OT with linear_sum_assignment: measure how the pairing cost and the CFM floor fall with the batch size.

    11. Watch and read #

    The conditional and marginal probability paths, the marginalization trick and the CFM loss, in the "noise at 0, data at 1" convention.
    Open on YouTube · the player loads from youtube-nocookie.com when you press play
    A talk by the first author: why the conditional loss works, the choice of paths, and how diffusion fits in.
    Open on YouTube · the player loads from youtube-nocookie.com when you press play
    A section-by-section reading of the original flow matching paper.
    Open on YouTube · the player loads from youtube-nocookie.com when you press play
    A visual explanation of velocity fields, the continuity equation and why the learned paths bend.
    Open on YouTube · the player loads from youtube-nocookie.com when you press play