The AY-Robots training matrix: five trainable policies as rows, four robot arms as columns, each cell linking to a specific training guide
MLOpsLeRobotDAggerImitation LearningDeployment

Record, Train, Deploy, Retrain: The Robot Policy Loop

AY-Robots ResearchAugust 23, 202616 min read

How to build the record, train, evaluate, deploy, retrain loop for an SO-100 arm: real LeRobot commands, DAgger-style failure collection, and what to automate first.

What you need to know

  • A single fine-tune is not a product. The unit of progress is one turn of a loop: record, train, evaluate, deploy, collect failures, retrain.
  • Expert-only data compounds error: a policy with error rate epsilon on the expert's states can make up to T squared times epsilon mistakes over a T-step episode under its own distribution.
  • DAgger fixes the data distribution, not the model: run your policy, correct the states it visits, retrain on the union of everything.
  • LeRobot on main ships this as a CLI. lerobot-rollout has a dagger strategy; lerobot-edit-dataset merges, splits and deletes episodes.
  • Automate the deterministic parts first: dataset revisions, GPU lifecycle, checkpoint upload, run metadata. Keep rollout scoring manual.
  • On AY-Robots the training and inference legs are automated: a form picks model plus dataset, the backend rents a GPU by required VRAM, and /api/inference/pod serves the policy back to the arm.

One fine-tune is not a system

Most people who train a first policy on an SO-100 do the same thing: record forty episodes, run a training job, load the checkpoint, watch the arm do something roughly correct, stop. Build that demo. But it is a single point measurement, and you want a slope.

The slope comes from repetition with feedback: deploy, watch it fail in a specific way, record data about that failure, retrain, deploy again. Each turn should cost less than the last, because the pure mechanism has been automated away. The rest of this is about which parts are mechanism.

What counts as one turn

A turn is complete when a checkpoint that did not exist yesterday is running on the arm and you can say in one sentence what it does better than the last. If you cannot say that sentence, you did not close the loop, you spent GPU money.

What a full turn contains

Six stages. The last column matters most: where a stage goes wrong decides whether automating it saves time or hides a bug.

StageWhat happensEffort per turnWhere it goes wrong
RecordTeleoperate, save episodes with camera and joint streams30 to 120 minInconsistent resets, drifting cameras
CurateDelete bad takes, fix task strings, merge earlier rounds10 to 30 minDeleting the episodes with the hard cases
TrainFine-tune a base VLA, or train a small policy from scratch2 to 6 h GPUWrong format version, no seed, checkpoints overwritten
EvaluateRun the checkpoint under a fixed protocol and score it20 to 60 minNo protocol, so scores do not compare across weeks
DeployServe the policy and let it run the task for realMinutesInference too far from the servos, control loop stalls
Collect failuresRecord what went wrong, with human corrections20 to 60 minRecording only successes, which teaches nothing
The AY-Robots training matrix with five policies as rows and four robot arms as columns, every cell linking to a specific guide
The /train matrix. One cell is one model-and-arm combination, which is the right granularity for one loop.

Why the loop exists: compounding error

Imitation learning from demonstrations is supervised learning on states the expert visited. At run time the policy visits states it causes. The moment it errs slightly it is somewhere the expert never was, and errors compound. Ross, Gordon and Bagnell formalized it: a classifier erring with probability epsilon under the expert's state distribution can make as many as T squared times epsilon mistakes over a T-step horizon under its own.

The bound in one line

Naive behavior cloning: cost grows quadratically in episode length T. DAgger, arXiv 1011.0686 (v1 November 2010, v3 March 2011): with iterations N on the order of uT, some learned policy costs at most the expert's cost plus u times T times the training loss, plus a constant. Linear in T. Not a better network, just training on the states the learner visits.

Practically: your first thirty episodes teach the happy path, the next thirty teach almost nothing. What moves the number is data in the states your checkpoint drifts into, which you only find by running it. That is why the loop closes, and why how you collect data beats how much you have.

Turn one: record the seed dataset

Everything starts with a LeRobot dataset. The desktop client from the download page records one out of a teleoperation session, and the recording tutorial walks it end to end. The commands below are from the LeRobot cheat sheet on main, checked 2026-08-24.

  1. 1
    Find the ports

    Once per arm. It asks you to unplug the USB cable, then prints the port that disappeared.

    bash
    pip install 'lerobot[training]'
    lerobot-find-port
    lerobot-find-cameras
  2. 2
    Calibrate leader and follower

    Put every joint roughly mid-range first. The --robot.id is the key LeRobot uses to find the calibration file later, so keep it stable.

    bash
    lerobot-calibrate \
        --robot.type=so101_follower \
        --robot.port=/dev/ttyACM0 \
        --robot.id=my_follower_arm
  3. 3
    Record the seed episodes

    Right arrow saves, left arrow deletes the take and retries, Escape stops and encodes. Use the left arrow generously: a bad take costs nothing now and a confusing loss curve later.

    bash
    lerobot-record \
        --robot.type=so101_follower \
        --robot.port=/dev/ttyACM0 \
        --robot.id=my_follower_arm \
        --robot.cameras="{ top: {type: opencv, index_or_path: 1, width: 640, height: 480, fps: 30}, wrist: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30} }" \
        --teleop.type=so101_leader \
        --teleop.port=/dev/ttyACM1 \
        --teleop.id=my_leader_arm \
        --dataset.repo_id=${HF_USER}/pick_block_r1 \
        --dataset.num_episodes=40 \
        --dataset.single_task="put the red brick in a bowl" \
        --display_data=true
The reset is part of the data

The most common cause of a policy that works in exactly one setup: every episode started from an identical scene. Vary object position and lighting, keep your hands out of frame. See policy only works in one setup.

The AY-Robots tutorial page for recording your first LeRobot dataset
/learn/record-your-first-dataset. The client writes the same layout the CLI does, which makes both halves of this article interchangeable.

Turn one: train, and the format trap

Now pick a model. The policies page lists the five trainable here, and the head-to-head pages cover the pairs people agonize over. For a first loop, start cheap: ACT and SmolVLA give turns of about 1 to 3 USD over 2 to 5 hours, so you can afford to be wrong. GR00T N1.7 and Pi0.5 cost 4 to 12 USD over 3 to 6 hours.

PolicyParamsMin episodesGPU tierPer action stepDataset format
ACT~80 M, from scratch50RTX 4090 / 24 GB20 msLeRobot v3.0
SmolVLA~450 M30RTX 4090 / 24 GB245 msLeRobot v3.0
GR00T N1.7~3 B, ~40 M trained50A100 / H100 80 GB152 msLeRobot v2.0 or v2.1
GR00T N1.5~3 B50A100 / H100 80 GB165 msLeRobot v2.0 or v2.1
Pi0.5~3 B, PaliGemma backbone50A100 / H100 80 GB485 msLeRobot v3.0
bash
# LeRobot main, checked 2026-08-24
lerobot-train \
    --dataset.repo_id=${HF_USER}/pick_block_r1 \
    --policy.type=act \
    --output_dir=outputs/train/act_r1 \
    --job_name=act_r1 \
    --policy.device=cuda \
    --policy.repo_id=${HF_USER}/act_pick_block_r1 \
    --steps=20000 \
    --wandb.enable=true

# resume from a checkpoint
lerobot-train --config_path=${HF_USER}/act_pick_block_r1 --resume=true
Policy types on main are act, diffusion, smolvla and pi05. To fine-tune an existing checkpoint, pass --policy.path and drop --policy.type.
The trap that eats a day: dataset format versions

A LeRobot v3.0 dataset crashes the GR00T loader, which wants v2.0 or v2.1. NVIDIA ships scripts/lerobot_conversion/convert_v3_to_v2.py in Isaac-GR00T for this, run from its own uv environment. The other direction is python -m lerobot.scripts.convert_dataset_v21_to_v30 --repo-id=<HF_USER/DATASET_ID>. Pin the format on turn one. See dataset rejected as v3.

Evaluate: the step nobody automates, and mostly should not

This is where homemade loops fall apart. LeRobot has lerobot-eval, but read its arguments: it takes --env.type and runs episodes in a simulator. There is no built-in scorer for a real arm, because scoring a real rollout means a human deciding whether the block ended up in the bowl. That judgement carries the information; automating it early means optimizing a proxy.

Standardize the protocol around the judgement instead, so two checkpoints a week apart are comparable. Change it only when you also re-score the old checkpoint.

Protocol elementFix it toWhy
Trial count20 trials, alwaysBelow 20, 60 versus 70 percent is noise
Start positionsA written list of 5, four trials eachOtherwise the new checkpoint gets easier starts
TimeoutFixed seconds per trialSucceeding after flailing is not succeeding
Outcome classessuccess / wrong grasp / missed grasp / stalled / collisionThe distribution tells you what to record next
Who scoresOne person, or video reviewed laterScoring while operating is not scoring
What gets loggedCheckpoint id, dataset revision, protocol version, outcomeSeparates data gains from hyperparameter gains
Score failure classes, not just the rate

The classes are the input to the next turn. Ten missed grasps means record wrist-camera data near the object. Ten stalls in one place means record recoveries from there. A success rate cannot tell you which. The failure mode index is organized the same way.

Deploy, and record what the policy does

Deployment used to be an afterthought in LeRobot. On main there is a dedicated CLI, lerobot-rollout, built around pluggable strategies whose names read like a list of what a deployment loop needs. On v0.5.1 you still use lerobot-record with a policy path, which is one reason to say which version you mean.

--strategy.typeWhat it doesUse it for
baseAutonomous rollout, no recordingChecking the checkpoint loads and moves
episodicEpisode-oriented recording with reset phasesRunning your evaluation protocol
sentryContinuous recording with auto-uploadLong unattended runs
highlightRing buffer plus a keystroke to saveRare failures, without hours of video
daggerHuman-in-the-loop, DAgger and RaC styleThe failure-collection stage
bash
# LeRobot main: run the checkpoint, take over when it drifts
lerobot-rollout \
    --strategy.type=dagger \
    --strategy.num_episodes=20 \
    --strategy.record_autonomous=true \
    --policy.path=${HF_USER}/act_pick_block_r1 \
    --robot.type=so100_follower \
    --robot.port=/dev/ttyACM0 \
    --teleop.type=so101_leader \
    --teleop.port=/dev/ttyACM1 \
    --dataset.repo_id=${HF_USER}/pick_block_dagger_r1 \
    --dataset.single_task="put the red brick in a bowl"

# slow VLAs: overlap inference with execution instead of pausing at chunk boundaries
lerobot-rollout \
    --strategy.type=base \
    --inference.type=rtc \
    --inference.rtc.execution_horizon=10 \
    --policy.path=${HF_USER}/my_pi05_policy \
    --robot.type=so100_follower \
    --robot.port=/dev/ttyACM0 \
    --task="put the red brick in a bowl" --duration=60
The dagger strategy writes a second dataset containing exactly the states your checkpoint got itself into. That dataset is the point of the exercise.
Latency decides where inference runs

The control loop here is 20 to 485 ms per action step, and public-internet round trips on top turn a working policy into a hesitant one. Remote inference suits slow pick-and-place, not fast reactive motion. Real-time chunking helps: Black, Galliker and Levine report precise tasks succeeding with delays above 300 ms, over 30 percent of the prediction horizon, and 20 percent faster motion than synchronous inference. A mitigation, not a licence to put the GPU on another continent. See inference latency and action chunking.

Collect failures: corrections beat more demonstrations

Classic DAgger asks the expert to label every visited state without giving the expert control, which is awkward with a physical arm. HG-DAgger (arXiv 1810.02890, Kelly and colleagues, 2018) has the human take over instead, because labelling without control degrades label quality through perceived actuator lag. That matches a leader-follower rig: the policy drives, you grab the leader when it goes wrong.

Intervention data versus more demonstrations
Advantages
  • It lands in the states your checkpoint actually reaches, the distribution the DAgger bound cares about
  • RaC (arXiv 2509.07953, September 2025) beats prior state of the art on three real bimanual tasks with 10 times less collection time and samples
  • Sirius (arXiv 2211.08416) reweights samples by approximated human trust and reports 8 percent higher success in simulation, 27 percent on real hardware
  • Each round doubles as an evaluation: the intervention rate is a number you can track
Trade-offs
  • It needs a human at the arm during the rollout, the expensive resource in the loop
  • Segments are short and unbalanced against long autonomous episodes, so naive merging drowns them out
  • Takeover moments are noisy: for a moment neither policy nor human is in control
  • The leader arm must be present at deploy time, which not every deployment allows
  • It biases the dataset toward the failures you happened to see that day

The RaC protocol is worth copying: when failure looks imminent, first rewind the arm to a state the policy handles, then drive the correct continuation. You teach recovery and correction at once, and recovery is what plain demonstration data never contains.

Retrain: merge, prune, rerun

Aggregation in DAgger is literal: train on the union, not the newest batch. LeRobot exposes the set operations as a CLI so you do not write dataset-surgery scripts, which is the glue code Sculley and colleagues warned about in 2015, estimating a mature system might be at most 5 percent machine learning code and 95 percent glue.

  1. 1
    Delete the takes you know are bad

    Before merging, and write down the indices. Deleting hard episodes because they look messy is the easiest way to stall a loop.

    bash
    lerobot-edit-dataset \
        --repo_id ${HF_USER}/pick_block_dagger_r1 \
        --operation.type delete_episodes \
        --operation.episode_indices "[3, 11, 17]"
  2. 2
    Merge round one with the intervention data

    Merging writes a new dataset instead of mutating the inputs, so earlier rounds stay reproducible.

    bash
    lerobot-edit-dataset \
        --new_repo_id ${HF_USER}/pick_block_r2 \
        --operation.type merge \
        --operation.repo_ids "['${HF_USER}/pick_block_r1', '${HF_USER}/pick_block_dagger_r1']"
  3. 3
    Hold out a split you never train on

    No substitute for real rollouts, but it catches a merge that broke something.

    bash
    lerobot-edit-dataset \
        --repo_id ${HF_USER}/pick_block_r2 \
        --operation.type split \
        --operation.splits '{"train": 0.9, "val": 0.1}'
  4. 4
    Retrain from base, not last week's checkpoint

    Chaining fine-tunes accumulates drift you cannot audit. Going back to base costs a few dollars and keeps every checkpoint traceable to one dataset revision.

    bash
    lerobot-train \
        --dataset.repo_id=${HF_USER}/pick_block_r2 \
        --policy.type=act \
        --output_dir=outputs/train/act_r2 \
        --job_name=act_r2 \
        --policy.device=cuda \
        --steps=20000

The same loop, two ways

All of the above runs on your own GPU or a box you rent. Right choice if you want to modify the trainer, if the data cannot leave the building, or if you have idle cards.

  1. Install with extras. Since v0.6.0, pip install lerobot no longer pulls dataset or training dependencies; add lerobot[training].
  2. Pin a version. v0.6.0 replaced GR00T N1.5 with N1.7, so pin lerobot==0.5.1 for N1.5, and renamed --dataset.vcodec to --dataset.rgb_encoder.vcodec.
  3. Record, train, deploy and aggregate with lerobot-record, lerobot-train, lerobot-rollout and lerobot-edit-dataset.
  4. Build your own run registry. Nothing in the CLI records which dataset revision produced which checkpoint.
  5. Provision and destroy GPUs yourself. An idle rented GPU bills like a busy one.
bash
# minimal run registry: one JSON line per turn
cat >> loop.jsonl <<'EOF'
{"turn": 2, "dataset": "user/pick_block_r2", "policy": "act", "steps": 20000, "ckpt": "outputs/train/act_r2/checkpoints/last", "protocol": "v1", "success": "13/20"}
EOF
GR00T runs are not reproducible

GR00T's fine-tuning entry point (gr00t/experiment/launch_finetune.py in Isaac-GR00T, a tyro CLI) exposes no seed. LeRobot's default seed is 1000. Comparing two GR00T checkpoints, part of the gap is just the run.

What to automate first, and what to keep manual

General MLOps answered the ordering question. Google's maturity model runs level 0 (all manual, predictions never logged), level 1 (training pipeline automated, triggered by schedule, new data or drift), level 2 (CI/CD for the pipeline code too). The useful part is the order: pipeline automation before deployment automation, logging before either.

Part of the loopAutomateReason
Dataset revisionsFirstDeterministic, and every later question depends on it
GPU provisioning and teardownFirstDeterministic, and forgetting it costs money
Checkpoint upload and namingFirstManual naming is where runs get lost
Training launch with fixed defaultsFirstA form or script beats retyping flags
Merging and pruning datasetsSecondMechanical, but deciding what to prune is not
Running the evaluation protocolSecondAutomate the sequence of trials, not the scoring
Scoring rolloutsLate or neverThis is the signal; a proxy replaces your objective
Deciding what to record nextNeverThis is the entire skill
The AY-Robots CLI page showing the install command and the commands for running platform operations from a terminal
/cli. The same operations in a terminal are what turn the deterministic half of the loop into a script you can schedule.
  • Same input, same output: automate it now.
  • Someone must look at a robot and form an opinion: leave it manual, automate the scaffolding.
  • Cheap to run, expensive to get wrong: automate it and log every input, so you can reconstruct it.
  • Log the boring metadata on turn one: dataset revision, checkpoint path, protocol version, per-trial outcome. One JSON line, one afternoon saved.

A maturity ladder for one arm on one desk

RungWhat is automatedCost per turnSignal you are here
0Nothing. Commands by hand, folders named final and final2A day, mostly bookkeepingYou cannot say which dataset produced the running checkpoint
1Training launch, GPU lifecycle, checkpoint storage, dataset revisionsAn afternoon, mostly recording and scoringYou can rerun last week's training with one command
2Plus dataset merge and prune, a scripted evaluation sequence, a run logTwo hours of human timeYou can plot success rate against turn number and trust it
3Plus retraining triggered when new intervention data landsUnder an hour, plus scoringSeveral tasks or people; coordination costs more than automation

Most single-arm projects should aim for rung two and stop. If you have not built rung one, train your first policy and then run it on the arm.

Where this breaks down, including here

  • There is no real-world evaluator. Not in LeRobot, not here. lerobot-eval runs in simulation. Every success rate above was counted by a person watching an arm.
  • Latency is physics. Cloud inference at 152 to 485 ms per action step plus a public round trip suits slow pick-and-place, not fast reactive motion. Only moving compute next to the servos changes it.
  • DAgger assumes a competent expert on demand. On a real desk the expert is you at 9 pm, and the quality of your 9 pm corrections is now in the dataset.
  • Format churn is real. GR00T needs v2.1 while Pi0.5 and SmolVLA want v3.0, and v0.6.0 renamed flags older tutorials still print.
  • Automating too early hides regressions. A loop that retrains nightly and is never watched converges on something worse, and you hear it from a user, not a metric.

None of that argues against the loop. It argues for building the boring parts properly and keeping a person in the judging part. No hardware yet? The live arm runs with no signup, and the arena has 85 VLA models with 332 benchmark results. See also the SO-100 guide and what a VLA is.

Start turn one on your own arm

Pick a model and a robot, get the exact commands and defaults for that combination, and rent the GPU for the length of the run. A cheap-tier run costs about 1 to 3 USD.

Open the training guides
How many episodes before the first training run?

The minimums here are 30 episodes for SmolVLA and 50 for ACT, GR00T N1.5, GR00T N1.7 and Pi0.5. Those are floors for the trainer, not targets for a working policy. Treat turn one as a calibration of your recording quality.

Retrain from base, or continue from my last checkpoint?

From base, almost always. Chaining fine-tunes makes each checkpoint depend on the whole run history, which you cannot audit. Retraining from base costs about 1 to 3 USD on the 24 GB tier and 4 to 12 USD on the A100 or H100 tier, and keeps every checkpoint traceable to one dataset revision.

Is DAgger still relevant now that VLAs are pretrained on huge datasets?

Yes, because it solves a distribution problem, not a capacity problem. A pretrained backbone reduces how much task data you need; it does not stop your policy drifting into states your demonstrations never covered. RaC matched prior state of the art in 2025 with 10 times less collection time.

Can I run the whole loop with the policy served from the cloud?

For slow pick-and-place, yes. For fast reactive motion, no. The control loop is 20 to 485 ms per action step before any network. Real-time chunking mitigates chunk-boundary pauses but does not remove the round trip.

What is the minimum bookkeeping for turn one?

One append-only file with, per turn: dataset revision, policy type and hyperparameters, checkpoint path, protocol version, per-trial outcomes. Enough to separate a data improvement from a hyperparameter one three turns later.

Which LeRobot version do these commands target?

LeRobot main as of 2026-08-24, after v0.6.1 (2026-08-03). On v0.5.1 (2026-04-07) there is no lerobot-rollout; you use lerobot-record with a policy path. v0.6.0 replaced GR00T N1.5 with N1.7 and made dataset and training dependencies optional extras.

Ready for high-quality robotics data?

AY-Robots connects your robots to skilled operators worldwide.

Get Started