Modern Robotics and Physical AILesson 1.8 · Flow matching
Glossary RU
1.8 Part 1 · Imitation learning · deep dive

Flow matching and straight paths

The diffusion policy from lesson 1.5 turns noise into an action chunk in dozens of steps, and every step is a network pass. While the chunk is being computed, the robot stands still or follows the old plan, so every millisecond counts. Flow matching trains the network on straight paths from noise to data, and along a straight line you can take big steps: that's how π0 from lesson 1.6, GR00T N1 (NVIDIA, 2025; lesson 3.7) and SmolVLA (Hugging Face, 2025; lesson 3.5) build a chunk in 4–10 steps. We'll work out why the generation paths still come out curved and one step isn't enough, how retraining on the model's own paths (reflow) straightens them almost down to one step, and how many steps fit into a robot's budget.

≈ 45 minutes5 labs, a task and a quizmissions with a goal
PATHSSteer noise into the right blob and see where one step lands instead of two hundred
FIELDTrain a network that shows the direction of motion at every point, and find the moment the arrows flip from the center toward the blobs
STEPSCompare diffusion and flow on the same data and find how many steps each one needs
REFLOWStraighten the paths so that one step is enough, and find what you pay for it
ROBOTPick the number of steps for a chunk of 50 actions so Ada clears the kettle and stays within budget

Start the lesson ↓

1 Straight paths

Velocity along the line from noise to data

A diffusion model needs dozens of steps to turn noise into data. In lesson 1.5 every step became a network pass over the whole action chunk, and one chunk takes dozens of passes. All that time the robot stands still or follows the old plan.

The path from noise to data is curved. In lesson 1.4 the denoiser pointed toward the mean of the data under heavy noise and toward the nearest spiral under light noise, so a point first heads to the center and only then turns. The network knows the direction only at the current point, and a big step along it cuts the corner.

In lesson 1.4 the steps were cut down with the DDIM sampler: the same network steps without fresh noise and keeps the shape where DDPM is already pulling points to the center. But at a really small number of steps DDIM loses the shape too, so diffusion policies take dozens of steps per chunk.

The way out is to train the network on straight paths from noise to data: a straight line can be covered in one step, because the direction at the start points right at the end. That's how flow matching (Lipman et al., 2022) and the closely related rectified flow (Liu et al., 2022) work.

Take a random noise point x0x_0 and a random data point x1x_1 and connect them with a straight line. At time tt the point on the line is xt=(1−t) x0+t x1x_t = (1 - t)\,x_0 + t\,x_1; the velocity along it is constant and equals x1−x0x_1 - x_0. The network v(x,t)v(x, t) learns to predict that velocity from xtx_t and tt. It's ordinary regression: nothing has to be modeled step by step. Generation is taking noise and following the velocity field from t=0t = 0 to t=1t = 1 in a few Euler steps.

But lines from different pairs cross: through one point xtx_t run lines to different data points, and there are several right answers there. Will the generation paths be straight then, and will one step be enough? Let's check on two blobs of data. The velocity field here is computed by an exact formula, without a network, so everything we see follows from the method itself.

🔬 Lab 1
Under the hood: paths, the training objective and the exact field

Lipman et al. define the path conditionally: for each data point x1x_1, a Gaussian that coincides with the noise N(0,I)\mathcal N(0, I) at t=0t = 0 and shrinks around x1x_1 by t=1t = 1. In the variant the authors call the optimal transport path, the center and the width change linearly:

μt=t x1,σt=1−(1−σmin⁡) t,xt=(1−(1−σmin⁡) t) x0+t x1,LCFM=E ∥ vθ(xt,t)−(x1−(1−σmin⁡) x0)∥2.\begin{aligned} \mu_t &= t\,x_1, \qquad \sigma_t = 1 - (1 - \sigma_{\min})\,t,\\ x_t &= \bigl(1 - (1 - \sigma_{\min})\,t\bigr)\,x_0 + t\,x_1,\\ \mathcal L_{\text{CFM}} &= \mathbb E\,\bigl\|\,v_\theta(x_t, t)\\ &\qquad - \bigl(x_1 - (1 - \sigma_{\min})\,x_0\bigr)\bigr\|^2. \end{aligned}

As σmin⁡→0\sigma_{\min} \to 0 this is exactly the straight line from the text and the target x1−x0x_1 - x_0; Liu et al. use the same training target. The paper's main theorem: the gradients of this “conditional” objective coincide with the gradients of the objective where the true generation field stands in place of x1−x0x_1 - x_0. So it's enough to train the network on random pairs rather than know the field in advance.

What field an ideal network learns: the average of all velocities passing through a point, v∗(x,t)=E[x1−x0∣xt=x]v^*(x, t) = \mathbb E[x_1 - x_0 \mid x_t = x]. At t=0t = 0 the point xtx_t is the noise itself, and it says nothing about where to go. So v∗(x,0)=E[x1]−xv^*(x, 0) = \mathbb E[x_1] - x: the arrow points at the mean of the data.

In the lab the data is a mixture of two Gaussians, and the average is computed exactly. For a component with center mm and spread ss:

xt∼N(t m, (t2s2+(1−t)2) I),E[x1∣xt,m]=m+t s2t2s2+(1−t)2 (xt−t m).\begin{gathered} x_t \sim \mathcal N\bigl(t\,m,\ (t^2 s^2 + (1 - t)^2)\,I\bigr),\\ \mathbb E[x_1 \mid x_t, m] = m + \frac{t\,s^2}{t^2 s^2 + (1 - t)^2}\,(x_t - t\,m). \end{gathered}

The component weights are their likelihoods at the point xtx_t. The blobs are centered at (±1.2; 1.0), s=0.22s = 0.22. The probe path is 200 Euler steps.

The generation paths are curved, even though every training pair is a straight line. Through the points in the middle run lines to both blobs, and the field equals their average. So the point, just as in diffusion, first heads to the mean of the data and only then turns, and one step brings all the noise to the mean — into the void between the blobs. That's how regression in lesson 1.3 drove Ada into the kettle between the left and right detours. Here the field is computed by formula. What will a real network learn when it sees only random pairs?

Ada is the home humanoid robot the course's labs are built around. More about her in lesson 0.1.

🔬 Lab 2

Training the velocity field

What will a network learn when it sees only random pairs? For real data there's no formula for the field, and at every point the network runs into lines to different data points, that is, different right answers.

Let's train a small network right on the page and check two things: how low the loss drops, and where the field's arrows point at different moments t.

The data is harder than in lab 1: eight blobs on a ring, 4000 points. The network takes a point and a time and outputs a velocity. Every training step is 128 random “noise — data” pairs and random moments t. The arrows on the scene are what the network thinks the velocity is at each point at the selected moment.

Horizontal axis: training steps; vertical: mean squared velocity error.

Under the hood: the training loop and why the loss doesn't drop to zero
repeat 1500 times:
x1←x_1 \leftarrow 128 random data points, x0←x_0 \leftarrow 128 noise points N(0,I)\mathcal N(0, I)
t←t \leftarrow 128 numbers from U[0,1]U[0, 1]
xt=(1−t) x0+t x1x_t = (1 - t)\,x_0 + t\,x_1
loss = mean of ∥vθ(xt,t)−(x1−x0)∥2\bigl\|v_\theta(x_t, t) - (x_1 - x_0)\bigr\|^2
Adam step
  • Network. Input: the point (x,y)(x, y), 32 Fourier features of the point (cosines and sines of projections onto 16 random directions) and 5 time features: t, sin⁡πt, cos⁡πt, sin⁡2πt, cos⁡2πtt,\ \sin \pi t,\ \cos \pi t,\ \sin 2\pi t,\ \cos 2\pi t. Two hidden layers of 48 neurons with SiLU, output: the velocity (vx,vy)(v_x, v_y). Adam, learning rate 0.005, decaying toward the end of training. Without Fourier features such a small network draws a blurry ring instead of eight blobs.
  • Why the loss doesn't go to zero. Through one point xtx_t run lines to different blobs, and the target x1−x0x_1 - x_0 is random for it. The best the network can do is predict the mean, and the spread around the mean remains as loss. For this data the field can be computed exactly, as in lab 1: even with it the mean loss is 1.87. The dashed line on the plot is that bound.
  • What the scene shows. The arrows are the network's field on a 15 × 15 grid. Gray ones pull toward the center, orange ones push away from it. The cloud is 300 noise points the network carried along its field up to time tt, 100 Euler steps for the full path.

The network learned a field close to the ideal one: at every point, the average velocity of all the lines through it. The loss stopped just above the bound below which no network can go. Almost all of it is the irreducible spread of the targets, so the training curve is a poor guide to how well the model draws. Until about halfway along the path the field pulls the noise toward the center of the ring and only then flips it toward the blobs, so the point's path is curved again. How many Euler steps does it take to follow such a path, and is it fewer than diffusion needs?

🔬 Lab 3 · central

Diffusion and flow on the same data

How many steps does a flow model need, and is it fewer than diffusion? Its paths are curved, so the win isn't obvious.

Let's put the diffusion from lesson 1.4 alongside and compare on equal terms. For each model we'll find the smallest number of steps at which it holds the shape of the ring.

Same data, same network, same training budget — 1500 steps. The difference is in two things: the diffusion network predicts noise and generates with the DDIM sampler on the DDPM schedule; the flow network predicts velocity and generates with Euler's method along the straight line. Both start from the same 600 noise points.

Diffusion · DDIMthe network predicts noise
Flow matching · Eulerthe network predicts velocity

Horizontal axis: number of generation steps (log scale); vertical: share of points in blobs. A dot appears for every number of steps you try. The green dashed line is the threshold: the shape holds if at least 72% of the points are in blobs and all eight blobs are present; for the real data about 96% of the points are in blobs.

Under the hood: a DDIM step is an Euler step too

A DDIM step (η=0\eta = 0) first estimates the clean point from the predicted noise, then mixes it with the same noise in the proportion of the next moment:

x^0=xt−1−αˉt ε^αˉt,xs=αˉs x^0+1−αˉs ε^.\begin{gathered} \hat x_0 = \frac{x_t - \sqrt{1 - \bar\alpha_t}\,\hat\varepsilon}{\sqrt{\bar\alpha_t}},\\ x_s = \sqrt{\bar\alpha_s}\,\hat x_0 + \sqrt{1 - \bar\alpha_s}\,\hat\varepsilon. \end{gathered}

An Euler step along the straight path works the same way. From the velocity vv come a data estimate x^1=xt+(1−t) v\hat x_1 = x_t + (1 - t)\,v and a noise estimate ε^=xt−t v\hat\varepsilon = x_t - t\,v, and

xs=(1−s) ε^+s x^1=xt+(s−t) v.x_s = (1 - s)\,\hat\varepsilon + s\,\hat x_1 = x_t + (s - t)\,v.

So DDIM and Euler are the same sampler if the schedule is the same. Gao et al. in the survey “Diffusion Meets Flow Matching” put it this way: with Gaussian noise, flow matching and diffusion are equivalent, and the DDIM sampler coincides with the Euler sampler.

Where the difference in the lab comes from, then. First, the schedule: in DDPM almost the whole first half of the path is heavy noise, and a uniform grid wastes steps there. Second, the training target: at the first step DDIM gets its data estimate by dividing by αˉ1000≈0.0064\sqrt{\bar\alpha_{1000}} \approx 0.0064, and the network's error in the predicted noise grows about 160-fold. That's why at one step the diffusion points scatter. A network that predicts velocity has no such division.

Lipman et al. compared optimal transport paths with diffusion paths in one setting: the former give faster training and generation, and on ImageNet 32 × 32 they need about 60% of the field evaluations to reach the same error. That doesn't mean flow is always better: Gao et al. show that for wide distributions a different schedule can give straighter paths. The result depends on the schedule, the target and the sampler, not on the name of the method.

How quality is measured. A point is “in a blob” if it's within 0.2 of the center of one of the eight blobs (2.5 spreads). A blob is “present” if at least a quarter of its share of points landed in it. Both networks: 48 × 48 neurons, 1500 steps of 128 examples, the same seed. For the real data about 96% of the points are in blobs.

Flow holds the shape from 8 steps, diffusion from 16. And yet flow and diffusion are one family: a DDIM step is the same Euler step, and the difference comes from the noise schedule and what the network predicts. One step still doesn't work: the flow model gathers all the noise into one blob at the center of the ring, because the first step leads to the mean of the data. Can the generation paths themselves be straightened so that one step is enough?

🔬 Lab 4

Straightening: reflow

Can the generation paths be straightened so that one step is enough? Right now one step gathers all the noise at the center of the ring.

The paths are curved because the training lines cross: through one point run lines to different blobs, and the network learns their average.

So far the turn was taken in small steps: the flow model in lab 3 needed 8, and each one is a network pass.

So the network has to be trained on pairs whose lines don't cross. Liu et al. suggested where to get them.

Run the already trained model from noise z0z_0 and record where it brought it — z1z_1. The model's paths are solutions of a differential equation: at every point at every moment the field gives one direction, so two paths cannot cross. Hence the straight lines between z0z_0 and z1z_1 rarely cross either. Train the same network again, on the pairs (z0,z1)(z_0, z_1) instead of random ones. That is reflow.

Let's check how many crossings remain, whether one step is enough after that, and what it costs.

Random pairshow ordinary flow matching trains
Reflow pairsnoise and where the model took it
Steps for pairs
Under the hood: reflow, distillation and one-step models
1. Train a flow on random pairs (x0,x1)(x_0, x_1) → model 1.
2. z0∼N(0,I)z_0 \sim \mathcal N(0, I), z1z_1 — the end of model 1's path from z0z_0 over many steps → pairs.
3. Train the same objective on the pairs (z0,z1)(z_0, z_1) → model 2.
4. Optionally repeat, or distill into one step.
  • What the authors proved. The output distribution of reflow is the same as the original model's, and the transport cost doesn't grow. The more repetitions, the straighter the paths can get, but the authors advise against many repetitions: error accumulates. They fine-tune the new model from the previous one's weights, as we do.
  • The cost. The pairs have to be generated by model 1 over many steps, and the network trained once more. Model 1's errors pass into the pairs, so at a large number of steps the straightened model draws worse than the original. On CIFAR-10, for Liu et al., one Euler step gave FID 378 for the original model and 12.21 after reflow, while an exact solver gave 2.58 and 3.36.
  • In the lab. 2000 pairs, a separate noise sample. Model 2 is a copy of model 1, fine-tuned for 1000 steps of 128 pairs at learning rate 0.002. Crossings are counted for 100 pairs, that is, among 4950 pairs of segments.
  • Other routes to one step. Distillation trains the network to output the end of the path directly: that's how InstaFlow got a one-step Stable Diffusion, at a cost of 199 A100 GPU-days. Consistency models map any point of the path to its end: FID 3.55 in one step on CIFAR-10. MeanFlow (NeurIPS 2025) learns the average velocity over an interval and gives FID 3.43 in one step on ImageNet 256 × 256.

Reflow pairs barely cross, and the straightened model in one step puts about two thirds of the points into blobs and finds all eight. The price is one more training run, pairs that the original model builds over many steps, and quality at a large number of steps: the original model's errors pass into the pairs. All of this we checked on points. How many steps does a robot's action chunk need, and how many milliseconds do they cost?

2 An action chunk for the robot

How π0 builds an action chunk

How many steps does an action chunk need, and what do they cost? The robot has two requirements at once: the chunk must go around the obstacle and be computed quickly, because while it's being computed the robot stands still or follows the old plan.

Let's look at how it's done in π0 — the large policy from lesson 1.6, which we'll take apart fully in lesson 3.6. Next to a 3B-parameter VLM (a model that reads images and text) runs a separate action expert with 300M. It generates a chunk of 50 actions: it starts from noise of shape 50 × action dimension and in 10 Euler steps turns it into motion. Every step is a pass of the expert over the 50 action tokens. The VLM processes the images and text once per chunk and caches the keys and values, and the expert reads them at every step — that's the block mask of π0 from lesson 1.6.

On an RTX 4090 with three cameras, inference takes 73 ms: 14 ms for the image encoders, 32 ms for the pass over the observation and 27 ms for all 10 flow steps. If the model runs off the robot, 13 ms of network time is added. In GR00T N1 the action head is a DiT transformer, and 4 steps are enough for it: a chunk of 16 actions in 63.9 ms on an L40. π0.7 (a late version of π0, 2026; lesson 3.8) generates a chunk of 50 actions in 5 steps.

Let's check on Ada how many steps the chunk needs to clear the kettle, and how many steps fit into the time budget.

🔬 Lab 5

Top view of the table: Ada's gripper (the dot on the left) moves left to right, 60 cm in 1 s — a chunk of 50 actions ends at the “in 1 s” label. In the middle is the kettle; the dashed circle is a 2 cm clearance around it. Gray lines are 40 demonstrations: half go around the kettle above, half below. Orange ones are 20 chunks from different noise; the small dots are the 50 actions of one chunk, one per 20 ms tick.

The bar is what the inference time of one chunk is made of, ms. Ada executes 25 actions (0.5 s) and stands still while the next chunk is computed — hence the share of time the robot is idle.

⏱

Time convention in this course: t=0t = 0 is noise, t=1t = 1 is data, velocity = data − noise. That's how Lipman and Liu write it, and that's how the time τ\tau is introduced in the π0 and GR00T N1 papers. In openpi, the open-source code of π0, it's the other way round: xt=t⋅noise+(1−t)⋅actionsx_t = t\cdot\text{noise} + (1 - t)\cdot\text{actions}, the target is noise − actions, and generation runs from t=1t = 1 to 0 with step −0.1-0.1. The authors say outright in a comment that this is the opposite of the paper. The π0 and SmolVLA implementations in Hugging Face's LeRobot library work the same way. When reading code, check where the noise is.

Under the hood: the π0 formulas and what's behind the 73 ms
Aτ=τA+(1−τ) ε,ε∼N(0,I),target: A−ε,training: s−τs∼Beta(1.5; 1),s=0.999,inference: Aτ+δ=Aτ+δ vθ(Aτ,o),δ=0.1.\begin{gathered} A^\tau = \tau A + (1 - \tau)\,\varepsilon, \quad \varepsilon \sim \mathcal N(0, I),\\ \text{target: } A - \varepsilon,\\ \text{training: } \tfrac{s - \tau}{s} \sim \mathrm{Beta}(1.5;\ 1), \quad s = 0.999,\\ \text{inference: } A^{\tau + \delta} = A^\tau + \delta\, v_\theta(A^\tau, o),\\ \delta = 0.1. \end{gathered}
  • A sign error. In the 2024 versions of the paper the target is written as ε−A\varepsilon - A. With this path and a step of +δ v+\delta\,v that would lead from data to noise. In the January 2026 version the sign is corrected to A−εA - \varepsilon. In the code the sign is right in its own convention.
  • Choosing τ. The Beta distribution gives more training examples with heavy noise, that is, small τ\tau. Moments τ>0.999\tau > 0.999 aren't needed as long as the integration step is larger than 0.001.
  • Why 10 steps are cheaper than the images. The expert is 10 times smaller than the VLM and works only with the 50 action tokens, while the observation is computed once and sits in the cache. That's why 10 steps cost 27 ms, and one pass over the cameras and text costs 46 ms.
  • In the lab. The chunk is 50 lateral offsets of the gripper across the table, one per 20 ms tick; the gripper moves left to right, 60 cm in 1 s. Instead of a trained head, here we use the exact field for 40 demonstrations: 20 go around the kettle above, 20 below. That shows what the Euler steps themselves do, without training errors; a trained network would add its own errors on top. The latency in the calculator is the π0 breakdown: 14 + 32 + 2.7 ms per step (27 ms / 10) + 13 ms for the network. That every step costs the same is our simplification. Idle is the share of time the robot stands still: 25 actions executed (0.5 s), waiting for inference.
  • One-step heads. FlowPolicy and MP1 generate actions in one step: 19.9 and 6.8 ms. In a single-author tech report (2026), a one-step head for GR00T sped up inference from 45 to 5 ms, but success dropped noticeably: on the long tasks of the LIBERO benchmark, from 74.5 to 26%.

In one step every chunk drives into the kettle: the first step from noise leads to the mean of the demonstrations. On the exact field Ada needs 4 steps, and on a server both the detour and the budget hold from 4 to 10 steps. The steps themselves are cheap: most of the latency comes from the pass over the observation. How many steps do real policies take?

🧩 Task

Who takes how many steps

Sort the models by the number of generation steps at inference. Most of the models on the cards are covered in later lessons; you don't need to know them in advance: everything you need is stated here. π0, π0.7 and GR00T N1 were described above. π0.5 (lesson 3.8) and SmolVLA build a chunk the same way as π0. RDT-1B is a bimanual diffusion model from 2025 whose DPM-Solver++ solver cuts 100 steps to 5. UMI (lesson 4.2) runs on the Diffusion Policy from lesson 1.5. Octo (an open policy, 2024; lesson 3.5) and ALOHA Unleashed (lesson 1.7) are also diffusion heads, on DDPM and DDIM, without distillation. FlowPolicy and MP1 are trained with consistency and MeanFlow objectives: the network outputs the end of the path directly. Drag a card, or click it and then a bin.

3 Check yourself

Eight common misconceptions

4 Takeaways

Lesson takeaways

  1. Diffusion needs dozens of steps per chunk, and the robot waits for every network pass. Flow matching learns a velocity field by regression on straight lines between random noise and a random data point. Generation is a few Euler steps from noise to data.
  2. The training lines cross, the network learns their average, so the generation paths are curved. One step from noise lands at the mean of the data.
  3. With Gaussian noise, flow matching and diffusion are one family: DDIM is an Euler step with a different schedule. The difference in the number of steps comes from the schedule and what the network predicts.
  4. Reflow trains the model on its own “noise → result” pairs. The paths straighten, and one or two steps are almost enough. The price is one more training run and a little quality.
  5. Robot heads on flow matching take 4–10 steps: π0, π0.5 and SmolVLA — 10, GR00T N1 — 4, π0.7 — 5. The expert's steps are cheap; most of the latency comes from the pass over the observation.
  6. Time conventions differ: in this course t=0t = 0 is noise; in the openpi code it's the other way round.

Open questions

Why doesn't π0 generate a chunk in one step, if reflow and distillation allow it?

One step gives the mean if the paths are curved, and straightening or distillation costs extra training and usually a little quality. Meanwhile the expert's 10 steps cost 27 ms out of 73: the main part of the latency is the pass over the cameras and text, and one step instead of ten would save about a third of the time. For dexterous tasks the loss of precision costs more than those milliseconds. One-step heads are being tested, but in the GR00T tech report such a head lost noticeably in success.

The demonstrations go around the kettle sometimes left, sometimes right. What does each Euler step do to the chunk, and why is the first step the most dangerous?

At the start the noise says nothing yet about the detour side, and the field pulls the chunk toward the mean of the demonstrations — straight into the kettle. If there's one step, the chunk stays there. If there are several, after the first the chunk is still noisy, and the next steps already “see” which side it's closer to and carry it there. That's why quality rises fast from one step to three or four, and then barely changes.

Paper guide

Y. Lipman, R. Chen, H. Ben-Hamu, M. Nickel, M. Le, “Flow Matching for Generative Modeling”, ICLR 2023.

X. Liu, C. Gong, Q. Liu, “Flow Straight and Fast: Learning to Generate and Transfer Data with Rectified Flow”, ICLR 2023 — reflow, the theorems on non-crossing paths and one-step generation.

Resources

✅

Check yourself on all of Part 1. 15 questions from lessons 1.1–1.8, shuffled, plus an exercise on a live scene: that shows what has stuck. At the end, a score per lesson and the sections worth revisiting.

Part 1 check →

➡️

Next: Part 2. A flow matching head builds a chunk in 4–10 steps and fits into the robot's budget. But the policy itself hasn't changed: it knows one task, needs fifty-odd demonstrations per skill, and can't follow an instruction given in words. How can a robot work out what to do and where? That's Part 2: scene geometry and language in Transporter and CLIPort, PerAct and planners on large language models. The flow matching action head returns in Part 3: in the π0 lesson it sits next to the VLM, and in the GR00T lesson behind the slow System 2.

Lesson 2.1 “Transporter and CLIPort” →

Was the lesson clear?
Found a mistake or inaccuracy? Report it on GitHub
Found this lesson useful? Say thanks — that is how the author knows the course is being read.