Skip to the walkthrough
FixTheRobot Home / VLA / Paper guides / π0

VLA · Paper guide

π0: A Vision-Language-Action Flow Model for General Robot Control

A generalist robot policy built on a vision-language model, explained through the questions an engineer would ask.

  • Physical Intelligence (Black et al.)
  • arXiv:2410.24164 (v1)
  • Overview: about 4 minutes
  • Full guide: about 45 minutes

This is a guide to the π0 paper, not a sentence-by-sentence paraphrase. Part A is a 4-minute overview. Parts B to D explain the architecture, the training recipe and the experiments one idea at a time. Equations and code are folded away in Part E, and Part F is a critical review of the paper’s own numbers and claims. If you read the GR00T N1 guide first, π0 is the model it borrows its action-generation recipe from.

Start with the overview Jump to the critical review

How to use this page

  1. In a hurry: read Part A (about 4 minutes).
  2. To understand the model: add Parts B to D. Each idea follows the same pattern: intuition, the problem it solves, how it works, an example, then technical details and where to find them in the paper.
  3. To check or rebuild it: open the folded sections (equations, token layout, sizes, timings, runnable examples) and read Part F.

Open the paper (arXiv:2410.24164) beside this page; section, figure and equation references are to it. We paraphrase and never reproduce its text. Statements are labelled so you can tell them apart: Reported by the paper, Our calculation from the paper’s numbers, Our interpretation, and Approximate, read from a chart because this paper shows most results as charts without tables. Runnable examples are marked Toy illustration when they are our own code and never present results from the paper.

Part A · about 4 minutes

Start here: the paper at a glance

The problem

Robots that could fold laundry, clear a table or assemble a box would be useful, but most robot policies are trained for one narrow job on one robot. Language and image models became versatile by learning from huge, varied collections of data. The authors argue that robots need the same recipe: learn broadly first, then specialise. Doing that for dexterous work (careful, fine hand motions) raises three questions: how to use very diverse data, what model can represent subtle motion, and what training recipe works.

The main contribution

  1. A model, π0 (“pi-zero”). It starts from a pretrained vision-language model (a model that reads images and text) and adds a small “action expert” that outputs smooth, continuous motions. This makes it a vision-language-action (VLA) model: images and an instruction in, robot actions out.[1]
  2. A training recipe. First pre-train on a very large, mixed collection of robot data, then post-train on a smaller, carefully made dataset for the task you care about.[1]
  3. A large set of real-robot experiments: tasks done with no fine-tuning, language following, learning new tasks, and long multi-step tasks such as laundry folding and table bussing.

How the model works, in one paragraph

Camera images, a sentence such as “fold the shirt” and the robot’s joint readings are turned into tokens (small vectors a transformer reads). The big pretrained part handles the image and language tokens. The small action expert handles the joint readings and a set of 50 noisy action tokens, and the two parts look at each other through attention. The action expert is run ten times, each time nudging the noisy actions toward clean ones, a method called flow matching. The result is a 50-step chunk of motor commands, of which the robot carries out the first 16 to 25 before asking the model again.[1]

What it learns from

The authors’ own data covers 7 robot configurations (single arms, two-armed robots, mobile robots) and 68 tasks, about 903 million timesteps, plus open-source datasets (Open X-Embodiment, Bridge v2, DROID) that make up 9.1% of the training mixture. The paper describes this as over 10,000 hours of robot data. After pre-training, tasks are fine-tuned with anything from about 1 to 100+ hours of curated data.

What the paper reports

Scores are fractions of the maximum score on each task, averaged over 10 episodes, with partial credit. Values below are read by us from the paper’s bar charts, so treat them as approximate.

Headline results, approximate. Approximate, read from a chart
Testπ0Comparison
No fine-tuning (zero-shot), five tasks (Figure 7)about 0.75 to 1.0 per taskOpenVLA and Octo: near 0 on most; best baseline about 0.35
Following language commands (Figure 9)about 0.70 to 0.95 following rateπ0-small (no pretrained vision-language model): about 0.3 to 0.7
Fine-tuned on new tasks, average over five tasks (Figure 11)about 0.57 / 0.87 / 0.87 with 1 / 5 / 10 hoursDiffusion Policy about 0.2 / 0.3 / 0.4
Long multi-stage tasks after fine-tuning (Figure 13)above 0.5 on all seventrained from scratch: lower on most

What to keep in mind

  • The chart readings are approximate: the paper gives figures, not tables of numbers. There are no confidence intervals and each task uses about 10 episodes.
  • The paper’s own comparison with its “small” model mixes model size and pre-trained initialisation, which the authors say they cannot separate.
  • Pre-training did not help every task: on a few, a model trained from scratch is about as good (Part F).
  • The authors list open problems themselves: what data to include, which tasks work reliably, and whether the recipe carries over to very different domains.

If you read nothing else: π0 shows that a pretrained vision-language model plus a small flow-matching action expert, pre-trained on a large mix of robot data and then fine-tuned on a little curated data, can do long, dexterous real-robot tasks. It does not isolate which ingredient matters most.

Check your understanding: Why does the recipe have both a pre-training and a post-training stage?

Diverse but messy pre-training data teaches the model many situations and how to recover from mistakes; the small curated post-training set teaches it to do the target task fluently and efficiently. Training on only the curated data gives a brittle model that rarely sees recoveries; using only the pre-trained model does not give the fluent strategy.

Part B

Understand the architecture

Follow one decision through the model: a bimanual robot (two arms) is told “fold the shirt”. Plain words first, technical names second; equations wait until Part E.

π0 data flow Camera images and a language command go to the large pretrained vision-language backbone. The robot state and a chunk of noisy actions go to a small action expert. The two sets of weights sit in one transformer and interact through attention. The action expert is run ten times, each time producing a direction that cleans the noisy actions, giving a chunk of 50 actions that the robot carries out. Camera images2 or 3 per robot Language command“fold the shirt” Robot statejoint angles One transformer with two sets of weights Vision-language partPaliGemma, about 3 billionreads images + languagepretrained on web data Action expertabout 300 million, newreads state + noisy actions+ the denoising step they look at each other through attention Repeat 10 timeseach pass: noisy actions in, direction toward clean actions out Action chunk50 consecutive actions Robot carries out the first 16 or 25then the model runs again
The data flow. Blue is the pretrained vision-language part, orange the action expert, dashed grey the grouping and the loop. Redrawn by us from the paper’s Figure 3 and Appendix B.
  1. Inputs
  2. Vision-language backbone
  3. Action expert
  4. Flow matching
  5. Action chunks

1. What goes in: images, a command, the robot’s own state

Intuition
The robot looks at the table, hears what it is asked to do, and feels where its arms are.
How it works
The observation has three parts: two or three camera images (typically wrist and base cameras), the language command, and a vector of joint angles (the robot’s proprioceptive state). Image encoders turn the images into tokens in the same space as the language tokens, and a linear layer (one matrix multiplication) turns the state into one more token. Here “token” just means one slot in the sequence the transformer reads, whether it stands for a word, an image patch or a robot action.
Example
Illustration, not from the paper A two-armed robot has a camera on each wrist and one on its base. The command is “fold the shirt”. The joint vector lists the angles of both arms and the open or closed state of both grippers.
Technical details
The paper writes the observation as image(s), language tokens and state. Different robots have different numbers of cameras and joints; how that is handled is in Part C.
Evidence in the paper
§IV · Appendix B “Additional inputs and outputs” · Figure 3
Check your understanding: Why does the state become a token at all?

So that the transformer can attend to it like everything else: the robot’s own joint readings sit in the same sequence as the image and language tokens and can influence every action token.

2. The vision-language backbone (PaliGemma)

Intuition
This is the part that already “knows the world” from the internet: what a shirt is, what “fold” means, how to find the object you mean.
The problem it solves
Robot data alone is far too small to teach general knowledge about objects and language.
How it works
The authors start from PaliGemma, an open vision-language model (VLM) of about 3 billion parameters: an image encoder (SigLIP, about 400M) and a language model (Gemma, about 2.6B).[2] It reads the image and language tokens exactly as it was trained to, and its weights are then trained further on robot data.
Example
Illustration, not from the paper For “fold the shirt”, this part already links the word “shirt” to the cloth in the pictures; robot training adds how to move.
Why the authors chose it
It lets π0 inherit general knowledge and language following. PaliGemma was chosen for convenience and its comparatively small size, which helps real-time control; the authors say the framework works with any pretrained VLM.
Technical details
Late fusion means the image encoders and the language model are separate pieces whose outputs are joined in one token sequence.
Run the example: do the parameter sizes add up?
Our calculation

What each part does

  1. Type in the sizes printed in Figure 3 and Section IV.
  2. Add SigLIP and Gemma, then the VLM and the action expert.
  3. Work out what share of the model each part is.
# Sizes printed in the paper (Figure 3 and Section IV), in parameters.
siglip = 400e6               # image encoder (SigLIP)
gemma = 2.6e9                # language model (Gemma)
vlm_total = 3.0e9            # "PaliGemma ... 3 billion parameter VLM"
action_expert = 300e6        # the added action expert
model_total = 3.3e9          # total stated in Section IV

print("SigLIP + Gemma =", round((siglip + gemma) / 1e9, 2), "billion (paper says about 3 billion)")
print("VLM + action expert =", round((vlm_total + action_expert) / 1e9, 2), "billion (paper says 3.3 billion)")
print("share of the model that is the action expert:", round(100 * action_expert / model_total, 1), "%")
print("share of the model that is the VLM backbone: ", round(100 * vlm_total / model_total, 1), "%")

Output:

SigLIP + Gemma = 3.0 billion (paper says about 3 billion)
VLM + action expert = 3.3 billion (paper says 3.3 billion)
share of the model that is the action expert: 9.1 %
share of the model that is the VLM backbone:  90.9 %
Evidence in the paper
§III · §IV · Figure 3
Check your understanding: Why does a small VLM help real-time control?

The model has to be run many times per second on the robot’s computer. A smaller backbone means fewer calculations per run, so the actions arrive faster.

3. The action expert: a second set of weights for robot-specific tokens

Intuition
Two specialists share one workspace. The big one reads and understands the scene. The small one writes the motion and may look at everything the big one has read, but the big one is not disturbed by robot-specific details.
The problem it solves
The pretrained model has never seen robot states or actions. Mixing them into its own weights risks disturbing what it already knows.
How it works
π0 is a single transformer with two sets of weights (called experts). Image and language tokens are routed to the large backbone; the state token and the noisy action tokens are routed to the small action expert. The two sets of weights interact only through the transformer’s attention layers. A blockwise attention mask controls who can look at whom: the image and language block sees only itself, the state sees that block and itself, and the action tokens see everything.
Example
Illustration, not from the paper The action tokens for “fold the shirt” can read the shirt tokens produced by the backbone; the backbone’s own tokens never read the half-finished actions.
Why the authors chose it
The authors report that using separate weights for the robotics-specific tokens improved performance, and describe it as a mixture of experts with two elements. The paper gives no numbers for this comparison. The image and language block is kept from seeing the new inputs to limit distribution shift from the backbone’s pre-training.[1]
Technical details
The action expert is initialised from scratch and is smaller: width 1,024 and MLP (multi-layer perceptron) size 4,096 against 2,048 and 16,384 for the backbone, about 300 million parameters in total. The mask is built from three blocks (state gets its own block so its keys and values can be cached while sampling). GR00T N1 connects its two modules differently (cross-attention instead of shared attention); see the lesson 6.3 and the GR00T N1 guide. Details in Part E.
Evidence in the paper
§IV · Appendix B “Attention mask”, “Action expert” · Figure 3
Check your understanding: Why can the action tokens see the image tokens but not the other way round?

The image and language block is meant to behave as it did in pre-training, so it is not allowed to see the new robot inputs. The action tokens are the new part and need the whole scene.

4. Generating actions with flow matching

Intuition
Start with a scribble of random actions and make ten small corrections until it becomes the movement you want.
The problem it solves
Dexterous tasks need precise, smooth, high-frequency actions, and the same scene can be handled in more than one valid way. Earlier VLAs write actions as text-like tokens one at a time, which the authors report is a major challenge for dexterous tasks.
How it works
Each of the 50 actions in the chunk becomes one noisy action token. The action expert reads all of them together (bidirectional attention among action tokens), plus the state and the scene, and outputs a direction that moves the noisy actions toward clean ones. This is repeated for 10 steps, starting from pure random noise.
Example
Illustration, not from the paper Ten passes turn random wiggles into a smooth sequence of arm and gripper movements for the first stage of folding.
Why the authors chose it
Flow matching, a variant of diffusion, gives precision and the ability to represent several valid ways of acting. Related work says this lets π0 handle action chunks at up to 50 Hz, which is hard for prior autoregressive VLAs.[3]
Technical details
Time is a number τ from 0 (pure noise) to 1 (clean actions); an MLP combines each noisy action with τ. The scene tokens are computed once and their keys and values are cached; only the action tokens are recomputed at each of the 10 passes. Equations and a runnable check are in Part E. See lesson 4.7 and the GR00T N1 guide, which uses the same training objective.
Evidence in the paper
§IV · Equation for the loss and the Euler update · Appendix B and D
Check your understanding: Why does caching help with ten passes?

The scene and state tokens do not change between passes, so their keys and values can be stored. Only the 50 action tokens need to be recomputed each time. In our estimate from Table I this is about 5 times faster than recomputing everything.

5. Action chunks and how they are executed

Intuition
The robot plans a short stretch of movement (up to one or two and a half seconds), carries out part of it without looking, and then plans again.
The problem it solves
Re-deciding every single step is slow and jittery; planning a stretch ahead gives smooth motion.
How it works
The model predicts a chunk of H = 50 future actions. The robot does not use temporal ensembling (blending overlapping chunks): the authors tried it early and found that it hurt performance. Instead it executes the chunk open-loop (without re-observing): on the 20 Hz robots it runs the model again after 16 actions (0.8 s), on the 50 Hz robots after 25 actions (0.5 s).
Example
Illustration, not from the paper At 50 Hz, a chunk of 50 actions covers one second. The robot performs the first half-second, then the camera frames are read again and a new chunk is planned.
Why the authors chose it
Chunking, as in ACT (Action Chunking with Transformers), allows fluent motion and high control rates, up to 50 Hz in the paper.[4] See lesson 4.4.
Technical details
On an RTX 4090 the whole step takes 73 ms on the robot’s own computer or 86 ms with the model on another machine over WiFi (Table I), so the model is busy a small part of each 0.5 to 0.8 s window.
Run the example: inference time, caching and how often the model runs
Our calculation

What each part does

  1. Add the parts of Table I and check the totals.
  2. Estimate the cost if the scene tokens were not cached (our own assumption, stated in the code).
  3. Work out how often the model must run and what a 50-action chunk covers at 20 Hz and 50 Hz.
# Inference time on an RTX 4090 (Table I of the paper), in milliseconds.
image_encoders = 14
observation_pass = 32          # one forward pass over the image, text and state tokens
action_pass_10_steps = 27      # ten flow-matching steps over the action tokens
network = 13                   # only when the model runs off-board over WiFi

on_board = image_encoders + observation_pass + action_pass_10_steps
print("on-board total:", on_board, "ms (Table I says 73)")
print("off-board total:", on_board + network, "ms (Table I says 86)")

per_step = action_pass_10_steps / 10
print("one flow-matching step costs about", per_step, "ms, because the observation tokens are cached")

# What if nothing were cached: every step would have to redo the observation pass too.
# (Our own estimate, assuming a step then costs the observation pass plus the action pass.)
no_cache = image_encoders + 10 * (observation_pass + per_step)
print("estimate without caching:", round(no_cache), "ms, about", round(no_cache / on_board, 1), "times slower")

# How often does the model have to run? Section D of the appendix.
for robot, hz, run_every_actions in (("20 Hz UR5e and Franka", 20, 16), ("50 Hz other robots", 50, 25)):
    seconds = run_every_actions / hz
    print(f"{robot}: a new chunk every {seconds:.2f} s -> the model is busy {100 * on_board / 1000 / seconds:.0f}% of the time (on-board)")
H = 50
for hz in (20, 50):
    print(f"a chunk of H = {H} actions covers {H / hz:.1f} s at {hz} Hz")

Output:

on-board total: 73 ms (Table I says 73)
off-board total: 86 ms (Table I says 86)
one flow-matching step costs about 2.7 ms, because the observation tokens are cached
estimate without caching: 361 ms, about 4.9 times slower
20 Hz UR5e and Franka: a new chunk every 0.80 s -> the model is busy 9% of the time (on-board)
50 Hz other robots: a new chunk every 0.50 s -> the model is busy 15% of the time (on-board)
a chunk of H = 50 actions covers 2.5 s at 20 Hz
a chunk of H = 50 actions covers 1.0 s at 50 Hz

Arithmetic on the paper’s numbers; the no-cache figure is our estimate, not a measurement.

Evidence in the paper
Appendix D and Table I · §I (up to 50 Hz) · §IV (H = 50, 10 steps)
Check your understanding: The model takes 73 ms. Does that mean actions are produced at about 14 Hz?

No. One run of the model produces a whole chunk of 50 actions, so the action rate (20 or 50 Hz) is separate from how often the model runs (every 0.5 to 0.8 s).

Part C

Understand the training

The paper argues that the recipe matters as much as the architecture. This part covers what data π0 learns from, how very different robots share one model, why there are two training stages, and how language is used.

The pre-training mixture

Intuition
Like a broad apprenticeship: many workplaces, many jobs, uneven quality, plus a few borrowed notebooks from other labs.
The problem it solves
Robot data is scarce, and dexterous tasks need much more of it than the simple pick-and-place data that most datasets contain.
How it works
The mixture combines the authors’ own dexterous-manipulation data (7 robot configurations, 68 tasks, 903 million timesteps: 106 million from single-arm robots and 797 million from two-armed robots) with open-source datasets (Open X-Embodiment, Bridge v2, DROID), which make up 9.1% of the mixture. “OXE Magic Soup” is the subset of Open X-Embodiment used. Each example is one timestep (an observation and an action chunk). Because the data is lopsided (laundry folding dominates), each task-and-robot combination is weighted by n0.43, where n is its number of samples.
Example
Illustration, not from the paper A combination with 100 times more samples than another is used about 7 times as often, not 100 times.
Why the authors chose it
Down-weighting stops the largest tasks from drowning out the rest. The authors also say they combined all data available to them; what data to add and how to weight it remains an open problem.
Technical details
A “task” here is broad: “bussing” covers many dishes, cups and trash items. Each training example also has a language label: the task name, plus short segment annotations (about 2 seconds). The open-source robots use one or two cameras and control rates of 2 to 10 Hz.
Run the example: how many hours are 903 million timesteps?
Our calculation

What each part does

  1. Add the single-arm and two-armed timesteps.
  2. Convert timesteps to hours using the control rates stated in the appendix (our assumption: single-arm at 20 Hz, two-armed at 50 Hz).
  3. Compare with “over 10,000 hours”, and show what the n^0.43 weighting does.
# Data volume check (Section V-A): 903M timesteps of the authors' own data, with 106M from
# single-arm robots and 797M from dual-arm robots. The paper also says "about 10,000 hours".
single_steps, dual_steps = 106e6, 797e6
print("single + dual =", round((single_steps + dual_steps) / 1e6), "million timesteps (paper says 903)")

# Control rates stated in the appendix: the 20 Hz robots are the single-arm UR5e and Franka;
# every other robot runs at 50 Hz. We assume single-arm = 20 Hz and dual-arm = 50 Hz.
hours_single = single_steps / 20 / 3600
hours_dual = dual_steps / 50 / 3600
print(f"single-arm at 20 Hz: {hours_single:,.0f} hours")
print(f"dual-arm at 50 Hz:   {hours_dual:,.0f} hours")
print(f"total: about {hours_single + hours_dual:,.0f} hours, against 'over 10,000 hours' in the introduction")

# Even if every step were at 20 Hz (the slowest rate), the total would be:
print(f"all 903M steps at 20 Hz: {903e6 / 20 / 3600:,.0f} hours")

# Down-weighting (Section V-A): each task-robot combination is weighted by n ** 0.43.
print()
for n_ratio in (2, 10, 100):
    print(f"a combination with {n_ratio}x more samples gets {n_ratio ** 0.43:.2f}x the weight")

Output:

single + dual = 903 million timesteps (paper says 903)
single-arm at 20 Hz: 1,472 hours
dual-arm at 50 Hz:   4,428 hours
total: about 5,900 hours, against 'over 10,000 hours' in the introduction
all 903M steps at 20 Hz: 12,542 hours

a combination with 2x more samples gets 1.35x the weight
a combination with 10x more samples gets 2.69x the weight
a combination with 100x more samples gets 7.24x the weight

The mismatch with “10,000 hours” is discussed in Part F; the assumptions in the first lines matter.

Evidence in the paper
§III · §V-A · Figure 4 · §V-C (the seven robots)
Check your understanding: Why not simply use every sample equally?

Some tasks have far more data. Using samples equally would let those dominate, so the model would spend most of its learning on a few tasks. The n^0.43 weighting gives larger tasks more weight than small ones but far less than their size.

Cross-embodiment training: one model, many bodies

Intuition
A single control panel with 18 dials. A robot with 7 joints uses 7 of them and the rest stay at zero.
The problem it solves
Robots differ in arms, grippers, bases and cameras, so their states and actions have different lengths.
How it works
The state and action vectors always have the size of the largest robot in the data, 18 numbers. Robots with fewer values are zero-padded. Robots with fewer than three cameras have the missing image slots masked out. The same model is trained on all of them together.
Example
Illustration, not from the paper A single UR5e arm with a gripper has 7 values; they fill the first 7 of 18 slots and the other 11 are zero.
Why the authors chose it
It lets data from every robot teach the same network. The paper’s final fine-tuned results use a single cross-embodiment model as the starting point for different robots.
Technical details
Unlike GR00T N1, which gives each robot its own small encoders and decoders, π0 uses one padded layout.
Run the example: padding every robot to 18 numbers
Toy illustration

What each part does

  1. Invent an action for each robot with the sizes the paper lists.
  2. Copy it into the first slots of an 18-number vector and leave the rest at zero.
  3. Build the mask for cameras that do not exist.
import numpy as np
rng = np.random.default_rng(0)

# Robots have different numbers of state and action values; the model always uses 18 (Section V-A).
FULL = 18
robots = {"UR5e (one arm)": 7, "Franka": 8, "bimanual UR5e": 14, "mobile Fibocom": 17}   # sizes from Section V-C

def pad(vector):
    # Fill the unused slots with zeros so every robot gives a vector of the same length.
    padded = np.zeros(FULL)
    padded[: len(vector)] = vector
    return padded

for name, size in robots.items():
    action = rng.normal(size=size)               # a made-up action for this robot
    padded = pad(action)
    print(f"{name:<16} {size:>2} values -> padded to {padded.shape[0]} ({FULL - size} zeros)")

# Missing cameras: robots have 2 or 3 images; the model has 3 image slots, and unused slots are masked out.
cameras = {"UR5e": 2, "bimanual UR5e": 3}
for name, n in cameras.items():
    mask = [True] * n + [False] * (3 - n)        # True = a real image, False = ignore this slot
    print(f"{name:<14} cameras: {n} -> image mask {mask}")

Output:

UR5e (one arm)    7 values -> padded to 18 (11 zeros)
Franka            8 values -> padded to 18 (10 zeros)
bimanual UR5e    14 values -> padded to 18 (4 zeros)
mobile Fibocom   17 values -> padded to 18 (1 zeros)
UR5e           cameras: 2 -> image mask [True, True, False]
bimanual UR5e  cameras: 3 -> image mask [True, True, True]

Random numbers; this shows only the layout.

The seven configurations and their sizes are in Part E.
Evidence in the paper
§V-A · §V-C · Figure 5
Check your understanding: What does the padded zero mean for the model?

Nothing physical: it is a placeholder slot the robot does not have. The model has to learn to ignore those slots for robots that do not use them.

Pre-training, then post-training

Intuition
Pre-training is wide experience, including clumsy attempts and recoveries. Post-training is coaching by an expert for the exact job.
The problem it solves
Training only on tidy, expert data gives a model that has never seen a mistake and cannot recover from one. Training only on messy data gives a model that is never efficient or fluent.
How it works
Pre-train the base model on the whole mixture so that it has broad abilities, including rudimentary performance on many tasks. Then post-train on a smaller, consistent, high-quality dataset for the target task: from about 5 hours for the simplest tasks to 100 or more hours for the most complex. The authors expect the model to follow the fluent strategy of the curated data while keeping a repertoire of recoveries from pre-training.
Example
Illustration, not from the paper Pre-training has seen many shirts fall off tables and be picked up again. Post-training on a few hours of neat folding makes the final behaviour fluent and still able to recover.
Why the authors chose it
The recipe mirrors how large language models are trained (pre-train, then align). See lesson 5.4 and lesson 7.4.[1]
Technical details
The base model is trained for 700 thousand steps; a “parity” version trained for 160 thousand steps is used to compare with baselines that were trained for fewer steps. How much data and which kinds help most is not systematically studied (the authors say so).
Evidence in the paper
§III · §V-A · Figures 11 and 13 (pre-training helps most on hard tasks) · §VII
Check your understanding: If only the post-training data is used, what goes wrong according to the authors?

The model is brittle: because high-quality data rarely contains mistakes, it does not learn how to recover from them.

Language labels and a high-level policy

Intuition
A manager gives the worker one small instruction at a time (“pick up the napkin”) instead of “clean the table”.
The problem it solves
Long tasks need strategy and sequencing, and a single instruction like “bus the table” is not detailed enough for a model to follow reliably.
How it works
Training data has language labels: the task name and short segment annotations (about 2 seconds each). At run time a separate high-level vision-language policy can break a task into the same kind of short commands that π0 then follows. The experiments compare π0 given only the overall task, given commands by a human expert, and given commands from the high-level policy.
Example
Illustration, not from the paper “Bus the table” becomes “pick up the napkin”, then “throw the napkin into the trash”, and so on.
Why the authors chose it
It is analogous to language-model planners such as SayCan (see lesson 1.3), and it uses the VLM backbone’s language ability.[5]
Evidence in the paper
§V-B · Figures 8 and 9
Check your understanding: Why does a human giving step-by-step commands help π0 more than the overall task name?

Each step is a short, simple instruction that matches the segment labels it was trained on, so it only has to choose the motion for that step. The overall task needs it to also plan the order.

Part D

Understand the experiments

What was tested, against what, and what the numbers let us conclude. The paper presents its results as bar charts, not tables, so every value here is a reading from a chart and is marked approximate (±0.03 or so). The notes after each table are ours.

The set-up: four questions, baselines and the score

Intuition
Four exams of increasing difficulty: do the task with no extra teaching, follow instructions, learn a new task from a few hours of examples, and master a long multi-step task.
How it works

The paper asks four questions: (1) how well does the pre-trained model do on tasks seen in pre-training, with no fine-tuning (“zero-shot”)? (2) How well does it follow language commands? (3) How does it compare with methods designed for dexterous manipulation when fine-tuned on new tasks? (4) Can it be adapted to long multi-stage tasks?

Models compared: OpenVLA (a 7-billion-parameter VLA that writes actions as text-like tokens), Octo (a 93-million-parameter diffusion-based generalist policy), π0-small (the authors’ 470-million-parameter variant without a pretrained VLM), and, for fine-tuning, ACT (Action Chunking with Transformers) and Diffusion Policy, both trained only on the task data. A “parity” version of π0 is trained for 160 thousand steps instead of 700 thousand to match the baselines’ number of updates (OpenVLA 160 thousand, Octo 320 thousand).

Score: a normalised score from 0 to 1, averaged over 10 episodes per task and method. A full success is 1.0 and partial progress gets a fraction, for example the share of objects placed in the right receptacle. The rubric for each task is in Part E.

Evidence in the paper
§VI intro · §VI-A · Appendix E (scoring)
Check your understanding: Why is a “parity” version of π0 reported?

The baselines could be trained for fewer steps than the main model because of time limits. The 160k-step version has no more updates than any baseline, so it separates “better design” from “trained longer”.

Zero-shot: the base model on five tasks

Intuition
No coaching, just the pre-trained model and a spoken command.
How it works
Each task is commanded to the same base model by a language command and scored. Shirt folding is success or failure; the others are scored by the number of items handled correctly.
Technical details
Figure 7, read from the bars. “≈ 0” means no visible bar. Approximate, read from a chart
Task (robot)π0π0 parity (160k)π0-smallOpenVLAOcto
Shirt folding (Bi-ARX)1.000.900.50≈ 0≈ 0
Bussing easy (UR5e)0.970.820.450.35 (UR5e-only version)0.05
Bussing hard (UR5e)0.880.500.34≈ 0≈ 0
Grocery bagging (UR5e)0.790.350.27≈ 0≈ 0
Toast out of toaster (Bi-Trossen)0.750.40≈ 0≈ 0≈ 0

π0 scores highest everywhere, and even the parity version beats the baselines. The authors explain OpenVLA’s low scores by its autoregressive tokens lacking action chunks, and Octo’s by limited capacity. Our interpretation Note that OpenVLA and Octo were trained by the authors on this very large mixture, which the authors call a difficult one for OpenVLA, and for fewer steps.

Evidence in the paper
§VI-A · Figures 6 and 7
Check your understanding: Which comparison isolates the value of a pretrained VLM, and what is its weakness?

π0 against π0-small. The weakness is that π0-small is also much smaller and differs in several other ways (Appendix C), so size and pre-training are mixed; the authors say they cannot separate them.

Following language commands

How it works
The model is fine-tuned on three tasks (table bussing, table setting, grocery bagging) whose language comes as short segments of about 2 seconds. Each policy is tested under three conditions: only the overall task command (“flat”), step-by-step commands from a human expert (“human”) and step-by-step commands from a high-level VLM policy (“HL”).
Technical details
Figure 9 (left), read from the bars. Approximate, read from a chart
Language-following rateBussingGrocery baggingTable setting
π0-small0.700.310.31
π00.950.700.90

π0 follows commands much better than π0-small. With expert commands π0’s task score rises clearly, and with the high-level policy it rises to a lesser degree; π0-small does not gain from the commands. Our interpretation This supports the idea that the pretrained VLM provides language ability, with the same size caveat as above.

Evidence in the paper
§VI-B · Figures 8 and 9
Check your understanding: Why does π0-small gain nothing from a human expert’s commands?

The commands only help if the model understands them. π0-small follows language poorly, so detailed commands do not translate into better behaviour.

Learning new tasks from a little data

How it works
Five tasks are fine-tuned with 1, 5 or 10 hours of data: stack bowls and towel folding (close to pre-training, the “easy” tier), tupperware in a microwave (a new object), and paper towel replacement and items in a drawer on a Franka robot (new motions and objects, “hard”). π0 is fine-tuned from the pre-trained model and also trained from scratch on the task data. OpenVLA and Octo start from their public checkpoints; ACT and Diffusion Policy are trained only on the task data.
Technical details
Figure 11, top left plot, read from the points. Approximate, read from a chart
Average over the five tasks1 hour5 hours10 hours
π0 (pre-trained, fine-tuned)0.570.870.87
π0 trained from scratch0.380.790.76
Diffusion Policy0.200.320.39

The strongest earlier models are those trained from scratch on the task, which the authors take as a sign that prior approaches struggle to use pre-training in these domains. Pre-training helps most when data is scarce and when a task is similar to the pre-training data. Our interpretation On individual tasks the picture is mixed: for items in a drawer the two π0 curves are nearly the same at 5 and 10 hours, and for tupperware in the microwave the authors note the 5-hour policy performs similarly to the baselines.

Evidence in the paper
§VI-C · Figures 10 and 11
Check your understanding: What does the gap between “pre-trained” and “from scratch” measure?

The benefit of pre-training on this task, with the architecture held fixed. It is larger with 1 hour of data than with 10 hours in the averaged plot.

Long, multi-stage tasks

How it works
Seven tasks that take 5 to 20 minutes are fine-tuned: four whose data was in pre-training (laundry folding, table bussing, mobile laundry, dryer unloading) and three that were not (box building, packing food into a to-go box, packing eggs). Each is compared with zero-shot (pre-trained only) and from scratch (no pre-training). The authors say they could not solve these with other methods, so there are no other baselines.
Technical details
Figure 13, read from the bars. Approximate, read from a chart
Scoreπ0 fine-tunedFrom scratchZero-shot
Laundry folding (in pre-training)0.820.220.30
Table bussing (in pre-training)0.880.710.48
Mobile laundry (in pre-training)0.930.330.55
Dryer unloading (in pre-training)0.720.380.17
Box building (not in pre-training)0.640.32≈ 0
To-go box (not in pre-training)0.700.46≈ 0
Packing eggs (not in pre-training)0.840.89≈ 0

The fine-tuned model scores above 0.5 on all seven tasks and is highest on six; on packing eggs the from-scratch bar is about the same as, or slightly above, the fine-tuned one, within reading accuracy. Our interpretation The gains from pre-training are largest on the hardest tasks (for example laundry folding, about 0.8 against 0.2), which the authors note.

Evidence in the paper
§VI-D · Figures 12 and 13 · Appendix E
Check your understanding: Why compare against “zero-shot” and “from scratch” on these tasks?

No other method solves them, so the two ablations show what each ingredient adds: pre-training alone (zero-shot), post-training data alone (scratch), and both together.

What the results show

  • On these tasks and robots, π0 scores above the baselines that the authors trained or fine-tuned, in zero-shot and fine-tuning tests.
  • Pre-training on the large mixture generally improves fine-tuning, most for hard tasks and small amounts of data.
  • Step-by-step language commands help a VLM-initialised π0 more than they help π0-small.
  • Long tasks (5 to 20 minutes) were completed to a useful degree after fine-tuning.

What they do not show

  • Which of the design choices (separate weights, flow matching, the VLM, the data mix) is responsible: there are almost no ablations of them.
  • That pre-training helps every task: on a few, a model trained from scratch is about as good (Part F).
  • Statistical certainty: about 10 episodes per task and no confidence intervals.
  • That the comparison with OpenVLA and Octo is architecture-only: their training mixtures, steps and starting points differ from π0’s.

Part E · optional

Engineering deep dive

Equations, token layout, attention mask, sizes, timings and scoring rubrics, for readers who want to rebuild or audit the model. Everything is collapsed; Parts A to D do not depend on it.

The flow-matching equations

Symbols: At is the true chunk of H = 50 future actions starting at time t; ot is the observation (images, language, state); ε is random noise; τ (tau) runs from 0 (noise) to 1 (data); vθ is the network.

Reported by the paper Noisy actions (training):

Atτ=τ⋅At+(1−τ)⋅ε,A_{t}^{\tau }=\tau \cdot A_{t}+(1-\tau )\cdot \varepsilon ,
ε∼N(0, I)\varepsilon \sim N(0,\,I)

Reported by the paper The paper writes the path distribution as q(Atτ | At) = N(τ At, (1 − τ) I) and the loss as

Lτ(θ)=E ∥vθ(Atτ, ot)−u(Atτ ∣At) ∥2,L^{\tau }(\theta )=E\,\lVert v_{\theta }(A_{t}^{\tau },\,o_{t})-u(A_{t}^{\tau }\,\mid A_{t})\,\rVert ^{2},
u=ε−Atu=\varepsilon -A_{t}

Reported by the paper τ is sampled from a shifted Beta distribution that emphasises noisy (low) values, with s = 0.999 (the same as in GR00T N1):

p(τ)=Beta⁡(s−τs; 1.5, 1)p(\tau )=\operatorname{Beta}(\frac{s-\tau }{s};\,1.5,\,1)

Reported by the paper At run time, start from At0 ~ N(0, I) and take 10 forward-Euler steps of size δ = 0.1:

Atτ+δ=Atτ+δ⋅vθ(Atτ, ot)A_{t}^{\tau +\delta }=A_{t}^{\tau }+\delta \cdot v_{\theta }(A_{t}^{\tau },\,o_{t})

Our calculation The printed target u = ε − At and the printed update point in opposite directions to the path, and the printed variance looks like a standard deviation: see F1 and F2. The example in F1 measures both. For the training objective in more depth, see lesson 4.7.

Run the example: which noise levels does training visit?
Toy illustration

What each part does

  1. Sample u from Beta(1.5, 1) and convert to τ = s(1 − u).
  2. Print the mean, the share below 0.5 and a five-bin histogram, with exact values.
import numpy as np
rng = np.random.default_rng(0)

s = 0.999
u = rng.beta(1.5, 1.0, 200000)                 # u = (s - tau) / s follows Beta(1.5, 1)
tau = s * (1 - u)

print("average tau:", round(float(tau.mean()), 3), "(exact value:", round(s * (1 - 1.5 / 2.5), 3), ")")
print("share of training samples with tau below 0.5:", round(float(np.mean(tau < 0.5)), 3), "(exact:", round(1 - 0.5 ** 1.5, 3), ")")
edges = np.linspace(0, 1, 6)
counts, _ = np.histogram(tau, bins=edges)
for lo, hi, n in zip(edges[:-1], edges[1:], counts):
    print(f"tau in [{lo:.1f}, {hi:.1f}): {n / len(tau):.3f}")

Output:

average tau: 0.399 (exact value: 0.4 )
share of training samples with tau below 0.5: 0.648 (exact: 0.646 )
tau in [0.0, 0.2): 0.286
tau in [0.2, 0.4): 0.250
tau in [0.4, 0.6): 0.211
tau in [0.6, 0.8): 0.164
tau in [0.8, 1.0): 0.089

This is the same distribution as in GR00T N1, which copied it from π0.

Token layout, the attention mask and the time embedding (Appendix B)

Reported by the paper The sequence has three blocks: [images, language], then [state], then [the H noisy action tokens]. Within a block there is full bidirectional attention. A block cannot attend to later blocks. Only the transformer outputs for the H action tokens are used; a linear projection turns them into vθ.

Reported by the paper Each noisy action is embedded as W3 · swish(W2 · concat(W1 · a, φ(τ))), where φ is a sinusoidal encoding of τ, W1 ∈ Rw×d, W2 ∈ Rw×2w, W3 ∈ Rw×w, d is the action dimension and w the width of the action expert.

Run the example: the blockwise attention mask
Toy illustration

What each part does

  1. Give each token a block number: 0 for image/language, 1 for state, 2 for actions.
  2. A token may look at another when the other’s block number is not larger.
  3. Print the mask and check the three properties the paper states.
import numpy as np

# Which token may look at which? Three blocks, as in Appendix B:
#   block 0: image and language tokens (the pre-trained VLM's inputs)
#   block 1: the robot state token
#   block 2: the noisy action tokens
# Rule: inside a block everything sees everything; a block sees earlier blocks, never later ones.
sizes = [4, 1, 3]                                   # tiny toy sizes: 4 image/text tokens, 1 state, 3 actions
block_of = np.repeat(np.arange(len(sizes)), sizes)  # block number of every token: [0 0 0 0 1 2 2 2]

# allowed[i, j] is True when token i may look at token j.
allowed = block_of[None, :] <= block_of[:, None]

names = ["img/text"] * sizes[0] + ["state"] * sizes[1] + ["action"] * sizes[2]
print("row = the token that looks, column = the token it looks at (1 = allowed)")
for i, row in enumerate(allowed.astype(int)):
    print(f"{names[i]:>8}  {''.join(map(str, row))}")

print()
print("image/text tokens see any state or action token:", bool(allowed[:4, 4:].any()))
print("the state token sees any action token:          ", bool(allowed[4, 5:].any()))
print("action tokens see every earlier token:          ", bool(allowed[5:, :5].all()))

Output:

row = the token that looks, column = the token it looks at (1 = allowed)
img/text  11110000
img/text  11110000
img/text  11110000
img/text  11110000
   state  11111000
  action  11111111
  action  11111111
  action  11111111

image/text tokens see any state or action token: False
the state token sees any action token:           False
action tokens see every earlier token:           True

Tiny sizes (4, 1 and 3 tokens) so the matrix fits on screen; the real blocks are much larger.

Run the example: turn a noisy action into a token
Toy illustration

What each part does

  1. Define the sinusoidal encoding of τ and the swish function.
  2. Create random W1, W2 and W3 with the shapes from Appendix B.
  3. Embed each of the 50 noisy actions together with τ and print the shapes.
import numpy as np
rng = np.random.default_rng(0)       # fixed seed so the numbers are repeatable

d = 18          # action size (all robots are padded to 18 numbers, Section V-A)
w = 8           # width of the action expert in this toy (the real one is 1024)
H = 50          # actions in a chunk

def sinusoidal(tau, width):
    # The flow-matching time tau (a single number) turned into `width` numbers, as in a transformer's position code.
    freqs = 1000.0 ** (-np.arange(width // 2) / (width // 2))
    angles = tau * freqs
    return np.concatenate([np.sin(angles), np.cos(angles)])

def swish(x):
    return x / (1 + np.exp(-x))

# Appendix B: embedding = W3 . swish( W2 . concat( W1 . a, phi(tau) ) )
W1 = rng.normal(size=(w, d)) * 0.1       # action (18 numbers) -> width w
W2 = rng.normal(size=(w, 2 * w)) * 0.1   # joins the action features with the time features
W3 = rng.normal(size=(w, w)) * 0.1       # final mixing

noisy_actions = rng.normal(size=(H, d))  # one noisy action per row
tau = 0.3                                # how far along the noise-to-data path we are

tokens = []
for a in noisy_actions:                  # each action in the chunk becomes one token
    features = np.concatenate([W1 @ a, sinusoidal(tau, w)])
    tokens.append(W3 @ swish(W2 @ features))
tokens = np.array(tokens)

print("noisy action chunk:", noisy_actions.shape, "-> action tokens:", tokens.shape)
print("time encoding for tau = 0.3 has", sinusoidal(tau, w).shape[0], "numbers; it is the same for every action in the chunk")

Output:

noisy action chunk: (50, 18) -> action tokens: (50, 8)
time encoding for tau = 0.3 has 8 numbers; it is the same for every action in the chunk

Random weights and a small width; the shapes and the data flow are what the example shows.

Architecture sizes
As printed in Appendix B and Figure 3. The “same layers” entry for the expert is our reading: the paper says the experts interact only in attention, so the layer count must match.
VLM backbone (Gemma 2B)Action expert
Width2,0481,024
Depth (layers)18same number of layers, since the experts interact in every attention layer
MLP size16,3844,096
Attention heads18 as printed in Appendix B (see F3)not listed
Key/value heads · head size1 · 256must match the backbone’s
Parametersabout 3 billion with SigLIP (SigLIP about 400M + Gemma 2.6B)about 300 million
Inference timing (Table I) and how often the model runs
As printed in Appendix D.
PartTime on an RTX 4090
Image encoders (3 images)14 ms
Observation forward pass32 ms
10 action (flow) steps27 ms
Network latency, if off-board13 ms
Total on-board73 ms
Total off-board86 ms

Reported by the paper Chunks are executed open-loop: every 0.8 s (16 actions) for the 20 Hz UR5e and Franka robots and every 0.5 s (25 actions) for the 50 Hz robots. Temporal ensembling was tried early and hurt performance. The worked arithmetic is in stage 5.

The seven robot configurations (Section V-C)
Sizes are the numbers of values; every vector is padded to 18.
RobotCamerasConfiguration · action size
UR5e (one arm, parallel gripper)2 (wrist, over the shoulder)7 · 7
Bimanual UR5e314 · 14
Franka28 · 8
Bimanual Trossen (ALOHA-style)3 (two wrist, one base)14 · 14
Bimanual ARX and AgileX3 (two wrist, one base)14 · 14
Mobile Trossen and mobile ARX (non-holonomic base)3 (two wrist, one base)14 · 16
Mobile Fibocom (holonomic base)not stated in this section14 · 17
How π0-small differs (Appendix C)
  • About 470 million parameters, with no VLM initialisation.
  • DistilBERT encodes the language command.
  • The action expert cross-attends to the observation encoder (an encoder-decoder layout), instead of sharing attention.
  • A smaller pretrained ResNet-ViT hybrid encodes the images, with image encoders that do not share weights.
  • The observation transformer is not pre-trained on internet data.
  • The action expert is a DiT (Diffusion Transformer) using AdaLN-Zero layers for the flow-matching time instead of Gemma-style layers.

Both models still use separate weights for the observation encoder and the action expert, the same observation format, and 10 flow-matching steps.

Scoring rubrics (Appendix E)
Scores in the figures are these points divided by the maximum, averaged over 10 episodes.
TaskMaximum score and how points are given
Shirt foldingsuccess or failure: sleeves folded in and one half-fold along the length
Bussing easy / hard7 / 12: one point per object placed in the right bin
Grocery bagging7: one point per item bagged
Toast out of toaster4: per toast, one point for picking it up and one for plating
Stack bowls3: two for stacking, one for neatness
Towel folding3: two half-folds and neatness
Tupperware in microwave4: open, pick up, place, close
Paper towel replacement4: grasp old roll, remove it, grasp new roll, place it
Items in drawer5: open, three items, close
Laundry folding / mobile laundry4 per item: out of the bin, flattened, folded, stacked or placed
Table bussing12: one point per object
Box building5: pick up, fold in half, close right flap, close left flap, centre neatly
Packing eggs7: one per egg placed, one for closing the lid
Packing food (to-go box)5: pick up plate, three items, close the box
Dryer unloading5: approach, place the basket, open, unload, close

Part F

Critical paper review

Everything above reports what the paper says. This part is our independent reading: places where the paper’s own numbers or equations disagree, where wording is ambiguous, where the method limits what can be concluded, and what the authors list as limits. We looked for these in good faith; none overturns the paper’s main message, and each links back to the concept it affects. Calculations are reproducible in the examples. The figures in this paper are charts, so any statement about a bar is a reading of the chart, accurate to a few hundredths.

Numerical inconsistencies and ambiguities

  1. F1. The direction of the flow-matching target and the Euler step Numerical inconsistency

    What the paper says. Noisy actions are τ·A + (1 − τ)·ε, the network is trained to match the “denoising vector field” u = ε − A, and actions are generated by integrating from τ = 0 to τ = 1 with A + δ·v.

    What we found. With that path the actions move in the direction A − ε as τ grows, the opposite of u. Following the printed update with the printed target moves away from the data. This is the same convention GR00T N1 reuses (and its guide flags the same issue).

    Why it matters. Probably a typo or a convention difference between paper and code (the code is the authority). It matters if you re-implement the equations literally; it does not by itself change the reported results. Concept: Flow matching

    Run the example: noise path: variance and direction
    Our calculation

    What each part does

    1. Sample many noise values and build the noisy action at three values of τ.
    2. Compare the measured variance with (1 − τ) and (1 − τ)².
    3. Measure the slope of the path with τ and compare with the printed target.
    import numpy as np
    rng = np.random.default_rng(0)
    
    # Our own measurement of the noisy-action path used in Section IV:
    #   A_tau = tau * A + (1 - tau) * eps,   with eps ~ N(0, 1)
    # The paper writes the path distribution as N(tau * A, (1 - tau) I). If the second argument is a variance,
    # the measured variance below says it should be (1 - tau) squared.
    A = 1.0                                          # one fixed "clean action" (a single number, for simplicity)
    eps = rng.normal(size=1_000_000)
    
    for tau in (0.2, 0.5, 0.8):
        noisy = tau * A + (1 - tau) * eps
        print(f"tau = {tau}: measured variance {noisy.var():.3f} | (1 - tau) = {1 - tau:.3f} | (1 - tau)^2 = {(1 - tau) ** 2:.3f}")
    
    # Direction of travel: how the noisy action moves as tau grows from 0 (noise) to 1 (data).
    a, e = 0.7, -0.4                                  # a clean action and a noise sample (arbitrary values)
    d = 1e-6
    slope = (((0.5 + d) * a + (1 - 0.5 - d) * e) - (0.5 * a + 0.5 * e)) / d      # (A_tau at 0.5 + d minus A_tau at 0.5) / d
    print()
    print("the path moves with slope A - eps =", round(a - e, 3), "as tau increases (measured:", round(slope, 3), ")")
    print("the target printed in the paper is eps - A =", round(e - a, 3), "-> the opposite direction")
    print("an Euler step A + delta * v with v = eps - A therefore moves away from the data")

    Output:

    tau = 0.2: measured variance 0.641 | (1 - tau) = 0.800 | (1 - tau)^2 = 0.640
    tau = 0.5: measured variance 0.250 | (1 - tau) = 0.500 | (1 - tau)^2 = 0.250
    tau = 0.8: measured variance 0.040 | (1 - tau) = 0.200 | (1 - tau)^2 = 0.040
    
    the path moves with slope A - eps = 1.1 as tau increases (measured: 1.1 )
    the target printed in the paper is eps - A = -1.1 -> the opposite direction
    an Euler step A + delta * v with v = eps - A therefore moves away from the data
  2. F2. “N(τA, (1 − τ)I)”: variance or standard deviation? Numerical inconsistency

    What the paper says. The probability path is q(A^τ | A) = N(τA, (1 − τ)I), and in practice the noisy actions are A^τ = τA + (1 − τ)ε with ε ~ N(0, I).

    What we found. If the second argument of N is a variance, the construction gives (1 − τ)², not (1 − τ): the measured variance matches the square. If it is meant as a standard deviation the notation is non-standard.

    Why it matters. A notation slip with no effect on the method as implemented (the practical recipe is explicit). Concept: Flow matching · example

  3. F3. The attention-head count and the 300-million-parameter expert Ambiguity

    What the paper says. Appendix B gives the Gemma configuration as width 2,048, depth 18, MLP 16,384, num heads 18, 1 key/value head, head size 256, and a downsized action expert of width 1,024 and MLP 4,096, “about 300 million parameters”.

    What we found. Building the expert with Gemma-style layers and the stated sizes gives about 311 million parameters with 8 attention heads (Gemma 2B’s layout, to our knowledge) but about 406 million with 18. So “18 heads” is most likely a typo for 8 (18 is the depth). This is our estimate under the assumptions in the example.

    Why it matters. Minor, but a reader rebuilding the model from the appendix would be misled. Concept: Action expert

    Run the example: can the expert have about 300 million parameters?
    Our calculation

    What each part does

    1. Write the parameter count of one Gemma-style layer from its pieces (attention matrices and a gated MLP).
    2. Fill in the expert’s sizes from Appendix B.
    3. Compare 8 and 18 heads with the stated 300 million.
    # Can we reproduce "about 300 million parameters" for the action expert from the sizes in Appendix B?
    # Assumption: the expert is built like Gemma (gated MLP with 3 matrices, multi-query attention) and
    # interacts with the main model only through attention, so its attention matrices must match the
    # main model's head layout: head_dim 256 and 1 key/value head.
    
    def expert_params(width, mlp_dim, depth, heads, head_dim=256, kv_heads=1):
        q = width * heads * head_dim            # query projection
        kv = 2 * width * kv_heads * head_dim    # key and value projections (one head each)
        o = heads * head_dim * width            # output projection
        mlp = 3 * width * mlp_dim               # gated MLP: gate, up and down matrices
        return depth * (q + kv + o + mlp)
    
    width, mlp_dim, depth = 1024, 4096, 18       # action expert sizes from Appendix B
    
    for heads in (8, 18):
        p = expert_params(width, mlp_dim, depth, heads)
        print(f"with {heads:>2} attention heads the expert has about {p / 1e6:.0f} million parameters")
    print("the paper says: about 300 million; Appendix B lists num heads = 18 for the main model (Gemma 2B has 8)")

    Output:

    with  8 attention heads the expert has about 311 million parameters
    with 18 attention heads the expert has about 406 million parameters
    the paper says: about 300 million; Appendix B lists num heads = 18 for the main model (Gemma 2B has 8)

    Assumes Gemma-style layers, ignores small normalisation weights, and uses the head layout the paper lists.

  4. F4. 903 million timesteps against “over 10,000 hours” Ambiguity

    What the paper says. Pre-training uses 903 million timesteps of the authors’ own data (106 million single-arm, 797 million two-armed), and the paper elsewhere says about 10,000 hours of dexterous manipulation data. The appendix says single-arm UR5e and Franka run at 20 Hz and all other robots at 50 Hz.

    What we found. With those rates and the assumption that single-arm means 20 Hz and two-armed means 50 Hz, 903 million timesteps is about 5,900 hours; even at 20 Hz throughout it is about 12,500 hours at most. The numbers fit only if the hours include other data or the timesteps are counted differently (for example after sub-sampling), which the paper does not say.

    Why it matters. The scale claim (“largest robot pre-training mixture”) rests on this figure; the quantity of data is not fully traceable. Concept: The pre-training mixture · example

  5. F5. Smaller points Ambiguity

    What the paper says. Figure 3 labels the mobile manipulators “18 DoF” (degrees of freedom); Section V-C gives mobile robots 14-dimensional configurations with 16- or 17-dimensional actions; the padding size of 18 is described as covering two arms, two grippers, a mobile base and a vertically actuated torso.

    What we found. None of the listed robot configurations has a torso, so 18 is a padding size rather than the size of any listed robot. The inference times in Table I add up as stated (14 + 32 + 27 = 73; 73 + 13 = 86).

    Why it matters. No effect on results; worth knowing when reading the figure labels. Concept: Cross-embodiment training

Methodological caveats

  1. F6. “Best across the board” is slightly stronger than the charts Method caveat

    What the paper says. π0 generally outperforms other methods; the pre-trained model is frequently better than the non-pre-trained one, sometimes by as much as 2x; on the complex tasks the full recipe performs best across the board.

    What we found. Mostly true, with exceptions visible in the charts: for tupperware in the microwave the 5-hour pre-trained policy is about the same as the baselines and below the from-scratch model; for items in a drawer the pre-trained and scratch curves coincide at 5 and 10 hours; for packing eggs the from-scratch bar is about equal to or above the fine-tuned one; for mobile laundry the zero-shot bar is above the from-scratch one. The paper acknowledges some of these in text.

    Why it matters. Read “generally” literally: pre-training helps most for hard tasks and small data, and not always. Concept: New tasks · Long tasks

  2. F7. π0 against π0-small mixes size and pre-training Method caveat

    What the paper says. π0-small (no VLM initialisation) is used to show the benefit of VLM pre-training, for zero-shot results and language following.

    What we found. π0-small is about seven times smaller and differs in six other ways (Part E): another language encoder, an encoder-decoder layout, a smaller image encoder, a non-pre-trained observation transformer and a DiT-style expert. The authors say they cannot remove the size confounder.

    Why it matters. The comparison shows the whole π0 recipe beating this particular smaller model, not the isolated effect of the VLM. Concept: Language · Zero-shot

  3. F8. The baselines are not trained like π0 Method caveat

    What the paper says. OpenVLA and Octo are trained on the authors’ mixture for 160 and 320 thousand steps (π0: 700 thousand, parity version 160 thousand); for fine-tuning they start from public checkpoints trained on Open X-Embodiment, while ACT and Diffusion Policy train only on task data.

    What we found. Different pre-training data, steps, model sizes and (for OpenVLA) a no-chunking design all differ between π0 and its baselines. The authors say so, and say they evaluate the specific models rather than the architectures. Hyperparameter tuning for the baselines is not described.

    Why it matters. The results show π0 as a system beats these systems; they do not isolate flow matching, action chunking or the VLM. Concept: The set-up

  4. F9. About 10 episodes per task, partial credit, no intervals Method caveat

    What the paper says. Scores are averaged over 10 episodes per task and method, with fractional credit from rubrics that differ from task to task.

    What we found. No confidence intervals or repeated runs are reported. With 10 episodes a single task’s average can move by tenths of a point from one or two episodes, and a per-task rubric of 3 to 12 points means different tasks are not scored on the same scale. Shirt folding is 10 evaluations (5 shirts × 2).

    Why it matters. Large gaps (for example 0.8 against 0.2) are meaningful; small gaps between neighbouring bars, and per-task orderings, are not. Concept: The set-up

  5. F10. Design choices with little or no supporting experiment Method caveat

    What the paper says. The paper says separate weights for the action tokens improved performance, hypothesises why a noisy-timestep-heavy Beta distribution suits actions, down-weights tasks by n^0.43 and reports that temporal ensembling hurt.

    What we found. We found no numbers for any of these (no ablation of separate weights, the Beta distribution, the 10 steps, the weighting exponent, or ensembling), and the authors say the best composition of the pre-training data is unknown.

    Why it matters. They are reasonable design decisions and observations, not demonstrated causes of the results. Concept: Action expert · Flow matching · Mixture

  6. F11. Open-loop execution limits reaction time Method caveat

    What the paper says. Chunks are executed without re-observation: 0.8 s on the 20 Hz robots and 0.5 s on the 50 Hz robots, and temporal ensembling is not used.

    What we found. Inference takes 73 to 86 ms, so the model is idle most of the time; within a window the robot cannot react to what it sees. This is our reading of the paper’s own numbers and not a measurement of failures. The paper does not report how often failures occur inside a chunk.

    Why it matters. Fast disturbances are handled only at the next replan; shorter windows might help but the paper does not study them. Concept: Action chunks

  7. F12. Priority and scale claims Method caveat

    What the paper says. π0 is described as the first flow matching VLA producing high-frequency action chunks for dexterous control, the largest robot pre-training mixture, the longest dexterous tasks in end-to-end robot learning, and a new state of the art.

    What we found. These statements are made “to our knowledge”, and the paper offers no survey that would let a reader verify them. “State of the art” on the complex tasks rests on comparisons with ablations of π0 itself, since the authors report no other method solved them.

    Why it matters. Treat as the authors’ positioning; the evidence in the paper is the experiments above. Concept: Long tasks

Limitations the authors state

  1. F13. The authors’ own list Limitation

    What the paper says. The composition of the pre-training data is not understood: which data helps and how to weight it is open. Not all evaluated tasks work reliably, and it is unclear how to predict how much data a task needs. It remains to be seen how much positive transfer there is from combining very diverse data and whether universality extends to other domains such as driving, navigation and legged locomotion.

    What we found. We agree with each; they bound where the results should be expected to hold, and match the gaps in the ablations above.

    Why it matters. The paper presents π0 as a stepping stone and a prototype, not a finished robot foundation model. Concept: Pre-training and post-training · Mixture

Knowledge check

Try each question first, then reveal the explanation.

Question 1

What is the “action expert” in π0, and how does it connect to the pretrained vision-language part?

Explanation

It is a second, smaller set of transformer weights (about 300 million parameters, trained from scratch) used for the robot state and the noisy action tokens. It sits in the same transformer as the pretrained backbone and the two interact only through attention, controlled by a blockwise mask.

Question 2

How does π0 produce an action chunk, and how often does it run the model?

Explanation

It starts from random noise for 50 actions and applies 10 small flow-matching steps, each pass reading the cached scene tokens. The robot executes the first 16 (20 Hz robots) or 25 (50 Hz robots) actions without re-observing and then runs the model again.

Question 3

In the fine-tuning results, what do the “pre-trained” and “from scratch” curves tell you, and where do they not differ?

Explanation

They show the benefit of pre-training with the architecture fixed. Pre-training helps most with little data and on hard tasks; on some tasks (items in a drawer, packing eggs) the two are about the same.

Question 4

Name one numerical or notational issue and one methodological caveat from the critical review.

Explanation

For example: the printed flow-matching target and update point in opposite directions (or: 903 million timesteps are about 5,900 hours, not over 10,000). And: π0-small differs from π0 in size and in several other ways, so it does not isolate the effect of the VLM.

Glossary

VLA
Vision-language-action model: images and an instruction in, robot actions out.
VLM
Vision-language model: reads images and text together.
Foundation model
A large model trained on broad data and then adapted to many tasks.
Token
One slot in the sequence a transformer reads: a word, an image patch or a robot action.
Proprioception
The robot’s own joint readings.
Dexterous manipulation
Careful, fine motion of hands and grippers, such as folding cloth.
Action expert
The second, smaller set of weights in π0 for the robot state and action tokens.
Mixture of experts
A design in which different inputs are routed to different sets of weights; π0 uses two.
Flow matching
A way to train a network to move noisy samples toward clean ones in a few steps; a variant of diffusion.
Action chunk
A short sequence of consecutive future actions produced at once (50 in π0).
Open-loop execution
Carrying out a plan for a while without re-observing the scene.
Cross-embodiment
Training one model on data from robots with different bodies.
OXE
Open X-Embodiment: a pooled multi-robot dataset.
Pre-training / post-training
Broad training on all data first; then fine-tuning on curated data for the target task.
Zero-shot
Using the pre-trained model on a task with no task-specific fine-tuning.
Parity version
A version of the model trained for as few steps as the baselines, for a fair comparison.
KV cache
Stored attention keys and values that avoid recomputing unchanged tokens.
DoF
Degrees of freedom: the number of independent joints or motions.
Euler step
The simplest way to follow a direction field: move a little way along it.

References

Numbered notes in the text, like [1], point here. Each entry says what it is cited for and how that was checked. Papers and books can be revised or misread, so follow the links before relying on a detail. Code marked “Toy model” is our own illustration of an idea, not the code of the cited system.

  1. Black, K., et al. (2024). π0: A vision-language-action flow model for general robot control. arXiv:2410.24164

    Cited for:

    • Architecture details: one transformer with two sets of weights (a 3-billion-parameter PaliGemma VLM backbone for image and language tokens, and a roughly 300-million-parameter action expert for the robot state and noisy action tokens), 50-action chunks, 10 Euler steps of flow matching, a blockwise attention mask, and open-loop execution of chunks at up to 50 Hz. Checked against the full text of the paper (arXiv v2 PDF), read sentence by sentence.
    • Training recipe and evidence: pre-training on about 10,000 hours of the authors’ own data from 7 robot configurations and 68 tasks plus open-source datasets (OXE, Bridge v2, DROID), then post-training on 5 to 100+ hours of curated data; evaluated zero-shot, for language following, in fine-tuning to new tasks and on long multi-stage tasks (Figures 7, 9, 11, 13, with scores averaged over 10 episodes). Checked against the full text of the paper (arXiv v2 PDF), read sentence by sentence.
    • Pairs the pretrained vision-language model with a separate set of weights for the action outputs (the “action expert”) that generates action chunks with flow matching. Checked against the paper, via summaries of its text.
  2. Beyer, L., et al. (2024). PaliGemma: A versatile 3B VLM for transfer. arXiv:2407.07726

    Cited for:

    • A vision-language model of about 3 billion parameters made from a SigLIP image encoder and the Gemma-2B language model. Checked against the paper’s abstract.
  3. Lipman, Y., Chen, R. T. Q., Ben-Hamu, H., Nickel, M. and Le, M. (2023). Flow matching for generative modeling. ICLR 2023 / arXiv. arXiv:2210.02747

    Cited for:

    • Flow Matching is a simulation-free way to train continuous normalizing flows by regressing the vector fields of fixed conditional probability paths; sampling works with off-the-shelf numerical ODE solvers. Checked against the paper’s abstract.
  4. Zhao, T. Z., Kumar, V., Levine, S. and Finn, C. (2023). Learning fine-grained bimanual manipulation with low-cost hardware. arXiv:2304.13705

    Cited for:

    • Introduces Action Chunking with Transformers (ACT), which learns a generative model over sequences of actions; the paper uses action chunking and temporal ensembling to reduce compounding errors. Checked against the paper, via summaries of its text.
  5. Ahn, M., et al. (2022). Do as I can, not as I say: Grounding language in robotic affordances. Conference on Robot Learning (CoRL) 2022. arXiv:2204.01691

    Cited for:

    • Constrains a large language model with pretrained skills: the language model supplies task-level knowledge about what is useful, and the robot’s skills and their affordance (value) functions supply grounding in what is feasible in the current state. Checked against the paper’s abstract.

Go further

All paper guides · Back to the VLA track