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

    ML for Science · Lesson 14 · Stochastic and generative models

    Flow matching, rectified flow and optimal transport

    Advanced 120 min 5 interactive figures 4 videos Colab notebook

    Before this lesson: score matching and the "conditional target" idea (lesson 13); flow matching for images, if you want the ML side first (generative models 10); matrix square roots (linear algebra 07); Lagrange multipliers (optimization 08); conditional expectation (probability 04). Time: about 120 minutes, plus the notebook.


    Why this matters #

    • Fast generative ensembles. A generative weather model samples many possible future states. The cost of one sample is (solver steps) × (one network call). Straighter paths mean fewer steps. ArchesWeatherGen (Couairon et al., 2024) is a weather ensemble model trained with flow matching. Stable Diffusion 3 (Esser et al., 2024) trains rectified-flow transformers for images.
    • Comparing distributions. The Wasserstein distance W2W_2 compares two distributions by how far mass must move. It compares a generated ensemble with observations, and its Gaussian version (the Bures formula) is the formula behind FID, the standard score for image generators.
    • Seismic imaging. A Wasserstein misfit between observed and simulated seismograms is less prone to cycle skipping than the least-squares misfit in full-waveform inversion (see lesson 04).
    • Data assimilation. The ensemble transform particle filter (Reich, 2013) turns a weighted ensemble into an equally weighted one with an optimal transport plan (lesson 06).

    1. Predict first #

    2. The picture #

    One pair: a straight line #

    Fix a noise point x0x_0 and a data point x1x_1. The straight line xt=(1−t)x0+tx1x_t = (1 - t)x_0 + t x_1 has the constant velocity x˙t=x1−x0\dot x_t = x_1 - x_0. One Euler step of size 1 from x0x_0 lands exactly on x1x_1.

    Many pairs: the lines cross, the flow bends #

    Now draw many pairs. Their lines cross. An ODE x˙=ut(x)\dot x = u_t(x) cannot have crossing paths: through each point (x,t)(x, t) passes exactly one solution. So the best single velocity at (x,t)(x, t) is the average direction of all lines that pass through xx at time tt:

    ut(x)=E [ x1−x0∣xt=x ].u_t(x) = \mathbb E\,[\,x_1 - x_0 \mid x_t = x\,].

    Averaging over crossing lines bends the paths. In the figure, grey lines are the pairs and orange curves are the paths of the flow with this average velocity, which is what a perfect model learns.

    Interactive figure: loading…

    Switch the coupling between "independent" and "minibatch OT", and move the time slider. Grey: one straight line per pair, from a noise point to a data point (aqua). Orange: with the independent coupling, the paths of the exact marginal velocity ut(x)=(E[x1∣xt=x]−x)/(1−t)u_t(x) = (\mathbb E[x_1 \mid x_t = x] - x)/(1 - t), started at the same noise points. They first move toward the centre and then turn, because early on the model cannot know which data point a path will reach. With minibatch OT the pairs are re-matched to minimise ∑i∣x1i−x0i∣2\sum_i \lvert x_1^i - x_0^i\rvert^2: the transport cost drops, and no pair can be made cheaper by swapping partners. For an exact OT coupling the straight lines are the paths of the flow (Theorem 6).

    The 1D example, in full #

    Take noise N(0,1)\mathcal N(0, 1) and data ±2\pm 2. At t=0t = 0 the line through x0x_0 goes to −2-2 or to +2+2 with equal chance. So u0(x)=E[x1]−x=−xu_0(x) = \mathbb E[x_1] - x = -x: every path starts toward the mean 00, and only later turns to −2-2 or +2+2. Section 4(d) derives the whole field: ut(x)=(2tanh⁡(2tx/(1−t)2)−x)/(1−t)u_t(x) = \big(2\tanh(2tx/(1 - t)^2) - x\big)/(1 - t).

    Interactive figure: loading…

    Move the slider for the number of Euler steps NN; then switch the coupling. The background is the velocity ut(x)u_t(x) over time (horizontal) and position (vertical): violet where u<0u < 0, yellow where u>0u > 0. Dark lines: exact paths from 13 noise values. Orange: Euler with NN steps from the same values. With the independent coupling, one step sends every sample to 00, the mean of the data; the mean distance to the nearest data point is 2.0 for N=1N = 1, about 0.5 for N=2N = 2 and about 0.01 for N=4N = 4. With the monotone (OT) coupling, negative noise goes to −2-2 and positive noise to +2+2: the paths are straight and one step is exact.

    A better pairing gives straight paths #

    Send negative noise to −2-2 and positive noise to +2+2. Now no lines cross. The average over the lines through a point is the one line itself, and the paths are straight. This sorted pairing is the optimal transport coupling. There are two ways to straighten the paths:

    1. choose a better coupling before training (exact OT, or minibatch OT);
    2. train once, then re-pair each noise point with the end point of the model's own path, and train again (reflow).
    Quick check

    In the 1D example (noise N(0,1)\mathcal N(0, 1), data ±2\pm 2, independent coupling), what is the velocity u0(x)u_0(x) of the perfect model at time 00?

    3. Definitions and main results #

    Flows and the continuity equation #

    A velocity field ut(x)u_t(x) defines a flow: the solution of x˙=ut(x)\dot x = u_t(x). If x(0)∼p0x(0) \sim p_0, the density ptp_t of x(t)x(t) solves the continuity equation

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

    In words: the density at a point changes only because mass flows in or out; no mass is created. We say "utu_t generates ptp_t". (Lesson 12 derived the Fokker–Planck equation; with zero diffusion it is this equation.)

    Flow matching needs a path of densities ptp_t from noise p0p_0 to data p1p_1 and a field utu_t that generates it. The flow matching (FM) loss is

    LFM(θ)=Et∼U[0,1],  x∼pt∥vθ(x,t)−ut(x)∥2.L_{\mathrm{FM}}(\theta) = \mathbb E_{t \sim U[0,1],\; x \sim p_t} \lVert v_\theta(x, t) - u_t(x) \rVert^2 .

    We do not know utu_t, so we cannot compute this loss. The way out uses pairs.

    A coupling π\pi of p0p_0 and p1p_1 is a joint distribution of (x0,x1)(x_0, x_1) whose marginals are p0p_0 and p1p_1. The independent coupling is p0⊗p1p_0 \otimes p_1: draw x0x_0 and x1x_1 separately. Given a coupling, set xt=(1−t)x0+tx1x_t = (1 - t)x_0 + t x_1, let ptp_t be the law of xtx_t, and define the marginal velocity

    ut(x)=E [ x1−x0∣xt=x ].u_t(x) = \mathbb E\,[\,x_1 - x_0 \mid x_t = x\,].

    Theorem 1 (the marginalization trick) #

    The marginal velocity utu_t generates ptp_t. When utu_t is regular enough (for example, Lipschitz in xx), the ODE x˙=ut(x)\dot x = u_t(x) started from p0p_0 has the marginals ptp_t and ends at the data distribution p1p_1.

    Why it is true, in one line. Each pair moves mass along its own line. At a point xx, the total flow of mass is the sum over the lines through xx; dividing by the density pt(x)p_t(x) gives the average velocity there.

    Proof of Theorem 1 (weak form)

    Take any smooth test function φ\varphi with compact support.

    1. Along each line, ddtφ(xt)=∇φ(xt)⋅(x1−x0)\frac{d}{dt}\varphi(x_t) = \nabla\varphi(x_t) \cdot (x_1 - x_0). Take the expectation: ddtE[φ(xt)]=E[∇φ(xt)⋅(x1−x0)]\frac{d}{dt}\mathbb E[\varphi(x_t)] = \mathbb E[\nabla\varphi(x_t) \cdot (x_1 - x_0)].
    2. Condition on xtx_t (the tower property E[Z]=E[E[Z∣xt]]\mathbb E[Z] = \mathbb E[\mathbb E[Z \mid x_t]]): this equals E[∇φ(xt)⋅ut(xt)]=∫∇φ⋅ut pt dx\mathbb E[\nabla\varphi(x_t) \cdot u_t(x_t)] = \int \nabla\varphi \cdot u_t\, p_t\, dx.
    3. The left side is ddt∫φ pt dx\frac{d}{dt}\int \varphi\, p_t\, dx. Integrate the right side by parts: ∫φ ∂tpt dx=−∫φ ∇⋅(ptut) dx\int \varphi\, \partial_t p_t\, dx = -\int \varphi\, \nabla\cdot(p_t u_t)\, dx for every φ\varphi. This is the weak form of ∂tpt+∇⋅(ptut)=0\partial_t p_t + \nabla\cdot(p_t u_t) = 0. ■\blacksquare

    Theorem 2 (conditional flow matching) #

    Define the conditional flow matching (CFM) loss

    LCFM(θ)=Et,  (x0,x1)∼π∥vθ(xt,t)−(x1−x0)∥2.L_{\mathrm{CFM}}(\theta) = \mathbb E_{t,\;(x_0, x_1) \sim \pi} \lVert v_\theta(x_t, t) - (x_1 - x_0) \rVert^2 .

    Then LCFM(θ)=LFM(θ)+VL_{\mathrm{CFM}}(\theta) = L_{\mathrm{FM}}(\theta) + V, where VV does not depend on θ\theta. So the two losses have the same gradients and the same minimizer v⋆=utv^\star = u_t.

    1. Expand: ∥v−(x1−x0)∥2=∥v∥2−2⟨v,x1−x0⟩+∥x1−x0∥2\lVert v - (x_1 - x_0)\rVert^2 = \lVert v\rVert^2 - 2\langle v, x_1 - x_0\rangle + \lVert x_1 - x_0\rVert^2.
    2. The term E∥vθ(xt,t)∥2\mathbb E\lVert v_\theta(x_t, t)\rVert^2 is the same in both losses, because xt∼ptx_t \sim p_t.
    3. Cross term, by the tower property: E⟨vθ(xt,t),x1−x0⟩=E⟨vθ(xt,t),E[x1−x0∣xt]⟩=E⟨vθ(xt,t),ut(xt)⟩\mathbb E\langle v_\theta(x_t, t), x_1 - x_0\rangle = \mathbb E\langle v_\theta(x_t, t), \mathbb E[x_1 - x_0 \mid x_t]\rangle = \mathbb E\langle v_\theta(x_t, t), u_t(x_t)\rangle.
    4. What remains does not contain θ\theta: V=∫01E∥x1−x0−ut(xt)∥2 dt≥0V = \int_0^1 \mathbb E\lVert x_1 - x_0 - u_t(x_t)\rVert^2\, dt \ge 0. ■\blacksquare

    This is the argument of denoising score matching in lesson 13: 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 exactly when no two lines meet at the same time.

    Quick check

    You train CFM with the independent coupling and a perfect network. What value does the CFM loss reach?

    Link to diffusion. With source p0=N(0,I)p_0 = \mathcal N(0, I) and the independent coupling, ut(x)=(x+(1−t)∇log⁡pt(x))/tu_t(x) = \big(x + (1 - t)\nabla\log p_t(x)\big)/t (check yourself 6). A velocity model and a score model carry the same information.

    Theorem 3 (rectified flow lowers convex transport costs) #

    Let utu_t be the marginal velocity of a coupling (X0,X1)(X_0, X_1), and let ZZ solve Z˙t=ut(Zt)\dot Z_t = u_t(Z_t) with Z0=X0Z_0 = X_0. Assume this ODE has a unique solution (Liu, Gong and Liu, 2022, call the coupling rectifiable). Then (Z0,Z1)(Z_0, Z_1) is again a coupling of p0p_0 and p1p_1 (Theorem 1), called the rectified flow, and for every convex cost 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 of Theorem 3
    1. Z1−Z0=∫01ut(Zt) dtZ_1 - Z_0 = \int_0^1 u_t(Z_t)\, dt, so by Jensen's inequality over tt: c(Z1−Z0)≤∫01c(ut(Zt)) dtc(Z_1 - Z_0) \le \int_0^1 c(u_t(Z_t))\, dt.
    2. ZtZ_t and XtX_t have the same law (Theorem 1), so E c(ut(Zt))=E c(ut(Xt))\mathbb E\, c(u_t(Z_t)) = \mathbb E\, c(u_t(X_t)).
    3. ut(Xt)=E[X1−X0∣Xt]u_t(X_t) = \mathbb E[X_1 - X_0 \mid X_t], so by conditional Jensen: c(ut(Xt))≤E[c(X1−X0)∣Xt]c(u_t(X_t)) \le \mathbb E[c(X_1 - X_0) \mid X_t].
    4. Take expectations and integrate over tt: E c(Z1−Z0)≤E c(X1−X0)\mathbb E\, c(Z_1 - Z_0) \le \mathbb E\, c(X_1 - X_0). ■\blacksquare

    The new coupling is deterministic: Z1Z_1 is a function of Z0Z_0.

    Straightness. Liu et al. define S(Z)=∫01E∥(Z1−Z0)−ut(Zt)∥2 dtS(Z) = \int_0^1 \mathbb E\lVert (Z_1 - Z_0) - u_t(Z_t)\rVert^2\, dt. S=0S = 0 means straight paths at constant speed, so one Euler step is exact. For c=∥⋅∥2c = \lVert\cdot\rVert^2 the two Jensen steps become equalities plus variance terms, and

    E∥X1−X0∥2−E∥Z1−Z0∥2=S(Z)+V.\mathbb E\lVert X_1 - X_0\rVert^2 - \mathbb E\lVert Z_1 - Z_0\rVert^2 = S(Z) + V .

    Reflow. Train a new flow on the pairs (Z0,Z1)(Z_0, Z_1), then repeat. The transport cost falls in each round by S+VS + V and cannot fall below 00. Summing over KK rounds gives min⁡1≤k≤KS(Zk)≤E∥X1−X0∥2/K\min_{1 \le k \le K} S(Z^k) \le \mathbb E\lVert X_1 - X_0\rVert^2/K for the kk-th rectified flows ZkZ^k. The price: each round must simulate the current flow to make new pairs, and each round fits a model to model output, so errors add up. In practice one or two reflows are used, often followed by distillation into a one-step model (generative models 12).

    Optimal transport: Monge and Kantorovich #

    Let μ\mu and ν\nu be probability distributions and c(x,y)c(x, y) a cost of moving a unit of mass from xx to yy.

    • Monge problem: find a map TT with T#μ=νT_\#\mu = \nu (if x∼μx \sim \mu then T(x)∼νT(x) \sim \nu) that minimizes ∫c(x,T(x)) dμ(x)\int c(x, T(x))\, d\mu(x). A map may not exist: μ=δ0\mu = \delta_0 cannot be split into 12δ−1+12δ1\tfrac12\delta_{-1} + \tfrac12\delta_1.
    • Kantorovich problem: minimize ∫c dπ\int c\, d\pi over all couplings π∈Π(μ,ν)\pi \in \Pi(\mu, \nu). Mass may now be split. This is a linear program, and under mild conditions (for example, a continuous cost bounded below) a minimizer exists. For discrete weights a∈Rna \in \R^n, b∈Rmb \in \R^m and a cost matrix CC: minimize ⟨C,P⟩=∑ijCijPij\langle C, P\rangle = \sum_{ij} C_{ij}P_{ij} over transport plans P≥0P \ge 0 with P1=aP\mathbf 1 = a and P⊤1=bP^\top\mathbf 1 = b.
    • Birkhoff–von Neumann: with n=mn = m and weights 1/n1/n, some optimal PP is a permutation matrix divided by nn. Then Monge and Kantorovich agree, and the Hungarian algorithm (scipy.optimize.linear_sum_assignment) solves the problem in O(n3)O(n^3).
    • Wasserstein distance: Wp(μ,ν)=(min⁡πEπ∥x−y∥p)1/pW_p(\mu, \nu) = \big(\min_\pi \mathbb E_\pi\lVert x - y\rVert^p\big)^{1/p}. It is a metric on distributions with finite pp-th moments.
    • Brenier's theorem: for the cost ∥x−y∥2\lVert x - y\rVert^2, μ\mu with a density, and finite second moments, the optimal map exists, is unique (μ\mu-almost everywhere), and is the gradient of a convex function, T=∇ϕT = \nabla\phi. Conversely, a map ∇ϕ\nabla\phi with convex ϕ\phi that pushes μ\mu to ν\nu is optimal.

    1D OT is sorting. On a line, for every convex cost c(x−y)c(x - y), the monotone coupling is optimal: the ii-th smallest source point goes to the ii-th smallest target point. In terms of the quantile functions F−1F^{-1} and G−1G^{-1}, Wpp=∫01∣F−1(s)−G−1(s)∣p dsW_p^p = \int_0^1 \lvert F^{-1}(s) - G^{-1}(s)\rvert^p\, ds. The reason: if two pairs cross, x<x′x < x' but y>y′y > y', then swapping partners does not raise the cost, and for a strictly convex cost it lowers it.

    Interactive figure: loading…

    Drag the points. Blue: source points; aqua: target points; each has weight 1/n1/n. Orange: the sorted matching. Magenta dashed: the pairing in index order xi→yix_i \to y_i. The readout checks all n!n! pairings by brute force: the best one always has the sorted cost, and the orange lines never cross.

    Theorem 4 (Gaussian W2W_2, the Bures formula) #

    For μ=N(m1,S1)\mu = \mathcal N(m_1, S_1) and ν=N(m2,S2)\nu = \mathcal N(m_2, S_2),

    W22(μ,ν)=∥m1−m2∥2+tr⁡ ⁣(S1+S2−2(S11/2S2S11/2)1/2).W_2^2(\mu, \nu) = \lVert m_1 - m_2\rVert^2 + \operatorname{tr}\!\Big(S_1 + S_2 - 2\big(S_1^{1/2} S_2 S_1^{1/2}\big)^{1/2}\Big).

    The first term moves the centre; the second term (the Bures term) reshapes the covariance. The optimal map is affine: T(x)=m2+A(x−m1)T(x) = m_2 + A(x - m_1) with the symmetric positive definite matrix

    A=S1−1/2(S11/2S2S11/2)1/2S1−1/2.A = S_1^{-1/2}\big(S_1^{1/2} S_2 S_1^{1/2}\big)^{1/2} S_1^{-1/2}.
    Proof sketch of Theorem 4 (for S1≻0S_1 \succ 0; the singular case follows by continuity)
    1. For any coupling, E∥X−Y∥2=∥m1−m2∥2+tr⁡S1+tr⁡S2−2tr⁡K\mathbb E\lVert X - Y\rVert^2 = \lVert m_1 - m_2\rVert^2 + \operatorname{tr}S_1 + \operatorname{tr}S_2 - 2\operatorname{tr}K with K=Cov⁡(X,Y)K = \operatorname{Cov}(X, Y). So OT means: make tr⁡K\operatorname{tr}K as large as possible.
    2. Try Y=m2+A(X−m1)Y = m_2 + A(X - m_1) with AA symmetric positive semidefinite. Then Y∼N(m2,AS1A)Y \sim \mathcal N(m_2, AS_1A), so we need AS1A=S2AS_1A = S_2. The matrix AA above solves it: substitute and use S1−1/2S1S1−1/2=IS_1^{-1/2}S_1S_1^{-1/2} = I.
    3. Then K=S1AK = S_1A, and by the cyclic property of the trace, tr⁡(S1A)=tr⁡(S11/2S2S11/2)1/2\operatorname{tr}(S_1A) = \operatorname{tr}\big(S_1^{1/2}S_2S_1^{1/2}\big)^{1/2}.
    4. The map is ∇ϕ\nabla\phi for the convex ϕ(x)=12(x−m1)⊤A(x−m1)+m2⊤x\phi(x) = \tfrac12(x - m_1)^\top A(x - m_1) + m_2^\top x, so it is optimal by Brenier's theorem. Put tr⁡K\operatorname{tr}K into step 1. ■\blacksquare

    Special cases. In 1D, W22=(m1−m2)2+(s1−s2)2W_2^2 = (m_1 - m_2)^2 + (s_1 - s_2)^2 with standard deviations s1,s2s_1, s_2. For commuting covariances, the Bures term is ∥S11/2−S21/2∥F2\lVert S_1^{1/2} - S_2^{1/2}\rVert_F^2. For non-Gaussian distributions with the same means and covariances, the formula is a lower bound on W22W_2^2 (Gelbrich's bound).

    Interactive figure: loading…

    Drag the centres and the small axis handles, and move tt. Blue: the source N(m1,S1)\mathcal N(m_1, S_1); aqua: the target N(m2,S2)\mathcal N(m_2, S_2), as 1-standard-deviation ellipses. Grey segments: the straight paths x→T(x)x \to T(x) of the OT map for 12 points of the source ellipse. Yellow: the distribution at time tt (the law of (1−t)x+tT(x)(1 - t)x + tT(x)), which is again Gaussian. Try "shift only": the Bures term is 00. Try "rotation": the means agree, but the shape term is not zero.

    Quick check

    What is W22W_2^2 between N(0,1)\mathcal N(0, 1) and N(3,4)\mathcal N(3, 4) in 1D (the second numbers are variances)?

    Entropic OT and the Sinkhorn algorithm #

    Exact OT between nn points costs about O(n3)O(n^3). A popular alternative adds an entropy term. With H(P)=−∑ijPijlog⁡PijH(P) = -\sum_{ij} P_{ij}\log P_{ij} and ε>0\varepsilon > 0, entropic OT is

    min⁡P∈Π(a,b) ⟨C,P⟩−εH(P).\min_{P \in \Pi(a, b)} \ \langle C, P\rangle - \varepsilon H(P).

    The problem is strictly convex, so the solution PεP_\varepsilon is unique. The entropy term rewards spread-out plans, so ε\varepsilon sets how blurred the plan is.

    Form of the solution. Use multipliers fif_i for the row constraints and gjg_j for the column constraints (optimization 08). Setting the derivative of the Lagrangian with respect to PijP_{ij} to zero gives Cij+ε(log⁡Pij+1)−fi−gj=0C_{ij} + \varepsilon(\log P_{ij} + 1) - f_i - g_j = 0. Absorb the constant into ff:

    Pij=exp⁡ ⁣((fi+gj−Cij)/ε).P_{ij} = \exp\!\big((f_i + g_j - C_{ij})/\varepsilon\big).

    Equivalently P=diag⁡(u) Kdiag⁡(v)P = \operatorname{diag}(u)\, K \operatorname{diag}(v) with the Gibbs kernel K=e−C/εK = e^{-C/\varepsilon}, u=ef/εu = e^{f/\varepsilon}, v=eg/εv = e^{g/\varepsilon}.

    Sinkhorn alternates two scalings. Each one makes one marginal exact: u←a⊘(Kv)u \leftarrow a \oslash (Kv), then v←b⊘(K⊤u)v \leftarrow b \oslash (K^\top u) (elementwise division). In the log domain, with LSE⁡(z)=log⁡∑ez\operatorname{LSE}(z) = \log\sum e^{z}:

    fi←εlog⁡ai−εLSE⁡j((gj−Cij)/ε),gj←εlog⁡bj−εLSE⁡i((fi−Cij)/ε).f_i \leftarrow \varepsilon\log a_i - \varepsilon\operatorname{LSE}_j\big((g_j - C_{ij})/\varepsilon\big), \qquad g_j \leftarrow \varepsilon\log b_j - \varepsilon\operatorname{LSE}_i\big((f_i - C_{ij})/\varepsilon\big).

    Each iteration costs O(nm)O(nm) and is all matrix–vector work, so it runs well on a GPU. The number of iterations grows as ε\varepsilon shrinks. Why the log domain: e−746=0e^{-746} = 0 in float64, so kernel entries with Cij/εC_{ij}/\varepsilon above about 745 underflow. When a whole row of KK is zero, a⊘(Kv)a \oslash (Kv) divides by zero. The LSE with its maximum subtracted never underflows.

    Interactive figure: loading…

    Move ε\varepsilon; then press Reset and Step a few times. Rows are five source points with weights aia_i, columns five target points with weights 1/51/5, cost (xi−yj)2(x_i - y_j)^2. Darker orange cells carry more mass; blue outlines mark the exact OT plan. After a row step the row sums (right) equal aa; after a column step the column sums (top) equal bb. Small ε\varepsilon: a sharp plan close to the exact one, but thousands of iterations (about 11 500 for ε=0.01\varepsilon = 0.01). Large ε\varepsilon: a blurred plan close to the independent plan ab⊤ab^\top.

    Theorem 5: the bias of entropic OT, and the dual problem

    Theorem 5. 0≤⟨C,Pε⟩−OT≤εmin⁡(H(a),H(b))0 \le \langle C, P_\varepsilon\rangle - \mathrm{OT} \le \varepsilon\min\big(H(a), H(b)\big), where OT is the exact optimal cost and H(a)=−∑iailog⁡aiH(a) = -\sum_i a_i\log a_i.

    1. PεP_\varepsilon is a coupling and OT is the minimum over couplings, so the gap is ≥0\ge 0.
    2. PεP_\varepsilon beats an exact OT plan P⋆P^\star on the entropic objective: ⟨C,Pε⟩−εH(Pε)≤OT−εH(P⋆)\langle C, P_\varepsilon\rangle - \varepsilon H(P_\varepsilon) \le \mathrm{OT} - \varepsilon H(P^\star). So the gap is ≤ε(H(Pε)−H(P⋆))\le \varepsilon\big(H(P_\varepsilon) - H(P^\star)\big).
    3. For every coupling, max⁡(H(a),H(b))≤H(P)≤H(a)+H(b)\max(H(a), H(b)) \le H(P) \le H(a) + H(b): a joint entropy is at least each marginal entropy and at most their sum.
    4. So the gap is ≤ε(H(a)+H(b)−max⁡(H(a),H(b)))=εmin⁡(H(a),H(b))\le \varepsilon\big(H(a) + H(b) - \max(H(a), H(b))\big) = \varepsilon\min(H(a), H(b)). ■\blacksquare

    As ε→0\varepsilon \to 0, PεP_\varepsilon tends to an exact OT plan (the one of largest entropy if there are several); as ε→∞\varepsilon \to \infty, it tends to ab⊤ab^\top.

    The dual. Entropic OT has the unconstrained concave dual problem max⁡f,g ⟨f,a⟩+⟨g,b⟩−ε∑ije(fi+gj−Cij)/ε\max_{f, g}\ \langle f, a\rangle + \langle g, b\rangle - \varepsilon\sum_{ij} e^{(f_i + g_j - C_{ij})/\varepsilon} (up to a constant). Setting the gradient in ff to zero gives exactly the ff-update above, and the same for gg. So Sinkhorn is block coordinate ascent on the dual: each half-step maximizes over one block exactly. See Peyré and Cuturi, Computational Optimal Transport, ch. 4.

    Theorem 6 (optimal transport paths do not cross) #

    Let π\pi be optimal for the cost ∥x−y∥2\lVert x - y\rVert^2. If two pairs (x0,x1)(x_0, x_1) and (x0′,x1′)(x_0', x_1') in the support of π\pi are at the same point at some time t∈(0,1)t \in (0, 1), then they are the same pair.

    1. Optimality means that swapping partners cannot lower the cost (c-cyclical monotonicity): ∥x0−x1∥2+∥x0′−x1′∥2≤∥x0−x1′∥2+∥x0′−x1∥2\lVert x_0 - x_1\rVert^2 + \lVert x_0' - x_1'\rVert^2 \le \lVert x_0 - x_1'\rVert^2 + \lVert x_0' - x_1\rVert^2.
    2. Expand both sides. The squared norms cancel, and what is left is ⟨a,b⟩≥0\langle a, b\rangle \ge 0 with a=x0−x0′a = x_0 - x_0' and b=x1−x1′b = x_1 - x_1'.
    3. Meeting at time tt means (1−t)a+tb=0(1 - t)a + tb = 0, so b=−1−ttab = -\frac{1 - t}{t}a.
    4. Then ⟨a,b⟩=−1−tt∥a∥2≥0\langle a, b\rangle = -\frac{1 - t}{t}\lVert a\rVert^2 \ge 0 forces a=0a = 0, and so b=0b = 0. ■\blacksquare

    Consequences. Under the OT coupling, the position xtx_t determines its pair, so ut(xt)=x1−x0u_t(x_t) = x_1 - x_0: the floor VV is 00, the flow moves along the straight lines, S=0S = 0, and one Euler step is exact. An optimal coupling is a fixed point of reflow. Its kinetic energy ∫01E∥ut∥2 dt\int_0^1 \mathbb E\lVert u_t\rVert^2\, dt equals W22W_2^2, the smallest possible value: by the Benamou–Brenier formula, W22(p0,p1)W_2^2(p_0, p_1) is the minimum of ∫01Ept∥vt∥2 dt\int_0^1 \mathbb E_{p_t}\lVert v_t\rVert^2\, dt over all pairs (pt,vt)(p_t, v_t) that solve the continuity equation from p0p_0 to p1p_1.

    Minibatch OT (Tong et al., 2023; Pooladian et al., 2023). In each training batch, draw BB noise points and BB data points and re-pair them by exact OT (an assignment problem). This coupling lies between the independent one and the OT one: its transport cost is lower than the independent coupling's, and it approaches the OT coupling as B→∞B \to \infty. Limits: an assignment costs about O(B3)O(B^3), and in high dimension a batch is a very coarse sample of the two distributions (empirical OT converges slowly, at a rate like B−1/dB^{-1/d}), so the paths become only partly straight.

    Quick check

    In Theorem 6, which property of the optimal plan does the proof use?

    Answers to section 1. (1) All samples land at 00, the data mean, since x0+u0(x0)=x0+(E[x1]−x0)=E[x1]x_0 + u_0(x_0) = x_0 + (\mathbb E[x_1] - x_0) = \mathbb E[x_1]: a complete collapse, at distance 2 from every data point. (2) No, by Theorem 6. Their lines may still cross in space at different times, but two particles never occupy the same place at the same time.

    4. Worked example #

    (a) 1D OT by sorting. Take x=(0,1,3)x = (0, 1, 3) and y=(5,2,4)y = (5, 2, 4), weights 13\tfrac13, cost ∣x−y∣2\lvert x - y\rvert^2.

    1. Sort both: x=(0,1,3)x = (0, 1, 3), y=(2,4,5)y = (2, 4, 5).
    2. Pair in order: 0→20 \to 2, 1→41 \to 4, 3→53 \to 5.
    3. Cost: ((0−2)2+(1−4)2+(3−5)2)/3=(4+9+4)/3=17/3≈5.667=W22\big((0 - 2)^2 + (1 - 4)^2 + (3 - 5)^2\big)/3 = (4 + 9 + 4)/3 = 17/3 \approx 5.667 = W_2^2.
    4. The pairing in the given order, 0→50 \to 5, 1→21 \to 2, 3→43 \to 4, costs (25+1+1)/3=9(25 + 1 + 1)/3 = 9.

    (b) The Bures formula. m1=0m_1 = 0, S1=IS_1 = I; m2=(1,0)m_2 = (1, 0), S2=(2112)S_2 = \begin{pmatrix} 2 & 1 \\ 1 & 2 \end{pmatrix}.

    1. Mean term: ∥m1−m2∥2=1\lVert m_1 - m_2\rVert^2 = 1.
    2. Since S1=IS_1 = I: (S11/2S2S11/2)1/2=S21/2\big(S_1^{1/2}S_2S_1^{1/2}\big)^{1/2} = S_2^{1/2}.
    3. S2S_2 has eigenvalues 33 (eigenvector (1,1)/2(1, 1)/\sqrt2) and 11 (eigenvector (1,−1)/2(1, -1)/\sqrt2). So S21/2S_2^{1/2} has eigenvalues 3\sqrt3 and 11, and tr⁡S21/2=3+1\operatorname{tr}S_2^{1/2} = \sqrt3 + 1.
    4. Bures term: tr⁡(I)+tr⁡(S2)−2tr⁡(S21/2)=2+4−2(3+1)=4−23≈0.536\operatorname{tr}(I) + \operatorname{tr}(S_2) - 2\operatorname{tr}(S_2^{1/2}) = 2 + 4 - 2(\sqrt3 + 1) = 4 - 2\sqrt3 \approx 0.536.
    5. W22=1+4−23=5−23≈1.536W_2^2 = 1 + 4 - 2\sqrt3 = 5 - 2\sqrt3 \approx 1.536. The OT map is T(x)=m2+S21/2xT(x) = m_2 + S_2^{1/2}x, with S21/2=12(3+13−13−13+1)≈(1.370.370.371.37)S_2^{1/2} = \tfrac12\begin{pmatrix} \sqrt3 + 1 & \sqrt3 - 1 \\ \sqrt3 - 1 & \sqrt3 + 1\end{pmatrix} \approx \begin{pmatrix} 1.37 & 0.37 \\ 0.37 & 1.37\end{pmatrix} (the "worked example" preset of the Bures figure).

    (c) Sinkhorn on a 2×2 problem. a=b=(12,12)a = b = (\tfrac12, \tfrac12), C=(0110)C = \begin{pmatrix} 0 & 1 \\ 1 & 0 \end{pmatrix}.

    1. Exact OT keeps each mass in place: cost 0.
    2. By symmetry u=v=(c,c)u = v = (c, c), so P11=c2P_{11} = c^2 and P12=c2e−1/εP_{12} = c^2e^{-1/\varepsilon}.
    3. The row sum must be 12\tfrac12: c2(1+e−1/ε)=12c^2(1 + e^{-1/\varepsilon}) = \tfrac12. So P12=12(e1/ε+1)P_{12} = \dfrac{1}{2(e^{1/\varepsilon} + 1)}, and the cost is ⟨C,P⟩=2P12=1e1/ε+1\langle C, P\rangle = 2P_{12} = \dfrac{1}{e^{1/\varepsilon} + 1}.
    4. For ε=1\varepsilon = 1: P11=0.3655P_{11} = 0.3655, P12=0.1345P_{12} = 0.1345, cost 0.26890.2689, below the bound εlog⁡2=0.693\varepsilon\log 2 = 0.693 of Theorem 5. For ε=0.1\varepsilon = 0.1: cost 4.54×10−54.54 \times 10^{-5}.

    (d) The collapse, in numbers. Noise N(0,1)\mathcal N(0, 1), data ±2\pm 2, independent coupling.

    1. Given x1x_1, xt=(1−t)x0+tx1∼N(tx1,(1−t)2)x_t = (1 - t)x_0 + tx_1 \sim \mathcal N(tx_1, (1 - t)^2).
    2. Bayes' rule with equal prior weights: the posterior odds of x1=+2x_1 = +2 against −2-2 are exp⁡ ⁣(−(x−2t)2−(x+2t)22(1−t)2)=exp⁡ ⁣(4tx(1−t)2)\exp\!\big(-\frac{(x - 2t)^2 - (x + 2t)^2}{2(1 - t)^2}\big) = \exp\!\big(\frac{4tx}{(1 - t)^2}\big). So E[x1∣xt=x]=2tanh⁡(2tx/(1−t)2)\mathbb E[x_1 \mid x_t = x] = 2\tanh\big(2tx/(1 - t)^2\big).
    3. Since x1−x0=(x1−xt)/(1−t)x_1 - x_0 = (x_1 - x_t)/(1 - t), the marginal velocity is ut(x)=(2tanh⁡(2tx/(1−t)2)−x)/(1−t)u_t(x) = \big(2\tanh(2tx/(1 - t)^2) - x\big)/(1 - t).
    4. One Euler step: x0+u0(x0)=x0+(0−x0)=0x_0 + u_0(x_0) = x_0 + (0 - x_0) = 0 for every x0x_0.
    5. The exact flow from x0=0.5x_0 = 0.5 first moves toward 00 (down to about 0.4510.451 at t≈0.17t \approx 0.17), then turns and reaches +2+2. Since 1D flows keep the order of points, the rectified coupling is x1=2sign⁡(x0)x_1 = 2\operatorname{sign}(x_0): the OT coupling.
    6. Transport costs. Independent: E∣x1−x0∣2=Ex12+Ex02=4+1=5\mathbb E\lvert x_1 - x_0\rvert^2 = \mathbb E x_1^2 + \mathbb E x_0^2 = 4 + 1 = 5. OT: E∣2sign⁡(x0)−x0∣2=4−4 E∣x0∣+1=5−42/π≈1.808=W22\mathbb E\lvert 2\operatorname{sign}(x_0) - x_0\rvert^2 = 4 - 4\,\mathbb E\lvert x_0\rvert + 1 = 5 - 4\sqrt{2/\pi} \approx 1.808 = W_2^2. The difference 5−1.808=3.1925 - 1.808 = 3.192 is S+VS + V of the first rectification.
    Quick check

    In example (d), what is the transport cost E∣x1−x0∣2\mathbb E\lvert x_1 - x_0\rvert^2 of the OT coupling x1=2sign⁡(x0)x_1 = 2\operatorname{sign}(x_0)?

    5. In code #

    NumPy and SciPy check examples (a)–(c). The Hungarian algorithm in linear_sum_assignment solves the assignment problem exactly; logsumexp gives a stable LSE.

    import numpy as np
    from scipy.optimize import linear_sum_assignment
    from scipy.linalg import sqrtm
    from scipy.special import logsumexp
    
    # (a) 1D OT: sorting agrees with the exact assignment problem.
    x, y = np.array([0.0, 1.0, 3.0]), np.array([5.0, 2.0, 4.0])
    C = (x[:, None] - y[None, :]) ** 2                 # cost matrix |x_i - y_j|^2
    rows, cols = linear_sum_assignment(C)              # Hungarian algorithm: exact OT for equal weights
    print(C[rows, cols].mean(), cols)                  # 5.6667 [1 2 0]: pairs 0->2, 1->4, 3->5
    print(np.mean((np.sort(x) - np.sort(y)) ** 2))     # 5.6667: sort both and pair in order
    print(np.mean((x - y) ** 2))                       # 9.0: the pairing in the given order
    
    # (b) Gaussian W2 by the Bures formula.
    def bures_w2sq(m1, S1, m2, S2):
        R = sqrtm(S1)
        return np.sum((m1 - m2) ** 2) + np.trace(S1 + S2 - 2 * sqrtm(R @ S2 @ R)).real
    m1, S1 = np.zeros(2), np.eye(2)
    m2, S2 = np.array([1.0, 0.0]), np.array([[2.0, 1.0], [1.0, 2.0]])
    print(bures_w2sq(m1, S1, m2, S2), 5 - 2 * np.sqrt(3))   # 1.5359 1.5359
    
    # (c) Log-domain Sinkhorn on the 2 x 2 problem; closed form P12 = 1 / (2 (e^{1/eps} + 1)).
    def sinkhorn_log(a, b, C, eps, iters=2000):
        f, g = np.zeros(len(a)), np.zeros(len(b))
        for _ in range(iters):
            f = eps * np.log(a) - eps * logsumexp((g[None, :] - C) / eps, axis=1)
            g = eps * np.log(b) - eps * logsumexp((f[:, None] - C) / eps, axis=0)
        return np.exp((f[:, None] + g[None, :] - C) / eps)
    a = b = np.array([0.5, 0.5])
    C = np.array([[0.0, 1.0], [1.0, 0.0]])
    for eps in (1.0, 0.1):
        P = sinkhorn_log(a, b, C, eps)
        print(eps, P[0, 1], 1 / (2 * (np.exp(1 / eps) + 1)), (C * P).sum())
    # 1.0 0.13447 0.13447 0.26894    (exact OT cost is 0; the gap is below eps*log 2 = 0.693)
    # 0.1 2.2699e-05 2.2699e-05 4.5398e-05
    

    And example (d): the closed-form marginal velocity, one Euler step against an accurate ODE solve, Euler with a few steps, and the two transport costs by Monte Carlo:

    from scipy.integrate import solve_ivp
    
    def u(t, x):                                       # exact marginal velocity of example (d)
        return (2 * np.tanh(2 * t * x / (1 - t) ** 2) - x) / (1 - t)
    
    for x0 in (0.5, -0.1, 1.5):
        one_step = x0 + u(0.0, x0)                     # one Euler step from t = 0 to t = 1
        sol = solve_ivp(u, (0.0, 1 - 1e-6), [x0], method="Radau", rtol=1e-9, atol=1e-12)
        print(x0, one_step, round(sol.y[0, -1], 4))
    # 0.5 0.0 2.0 / -0.1 0.0 -2.0 / 1.5 0.0 2.0: one step gives 0; the exact flow ends at ±2
    
    z = np.random.default_rng(0).standard_normal(200_000)
    for N in (1, 2, 4, 8):                             # Euler with N steps from many noise samples
        xs = z.copy()
        for k in range(N):
            xs = xs + u(k / N, xs) / N
        print(N, np.mean(np.minimum(np.abs(xs - 2), np.abs(xs + 2))))
    # mean distance to the nearest data point: 2.0, 0.51, 0.011, 1.2e-05
    
    x1 = np.random.default_rng(1).choice([-2.0, 2.0], size=z.size)
    print(np.mean((x1 - z) ** 2), np.mean((2 * np.sign(z) - z) ** 2), 5 - 4 * np.sqrt(2 / np.pi))
    # about 5.0, about 1.807, 1.8085 (= W2^2)
    

    6. Where it shows up #

    • Generative models. Stable Diffusion 3 trains rectified-flow transformers (Esser et al., 2024). Meta's Movie Gen is trained with flow matching (2024).
    • Weather ensembles. ArchesWeatherGen (Couairon et al., 2024) uses flow matching to sample weather states around a deterministic forecast. Ensemble models pay per network call and per member, so the number of solver steps matters (lesson 16 compares model families).
    • Seismology. Wasserstein misfits for full-waveform inversion (Engquist and Froese, 2014; Métivier et al., 2016) compare seismograms as distributions of mass along time; they are more convex with respect to time shifts than the least-squares misfit, which reduces cycle skipping (lesson 04).
    • Evaluation. FID is the Bures W22W_2^2 between Gaussian fits of two sets of image features. The same formula compares an ensemble's mean and covariance with observations; by Gelbrich's bound it never overstates the true W2W_2.
    • Data assimilation. The ensemble transform particle filter (Reich, 2013) turns a weighted ensemble into an equally weighted one with an OT plan.

    7. Common mistakes #

    • Thinking the model learns x1−x0x_1 - x_0. It learns the conditional mean ut(x)u_t(x). When paths cross, the best CFM loss is V>0V > 0, and the learned paths are curved even though every conditional path is straight.
    • Mixing time conventions. Flow matching uses t=0t = 0 noise, t=1t = 1 data; score-based diffusion often uses the opposite. Converting flips the sign of the velocity.
    • W2W_2 versus W22W_2^2. The optimal cost for the squared distance is W22W_2^2, and so is the Bures formula. Take the square root before you call it a distance.
    • sqrtm on singular or nearly singular covariances. It can return NaN or complex values. Use eigh and clip tiny negative eigenvalues to 0.
    • Sinkhorn with e−C/εe^{-C/\varepsilon} for small ε\varepsilon. It underflows; use the log domain. And remember that ⟨C,Pε⟩\langle C, P_\varepsilon\rangle is above the exact OT cost (Theorem 5).
    • Minibatch OT done once, or reflow done many times. The pairing must be recomputed in every batch. Each reflow round fits a model to model output, so errors pile up.

    8. Check yourself #

    1. Compute W2W_2 between N(1,4)\mathcal N(1, 4) and N(−2,9)\mathcal N(-2, 9) in 1D (the second numbers are variances).
      AnswerW22=(1−(−2))2+(2−3)2=9+1=10W_2^2 = (1 - (-2))^2 + (2 - 3)^2 = 9 + 1 = 10, so W2=10≈3.162W_2 = \sqrt{10} \approx 3.162.
    2. For the independent coupling, why does the CFM loss of the best possible model stay above zero, and what is its value?
      AnswerLines meet, so the direction x1−x0x_1 - x_0 is random given the position xtx_t. The best model predicts its conditional mean ut(xt)u_t(x_t); the loss left over is V=∫01E∥x1−x0−ut(xt)∥2 dtV = \int_0^1 \mathbb E\lVert x_1 - x_0 - u_t(x_t)\rVert^2\,dt, the conditional variance.
    3. Costs CijC_{ij} up to 10 and ε=0.01\varepsilon = 0.01. What goes wrong in the scaling form of Sinkhorn, and what fixes it?
      Answere−Cij/εe^{-C_{ij}/\varepsilon} is as small as e−1000e^{-1000}, which is 00 in float64; KvKv can be 00 and a⊘(Kv)a \oslash (Kv) divides by zero. The log-domain updates with a stable LSE (subtract the maximum) fix it.
    4. Where does the proof of Theorem 3 use convexity, and why are there two uses?
      AnswerStep 1: Jensen over time, because Z1−Z0Z_1 - Z_0 is the time average of ut(Zt)u_t(Z_t). Step 3: conditional Jensen, because ut(Xt)u_t(X_t) is the conditional mean of X1−X0X_1 - X_0 given XtX_t.
    5. Source N(0,1)\mathcal N(0, 1), target N(3,4)\mathcal N(3, 4) in 1D. Give the OT map, the velocity field ut(x)u_t(x) of the straight OT flow, and say whether one Euler step is exact.
      AnswerT(x)=3+2xT(x) = 3 + 2x. On the path, xt=x0+t(3+x0)=3t+(1+t)x0x_t = x_0 + t(3 + x_0) = 3t + (1 + t)x_0, so x0=(x−3t)/(1+t)x_0 = (x - 3t)/(1 + t) and ut(x)=3+x0=(3+x)/(1+t)u_t(x) = 3 + x_0 = (3 + x)/(1 + t). One step: x0+u0(x0)=3+2x0=T(x0)x_0 + u_0(x_0) = 3 + 2x_0 = T(x_0), so it is exact.
    6. With source N(0,I)\mathcal N(0, I) and linear paths, express the marginal velocity through the score of ptp_t.
      Answerxt=tx1+(1−t)x0x_t = tx_1 + (1 - t)x_0, and Tweedie's formula ([lesson 13](/ml-for-science/13-score-matching-diffusion/)) for the Gaussian part (1−t)x0(1 - t)x_0 gives E[x0∣xt]=−(1−t)∇log⁡pt(xt)\mathbb E[x_0 \mid x_t] = -(1 - t)\nabla\log p_t(x_t). Then ut(x)=E[x1−x0∣xt=x]=(x−E[x0∣xt=x])/t=(x+(1−t)∇log⁡pt(x))/tu_t(x) = \mathbb E[x_1 - x_0 \mid x_t = x] = (x - \mathbb E[x_0 \mid x_t = x])/t = \big(x + (1 - t)\nabla\log p_t(x)\big)/t.
    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. Write the continuity equation for a density ptp_t moved by a velocity field utu_t.

    2. What is the conditional flow matching (CFM) loss for linear paths?

    3. State the marginalization trick.

    4. Why are the learned paths curved for an independent coupling?

    5. What does reflow do, and why does it help?

    6. What is the difference between the Monge and the Kantorovich problem?

    7. How do you solve OT between two equal-size samples on a line?

    8. State the Bures formula for W22W_2^2 between two Gaussians.

    9. Write the log-domain Sinkhorn update for ff.

    10. What does ε\varepsilon control in entropic OT?

    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 change (velocity ↔ score). They differ in the path, the loss weighting and the sampler. Flow matching regresses a velocity and needs no simulation during training.
    • "Why can rectified flow sample in few steps?" Its paths are straighter (Theorem 3, reflow); for S=0S = 0 one Euler step is exact. In practice reflow is followed by distillation.
    • "What is W2W_2 between two Gaussians? What is FID?" The Bures formula; FID is that formula applied to Gaussian fits of Inception features of real and generated images.
    • "Monge versus Kantorovich?" A map versus a coupling. A map may not exist; the coupling problem is a linear program that has a solution under mild conditions.
    • "How do you compute OT between 10510^5 points?" Not with the exact linear program (about cubic cost). Use Sinkhorn on a GPU (with its ε\varepsilon bias), minibatch OT, or sliced OT (1D sorting along random directions).

    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:

    1. 1D OT by sorting, checked against the exact assignment (linear_sum_assignment) and brute force.
    2. The Bures formula and the OT map between two Gaussians, checked by sampling.
    3. Log-domain Sinkhorn on a small problem; its cost approaches the exact OT cost as ε→0\varepsilon \to 0, within the bound of Theorem 5.
    4. The exact marginal velocity for a 1D mixture, and Euler sampling with few and many steps.
    5. Minibatch OT pairing: the transport cost and the swap test for batch sizes from 4 to 256.

    11. Watch and read #

    The marginalization trick and the CFM loss of Theorems 1 and 2, with the same time convention.
    Open on YouTube · the player loads from youtube-nocookie.com when you press play
    Flow matching explained by its first author; compare with Theorems 1 and 2.
    Open on YouTube · the player loads from youtube-nocookie.com when you press play
    A long tutorial on OT theory and algorithms; use it as a reference for the OT part of section 3.
    Open on YouTube · the player loads from youtube-nocookie.com when you press play
    Optimal transport as a tool in machine learning, by a co-author of Computational Optimal Transport.
    Open on YouTube · the player loads from youtube-nocookie.com when you press play