Training and evaluation

Training a two-level policy, then finding out which level failed

The policies we train have two levels. A high-level model (Molmo 2) looks at the camera and picks the next skill and a target point; a low-level model (ManiFlow) moves the arm. Both are trained only on ToyBlocks data. When an episode fails, we want to know which of the two was responsible, so the eval system lets you swap either one for an oracle.

Molmo 2 + ManiFlow on a stacking task. The panel on the right shows the high-level command and the goal checklist.

Training

During data generation the planner reads every block's pose straight from the simulator. A trained policy doesn't get that. It has to work out where the blocks are from camera images, the same way it would on a real robot, so both models map raw camera images and the robot's joint state to actions.

We split the policy in two. Molmo 2, a vision-language model, is the high level: it chooses the skill to run and points at the block to run it on. ManiFlow is the low level and carries out that one instruction. ManiFlow is trained to pause once it has finished a skill and ask Molmo 2 for the next one.

Molmo2-4B-tb high level

  • Input: one 640×360 front-camera image and the goal as text.
  • Output: a short plan, then the next action and its target as a point in the image.
  • Actions: pick, place (on a block or on the table), flip (left, right, forward, backward), rotate (cw, ccw) and done.
  • Training: Molmo2-4B fine-tuned for 6,000 steps at batch size 256 on three-block stacking episodes. A quarter of each batch is general pointing data (PixMo-Points, PixMo-Count, CoSyn-Point) so the model keeps its general pointing ability. About 8 hours on 8 H100s.

Docs: Molmo 2 in evals

maniflow-tb low level

  • Input: front and wrist RGB at 224×224, a 9-D robot state, the action name, and a heatmap drawn around the high level's target point.
  • Output: chunks of 9-D absolute actions (7 joints, gripper, play mode). It predicts 50 steps and runs the first 25.
  • Model: flow matching with consistency training, a CLIP ViT-B/16 image encoder and a 12-layer DiT action head, 322.5M parameters.
  • Training: 200,000 steps on 8 GPUs, batch 128 per GPU, on three ToyBlocks-generated LeRobot datasets.

Docs: training ManiFlow · all training flags

Prompt format

Molmo 2 gets the goal as a tower listed from top to bottom, followed by fixed instructions. It answers with the progress so far, the next step, and the action with its target point:

Promptstack A 4 B. plan. point to target. predict action.
Answernow: A not on 4, 4 on B. next: move A to 4. Do: block A <points coords="1 1 367 623">block A</points> pick
With historyprevious action: block A <points coords="1 1 367 623">block A</points> pick. stack A 4 B. plan. point to target. predict action.

The prompt can start with the previous step, written the same way as an answer. Point coordinates run from 0 to 1000 across the image width and height. Each target sits 5 px (in a 640×360 frame) below the block's center, on the face that points at the camera. ManiFlow then receives the action word ("pick") and a heatmap drawn around that point.

Data: toyblocks-data

Pausing and play mode

ManiFlow doesn't just move the arm. It also learns to say "I'm done." ManiFlow's ninth action dimension is the play mode: 1 keeps going, 0 indicates to the model that the attempt is complete and the robot is retracting, and −1 says the skill is done. ManiFlow learns it from the training labels: when a pick, place, flip or rotate finishes the attempt and retract stages partway through a chunk, it emits a −1 and the rest of that chunk repeats the final pose and is marked as done. At eval time, 1 and 0 are fed back as part of the next state. A −1 ends the skill, and the arm holds where it stopped until the next query. The skill boundaries behind these labels come straight from data generation, where every frame is labelled with its sub-goal.

A training episode with its play-mode labels. Input is the play mode fed back to ManiFlow, which is only ever 1 or 0. Phase target is the 25-step chunk it learns to predict: green is 1 (keep going), yellow is 0 (attempt complete, retracting), and red is −1, which fills the rest of a chunk once a skill ends inside it. The bar along the bottom covers the whole episode.

Molmo 2 can be queried on two schedules:

Synchronous and asynchronous Molmo 2 queries over the same ManiFlow rollout Seven action chunks. ManiFlow runs pick A, reports −1 partway through chunk 3 and holds; runs place on 4, reports −1 partway through chunk 6 and holds. In synchronous mode Molmo 2 is queried at all seven chunk boundaries. In asynchronous mode it is queried only at the start and at the first boundary after each −1, three calls in total. SynchronousMolmo 2 is queried at every chunk boundary: 7 calls Molmo 2 Query 1: pick Apick A Query 2: pick Apick A Query 3: pick Apick A Query 4: place on 4place on 4 Query 5: place on 4place on 4 Query 6: place on 4place on 4 Query 7: donedone ManiFlow Play mode 1: running pick Apick A · play mode 1 Holding after −1 until the next boundary Play mode 1: running place on 4place on 4 · 1 Holding after −1 until the next boundary −1 −1 AsynchronousMolmo 2 is queried at the start and after each −1: 3 calls Molmo 2 Query 1: pick Apick A No query No query Query 2: place on 4 (first boundary after −1)place on 4 No query No query Query 3: done (first boundary after −1)done ManiFlow Play mode 1: running pick Apick A · play mode 1 Holding after −1 until the next boundary Play mode 1: running place on 4place on 4 · 1 Holding after −1 until the next boundary −1 −1 0255075100125150 control steps (one action chunk = 25 steps)
Molmo 2 queriedno queryManiFlow running (1)holding after −1−1 skill done
The same rollout on both schedules. In both, ManiFlow's −1 ends the skill and the arm holds until the next chunk boundary. The synchronous run asks Molmo 2 again at every boundary, while the asynchronous run waits for −1.

Docs: high-level conditioning modes · HL options · pause labelling in training · play-mode metrics

Evaluation Modes

A mode is a choice of high level and low level. All of them run from the same launcher.

ModeHigh levelLow levelWhat it tells youDocs
Full systemMolmo 2, queried every action chunkManiFlowEnd-to-end performance. This is the default.defaults
Asynchronous high levelMolmo 2, queried at the start and whenever ManiFlow finishes a skillManiFlow (play-mode checkpoint)The full system with fewer high-level calls.HL options
High-level oracleSymbolic planner using the episode's PDDL problemManiFlowHow good the low level is when it always gets the right command.modes
Low-level oracleMolmo 2The motion-planned skills used for data generationHow good the high level is when every command is carried out well. Each command acts on the block nearest its target pixel.HL options
ReplaynoneThe dataset's recorded actions, open loopWhether the simulation, the dataset and the eval setup agree. If replay fails, policy numbers on that data don't mean much.replay

There is no mode with both oracles: that is just data generation. The low-level oracle always queries Molmo 2 when a skill ends, so it has no every-chunk variant. ManiFlow can also run with no high level at all, given only the episode's goal sentence.

Low-level oracle: Molmo 2 picks the skills, motion-planned skills execute them.
The high-level overlay video shows each command and its target point.

Docs: high-level conditioning modes · per-policy defaults · dataset replay

ResultsHow Molmo 2 does with the motion-planned skills or ManiFlow as its low level, on easy, medium and hard tasks with seen and held-out blocks.Molmo 2 results →

Evaluation at Scale

Every eval episode starts from an episode in a dataset. An episode queue reads the robot pose, block poses and sizes, table height and goal from the recording, and the policy has to reach the goal from there. Since the scene comes straight from the dataset, a difference in success rate between two models reflects the models and not a difference in setup.

The queue hands episodes out to GPU-parallel environments, so the same command works on a single workstation GPU or across a multi-GPU machine.

50 eval environments running at once, shown at 8× speed.

Docs: design goals · the episode queue

Oracle comparison

In this view, Molmo 2's choice is on the left and the symbolic planner's choice for the same scene at the same moment is on the right, with the target heatmaps drawn on both. It makes it easy to spot the exact frame where the model's plan starts to drift from the planner's.

Molmo 2 (left) and the planner (right) agreeing on the target.

TAMPER: training on your failures

TAMPER (TAMP Expert Relabeling) is a DAgger-style loop with a planning expert. An eval run finds the states where the policy goes wrong; the expert then plans new demonstrations starting from those states. The next round of training data then covers situations the policy actually ends up in, not only the ones data generation happens to sample.

  1. Evaluate with capture on. Turn on failure capture in an eval run. The final scene of every failed or timed-out episode is saved as a new environment package.
  2. Look at what was captured. A summary file lists each captured state with its episode, outcome and goal.
  3. Relabel. vecgen plans from the captured scene toward the recorded goal and executes it with the usual verified skills.
  4. Retrain and evaluate again. Annotate and merge the new episodes, add them to the training mix, and repeat.

In a small test on one RTX 5090, a random-action eval on a 16-episode stacking set captured 16 states, and vecgen recovered 12–13 of them in about 72 seconds.

Docs: TAMPER guide

Outputs

Each run scores every episode against its goal and writes per-step metrics and run summaries. Full rollouts, videos included, are recorded as a LeRobot dataset by default, in the same format as the training data. Any policy that can be served over a WebSocket can be evaluated by implementing a small policy-server interface.

Docs: eval metrics · scoring and outputs · adding a policy server

Running it

The quick start covers a small smoke-test run (10 episodes, one eval GPU, two environments) and a full run over a dataset, for each mode above.

Peak GPU memory we measured per process:

ProcessPeak VRAM
ManiFlow policy server2.9 GiB with 28 environments
Molmo 2 + ManiFlow policy server12.5 GiB with 4 environments, growing with more
Isaac Sim eval worker5.5 GiB with 4 environments, 10.2 GiB with 28

ManiFlow-only evals fit on a 16 GB card. Molmo 2 evals need about 24 GB, or two GPUs: the launcher puts the policy server on GPU 0 and the eval worker on GPU 1.

Docs: quick start · evaluation overview

← Data generationSim-to-real Toolkit →