The AY-Robots arena leaderboard, a sortable table of vision-language-action models and their benchmark results with each value linked to its source
EvaluationBenchmarkingRobot LearningStatisticsVLASO-100

Benchmarking Your Own Robot Task: Trials, Randomisation, Reporting

AY-Robots ResearchAugust 23, 202625 min read

How many rollouts a robot benchmark really needs, how to randomise starting conditions reproducibly, what to freeze between policies, and how to report a success rate someone can check.

A benchmark is not a number you produce at the end of a training run. It is a procedure you write down before you run anything, that another person could follow and get roughly the same answer. Most people skip the writing-down part, run twelve rollouts, get eight successes, and tell everyone the policy is at 67 percent. That number is close to meaningless, and this article is about why, and what to do instead.

The good news is that an honest benchmark for one task on one SO-100 is mostly bookkeeping: a fixed list of starting conditions, a written success rule, a frozen configuration, and the habit of reporting raw counts instead of a percentage. The expensive part is trial count, so that is where this starts.

What you need to know

  • Ten trials is not a measurement. At an observed 70 percent success rate the 95 percent Wilson interval on 10 trials runs from 39.7 to 89.2 percent. On 50 trials it is 56.2 to 80.9 percent.
  • Comparing two policies costs far more than measuring one. Resolving a real 60 vs 80 percent gap at 80 percent power takes about 81 trials per policy; 70 vs 80 percent takes about 292.
  • Published protocols are smaller than people assume: ACT ran 25 real-world trials per task, pi0.5 ran 10 evaluations per task, RoboChallenge runs 10 rollouts per task. All of them say so in the paper.
  • Pair the trials. RoboArena requires both policies to run back to back from closely matched initial conditions, and on the McNemar numbers below that cuts the rollout budget by roughly a third.
  • Randomise the starting conditions, but from a written list, with a seed. Randomisation you cannot reproduce is noise you cannot audit.
  • Report counts, not percentages: 18/25, not 72 percent. On 25 trials the metric can only land on multiples of 4 percentage points.
  • Freeze the inference configuration alongside the checkpoint. Image preprocessing, chunk size, control rate and where inference physically runs all change the result.

Why a leaderboard number cannot answer your question

The AY-Robots arena lists 85 vision-language-action models with 332 benchmark results, and every value links back to the paper or model card it came from. That is useful for orientation. It cannot tell you what a fine-tuned checkpoint will do on your table, with your lighting, your gripper and your task. Different embodiment, different objects, different success rule, different operator.

The SIMPLER paper makes the same point from the other direction. Ranking six open-source policy checkpoints on Google Robot tasks, validation mean squared error reached an average Pearson correlation of only 0.308 with real-world performance, while their visual-matching simulated evaluation reached 0.924. The loss curve you watch during training is a poor predictor of the ranking you care about, which is why you have to run the robot.

The AY-Robots arena page showing a sortable table of vision-language-action models with benchmark results, each value linked to its source paper
The arena is 85 models and 332 benchmark results, each linked to its source. It is context for choosing a starting point, not a prediction of what your checkpoint does on your bench.

It also helps to see how small real published protocols are. People assume the numbers in VLA papers rest on thousands of rollouts. In the real-robot sections they usually do not.

ProtocolTrialsSettingReported as
ACT / ALOHA (Zhao et al., 2023)25 per task, one seedReal robot, 6 tasksSuccess rate per task and per sub-stage
ACT / ALOHA, simulated tasks50 per seed, 3 seedsMuJoCoMean over seeds
OpenVLA on LIBERO50 rollouts per task, 10 tasks, 3 seedsSimulation, 500 rollouts per seed per suiteLIBERO-Spatial 84.7 +/- 0.9 percent, standard error over the 3 seeds
pi0.5 (Physical Intelligence, 2025)10 evaluations per task per policyReal homes and mock homes, 12 locationsPercent of rubric points, partial credit
SIMPLER, pick coke can75 (3 orientations x 25 grid positions)Real and simulated, pairedSuccess rate plus MMRV and Pearson r against real
RoboChallenge Table3010 rollouts per task, 30 tasksReal robots, online submissionSuccess rate plus a 0 to 100 progress score
RoboArenamore than 600 pairwise episodes, 7 policiesDROID arms at 7 institutionsTask-aware ranking from double-blind pairwise preferences

Two things stand out. First, the per-condition sample sizes are small, often 10 to 25. Second, almost none of these report a confidence interval on a single policy's success rate. PhAIL, a 2026 preprint that benchmarks four public VLAs on a Franka FR3, opens by describing the field in exactly those terms: real-world VLA evaluation still rests on binary success rate at a fixed timeout with 25 or fewer rollouts per condition, almost always without confidence intervals or paired statistical comparison. That is the paper's own framing of the status quo rather than a counted survey, but it matches the table above. Copy the field's habits and you inherit the field's uncertainty.

How many trials you actually need

Success on a rollout is a coin flip with an unknown bias. That makes the statistics simple and unforgiving. The table below is a 95 percent Wilson score interval for an observed 70 percent success rate at different trial counts. Wilson rather than the textbook Wald interval because Brown, Cai and DasGupta showed in Statistical Science in 2001 that the Wald interval's coverage is erratic and recommended Wilson or Jeffreys for small samples; the NIST/SEMATECH e-Handbook gives the same formula in section 7.2.4.1.

TrialsSuccessesObserved95% Wilson intervalInterval width
10770.0%39.7% to 89.2%49.5 pp
201470.0%48.1% to 85.5%37.3 pp
251872.0%52.4% to 85.7%33.3 pp
302170.0%52.1% to 83.3%31.2 pp
503570.0%56.2% to 80.9%24.6 pp
1007070.0%60.4% to 78.1%17.7 pp
20014070.0%63.3% to 75.9%12.6 pp
50035070.0%65.8% to 73.9%8.0 pp
python
# pip install statsmodels
from statsmodels.stats.proportion import proportion_confint

for n in (10, 20, 25, 30, 50, 100, 200, 500):
    k = round(0.70 * n)
    lo, hi = proportion_confint(k, n, alpha=0.05, method="wilson")
    print(f"{k}/{n}  [{lo*100:5.1f}, {hi*100:5.1f}]  width {100*(hi-lo):4.1f} pp")
Reproduce the table above. Swap method="beta" for the Clopper-Pearson interval, which is wider and more conservative.
A perfect score on a short run is not a perfect policy

10 successes out of 10 gives a 95 percent Wilson interval of 72.2 to 100 percent. 25 out of 25 gives 86.7 to 100 percent. A flawless short demo is compatible with a policy that fails one attempt in four. This is the single most common way a demo video misleads the person who recorded it.

Comparing two policies costs much more than measuring one

Measuring one policy roughly is cheap. Deciding which of two checkpoints is better is not, because you are now stacking two noisy estimates. The numbers below are for a standard two-proportion test, two-sided, alpha 0.05, 80 percent power, independent trials for each policy.

True gap you want to detectTrials per policyTotal rollouts
50% vs 70%93186
60% vs 80%81162
70% vs 90%60120
80% vs 90%195390
70% vs 80%292584
50% vs 60%388776

Read the last two rows again. A ten-point improvement, the size most fine-tuning changes actually produce, needs hundreds of rollouts per policy with independent trials. If your budget is 20 rollouts per checkpoint, you cannot resolve ten points, and your notes should say so.

The mirror-image question is more useful in practice: how often will a short evaluation rank the worse policy higher? Suppose the true rates are 60 and 70 percent, and you run n trials of each.

Trials per policyWorse policy scores higherExact tieFails to show the right order
1023.9%16.6%40.5%
2020.2%10.6%30.7%
2518.5%8.9%27.5%
5012.3%4.8%17.1%
1005.9%2.0%7.9%
Granularity is part of the honesty

On 25 trials one rollout is 4 percentage points; on 10 trials it is 10 points. Every real-world success rate in Table II of the ACT paper is a multiple of 4, ACT's own row running 100, 96, 92, 84, 72, 64, 40 and 20, because they ran one seed and 25 trials. Reporting 18/25 instead of 72 percent makes that resolution visible for free.

Define success before you run anything

Half the disagreements about a benchmark are definitional, not statistical. Write the success rule down first, in a form an unfamiliar person could apply from the video alone, and never edit it after seeing results.

  • Terminal state: the cube is inside the bin footprint and the gripper has released it. Not 'roughly in the bin'.
  • Tolerance: fully inside the printed rectangle counts, touching the rim does not.
  • Time limit: 60 seconds of wall clock, or a fixed number of control steps. Say which, because the two diverge when inference latency changes.
  • Retries: does a second grasp attempt after a slip still count as success? Decide before, not after.
  • Abort conditions: what stops the rollout early and how that outcome is scored. Hitting a joint limit is a failure, not a discarded trial.
  • Who scores it: one named person, or a video reviewed later by someone blind to which policy ran.

Binary success throws away most of what you saw

A binary outcome on 25 trials is a low-bandwidth measurement, and every serious recent protocol adds partial credit. RoboChallenge splits each task into stages worth 10 progress points per rollout, runs 10 rollouts per task so a task totals 100 points, deducts 0.5 progress points for each retry, and terminates the rollout once the number of successive failed retries exceeds four. pi0.5 scores against a rubric that roughly corresponds to the percentage of steps completed, so placing half the dishes in the sink scores around 50. RoboArena asks evaluators for a continuous progress score from 0 to 100 alongside the binary preference.

MetricWhat it capturesCostWhen to use it
Binary successDid the task completeFreeAlways. It is the number people compare.
Stage progress (0 to 10)How far it got before failingDefine stages onceLong-horizon tasks where most failures are late
Retry countFumbling that still succeedsOne tally per rolloutTasks where a clumsy success is not a good success
Time to successSpeed, and whether it hesitatesA stopwatch or a log timestampComparing a local run against a remote pod
Failure categoryWhere the policy breaksA short tag per rolloutChoosing what to fix next

The failure category is the field you will thank yourself for. Tags like 'missed grasp', 'grasped then dropped', 'wrong object', 'froze' or 'collided' turn 25 rollouts into a debugging plan, and the failure-mode pages split along roughly those lines: a policy that freezes mid-motion and a gripper that does not close are different problems even when both show up as a zero in the success column.

The AY-Robots fix index listing common robot failure modes such as arm not detected, gripper does not close, policy freezes mid-motion and policy only works in one setup
Tagging each failed rollout with a category turns a success rate into a work list. The fix index is a reasonable starting taxonomy.

Randomisation you can reproduce

There is a real tension here. If every trial starts from an identical cube position you are measuring one point in the task distribution, and the number will not survive a slightly different Tuesday. If every trial starts wherever you happened to drop the cube, the evaluation is not repeatable and, worse, it is manipulable. The RoboChallenge team measured this: they compared experienced testers who had collected the training data, ignorant testers who only read the task description, and adaptive testers who were the model authors and placed objects strategically based on how previous runs had gone. Their summary of real-machine testing is blunt: with the same props, task and model, the measured success rate can change even from 0 to 100 percent.

The fix is a written condition grid. Enumerate the factors you want to vary, take the product, and sample from that list with a fixed seed. SIMPLER does this explicitly: pick coke can is 3 orientations times 25 marked grid positions for 75 trials; move object near object is 5 object triplets times 2 triangle patterns times 6 role assignments for 60 trials; the drawer tasks are 9 robot base positions times 3 drawers times 2 directions for 54 trials. Nothing is left to the operator's judgement in the moment.

  1. 1
    Write the condition grid

    Pick two or three factors that matter for your task and enumerate their levels. Tape a grid onto the work surface and label the cells, so a position is a name and not a guess.

    python
    import itertools, random
    
    positions    = ["A1", "A2", "B1", "B2", "C1", "C2"]   # taped cells on the mat
    orientations = ["flat", "upright"]
    distractor   = [False, True]
    
    conditions = list(itertools.product(positions, orientations, distractor))  # 24 cells
    trials = conditions * 2                                                   # 48 trials
    random.Random(1000).shuffle(trials)                                       # fixed seed
    
    print("trial,position,orientation,distractor")
    for i, (pos, ori, dis) in enumerate(trials, start=1):
        print(f"{i:03d},{pos},{ori},{int(dis)}")
    
  2. 2
    Print the sheet and follow it

    Print the 48 lines and work down the list. The order is randomised so that anything drifting across the session, servo temperature, daylight through a window, your own fatigue, is spread across conditions instead of piling into the last ten trials.

    bash
    python make_trials.py > trials_2026-08-24.csv
    head -4 trials_2026-08-24.csv
    # trial,position,orientation,distractor
    # 001,B2,flat,1
    # 002,A1,upright,0
    # 003,C1,flat,0
    
  3. 3
    Reproduce the scene, do not eyeball it

    RoboChallenge superimposes a reference image on the live camera stream and asks the tester to move objects until the images match. You can do the same with a still frame and any camera viewer: it is the cheapest reproducibility tool in this whole article.

    bash
    # capture the reference frame for one condition, once
    ffmpeg -f avfoundation -framerate 30 -i "0" -frames:v 1 ref_B2_flat.png
    
    # later, overlay the reference at 50 percent on the live view while you reset the scene
    ffplay -f avfoundation -framerate 30 -i "0" \
      -vf "movie=ref_B2_flat.png[r];[in][r]blend=all_mode=average"
    
  4. 4
    Log the trial before you run it

    Write down the condition and the checkpoint identifier before the rollout starts, not after you have seen the outcome. This is the difference between a record and a memory.

    json
    {"trial": 17, "policy": "act_so100_ckpt100000", "grid_seed": 1000,
     "position": "B2", "orientation": "flat", "distractor": true,
     "operator": "pk", "started_at": "2026-08-24T14:05:11Z",
     "outcome": "fail", "stage_reached": 2, "stages_total": 4, "retries": 1,
     "time_to_success_s": null, "timeout_s": 60,
     "failure_tag": "grasped_then_dropped", "notes": "caught the rim, slipped"}
    
The seed is part of the protocol

Publish the seed with the results. LeRobot uses 1000 as its default seed in EvalPipelineConfig, and OpenVLA's LIBERO evaluation script defaults to --seed 7. A seed that lives only in your shell history is not a protocol, and re-running the same trial order later is how you separate a real regression from a bad afternoon.

What to hold fixed

Everything not in the condition grid must be pinned, written down and re-checked between policies. None of the items below show up in the success column when they go wrong; they just quietly make the comparison meaningless. Two of them, the action chunking settings and the inference latency you actually run at, change the controller itself rather than the weights.

Hold fixedWhy it moves the numberHow you pin it
Checkpoint identityTwo checkpoints from one run behave differentlyFull path plus step count in every trial record
Normalisation statisticsMismatched stats produce plausible but wrong actionsShip the stats file with the checkpoint, never regenerate at eval time
Image preprocessingOpenVLA needs --center_crop True at eval because it trained on a random 90 percent-area crop of every sampleRecord the exact preprocessing flags next to the checkpoint
Action chunk settingsACT defaults to chunkSize 100 and nActionSteps 100 here; changing either changes the controllerFreeze both, and report them
Control rateThe same policy at a different loop rate is a different controllerLog the achieved rate, not the intended one
Where inference runs20 ms locally versus a public-internet round trip is a different systemState local or remote pod in the report
Camera pose and lensA bumped wrist camera invalidates every trial after itPhotograph the rig at the start and end of the session
LightingDaylight drifts across a sessionBlinds down, one lamp, fixed exposure and white balance
Instruction stringThe language token stream is an inputCopy-paste it, never retype it
Battery and supplySTS3215 servos on the SO-100 run at 7.4 V and torque changes as supply sagsOne bench supply, checked before the session
The trap that eats a day: benchmarking on the pod, deploying on the bench

AY-Robots can auto-provision a cloud GPU pod that serves your policy to the robot client. That is a fine way to run a policy without a local GPU, but the control loop is already 20 to 485 ms per action step depending on the model, and public-internet round trips land on top of that. A benchmark run against a remote pod and a deployment run locally are two different systems. Measure the one you intend to ship, and if you must measure both, treat them as two rows in the table rather than one number. This is a real limit: remote inference is viable for slow pick and place and not viable for fast reactive motion.

One thing you cannot hold fixed is worth naming. The GR00T N1.7 fine-tuning entry point, the tyro CLI in Isaac-GR00T's launch_finetune.py, exposes no seed argument, so GR00T runs are not bit-for-bit reproducible and trainer variation becomes part of the noise in your comparison. LeRobot does expose a seed and defaults it to 1000, so ACT, SmolVLA and Pi0.5 runs can at least be repeated. If you are comparing two GR00T checkpoints trained on the same data, some of the difference you measure is the trainer, not your change.

Pair the trials and blind the operator

The cheapest way to buy statistical power is to stop running two independent batches. RoboArena is explicit about it: the evaluator arranges a scene, is handed two anonymous policy endpoints, runs A and B back to back, and is required to closely match the initial conditions within that pairwise comparison, though conditions may change freely between comparisons. pi0.5 does the same by holding the set of items constant for both policies within a comparison. Pairing removes scene-to-scene variance, and a paired test then only looks at the trials where the two policies disagreed.

DesignTo detect a 20-point gap at 80% powerTotal rollouts
Independent batches, 60% vs 80%81 per policy162
Paired, policies disagree on 24% of trials45 paired trials90
Paired, policies disagree on 30% of trials57 paired trials114
Paired, policies disagree on 40% of trials77 paired trials154
Paired, policies disagree on 50% of trials96 paired trials192

The paired numbers come from the McNemar sample-size formula and depend on how often the two policies differ on the same scene. Two similar checkpoints agree often, so pairing wins big. Either way you avoid the failure mode where policy A was evaluated in the morning and policy B after the sun moved.

Paired A/B against independent batches
Why pairing wins
  • Removes scene, lighting and operator drift from the comparison, because both policies see the same scene within seconds of each other.
  • Needs meaningfully fewer rollouts for the same power when the policies are similar, which is the usual case when you are iterating.
  • Makes blinding easy: the operator resets the scene, a script picks which endpoint answers, and the operator does not know which one ran.
  • Gives you a per-scene record, so you can watch the two videos side by side for the trials where they disagreed.
What it costs you
  • Does not give a clean absolute success rate for either policy, because the paired scenes are not a random sample of anything.
  • Requires swapping checkpoints between every pair, which on cloud inference means either two live endpoints or a slow reload.
  • Only compares the policies you paired. Adding a third checkpoint later means re-running, not appending.
  • Scene reproduction has to be genuinely good, or you have paid the cost of pairing without getting the variance reduction.
Blinding is not paranoia

RoboChallenge's comparative protocol has the tester prepare the initial state, then a randomly selected model is called, and the tester oversees the run without knowing which model is running. They adopted it because they watched model authors place objects strategically based on previous results. You are the model author. A ten-line wrapper that shuffles which of two endpoints answers is enough, and it costs you nothing.

Two ways to run this

Everything above works with a printed sheet, a text file and open-source tooling. If your task also exists as a simulated gym environment, LeRobot ships a runner that does the bookkeeping. Read on the main branch at version 0.6.2 on 2026-08-24, lerobot-eval defaults to n_episodes 50, auto-tunes batch_size from the CPU count, seeds at 1000 through EvalPipelineConfig, and writes an aggregated pc_success plus a per-episode record carrying each episode's seed. Those are upstream defaults; the trainer on this platform pins lerobot 0.5.1 for Pi0.5, so check the version you actually run before quoting a default.

bash
# the evaluation extra alone is not enough: you also need the policy extra
# (e.g. lerobot[pi]) and, for a simulated env, the env extra (e.g. lerobot[pusht])
pip install 'lerobot[evaluation,pusht]'

lerobot-eval \
  --policy.path=outputs/train/my_run/checkpoints/100000/pretrained_model \
  --env.type=pusht \
  --eval.n_episodes=200 \
  --eval.batch_size=50 \
  --seed=1000 \
  --policy.device=cuda
lerobot-eval needs a simulated environment. There is no equivalent command for a real SO-100 task, which is exactly why the trial sheet exists.
There is no real-robot eval command

This is the honest gap in the open-source stack. lerobot-eval and OpenVLA's run_libero_eval.py both assume a simulator that can reset itself. On a physical arm the reset is a human hand, and no tool automates that. Budget the wall-clock time: 100 paired rollouts at 60 seconds each plus resets is most of a working day.

bash
# the simulated reference protocol, for comparison
git clone https://github.com/openvla/openvla.git
python experiments/robot/libero/run_libero_eval.py \
  --model_family openvla \
  --pretrained_checkpoint openvla/openvla-7b-finetuned-libero-spatial \
  --task_suite_name libero_spatial \
  --center_crop True
# defaults: num_trials_per_task=50, seed=7, num_steps_wait=10
# 10 tasks x 50 rollouts = 500 trials per suite, averaged over 3 seeds
OpenVLA's LIBERO runner with the defaults it ships. The README states why center_crop matters: the model was fine-tuned on a random 90 percent-area crop of every training sample, so evaluation takes the centre 90 percent.
  1. Write the success rule and the condition grid in a file, and commit it before the first rollout.
  2. Generate the randomised trial sheet with a fixed seed and print it.
  3. Freeze the checkpoint, the normalisation statistics and every preprocessing flag.
  4. Run paired A/B rollouts with the operator blind to which endpoint answered.
  5. Record counts, stage progress, retries and a failure tag per trial.
  6. Report k/n with a Wilson interval, and publish the seed and the sheet.

Reporting a result someone else can check

A benchmark result is a claim, and a claim needs enough attached information for a reader to decide whether to believe it. If you cannot fill in a row, say so rather than letting the reader assume.

FieldExampleWhy it belongs
Raw counts18/25 and 21/25Percentages hide the trial count and the granularity
Interval72.0% (95% Wilson 52.4 to 85.7)Says what the number cannot rule out
Arm and serialSO-100, unit 2, calibrated 2026-08-20Two arms of the same model are not the same arm
Checkpointact_so100 run 4a1f, step 100000Identifies the exact weights
Training seed1000, or 'GR00T, no seed exposed'Names the reproducibility you have and the kind you do not
Condition grid and seed6 positions x 2 orientations x 2 distractors, shuffle seed 1000Lets someone regenerate your trial order
Success ruleCube fully inside the rectangle, gripper open, within 60 sEnds the definitional argument before it starts
Inference locationLocal, 20 ms per action stepA remote pod measures a different system
Operator and blindingOne operator, blind to endpointSays whether the number could have been nudged
Session and date2026-08-24, 14:00 to 17:30, blinds downDrift within and between sessions is real

Two conventions from outside robotics are worth stealing. Agarwal and colleagues, writing about deep reinforcement learning in 2021, argued that with few runs the interquartile mean with stratified bootstrap confidence intervals beats a bare mean, and that performance profiles beat single numbers. And OpenVLA reports 84.7 +/- 0.9 percent on LIBERO-Spatial, where the interval is a standard error across three training seeds of 500 rollouts each rather than a spread over rollouts. Those are two different uncertainties: rollout noise says how well you measured this checkpoint, seed noise says how much of a difference is the trainer.

The AY-Robots training matrix on the train page, with five policy models as rows and four robot arms as columns, each cell linking to a specific training guide
If your benchmark is going to compare two policy families, the training matrix is where you pin down the exact configuration each one runs with before you start counting rollouts.

A worked protocol for one SO-100 pick and place

Putting it together for a concrete case: you have fine-tuned ACT on a LeRobot dataset of roughly 60 episodes recorded through teleoperation, and you want to know whether a second checkpoint trained on 120 episodes is actually better.

  1. 1
    Decide what gap is worth detecting

    Be honest before you start. If you only care about improvements of 20 points or more, 45 to 60 paired trials will do. If you want to resolve 10 points, the paired budget is over 200 trials and you should probably spend that time collecting more data instead.

    text
    target gap        20 points (60% -> 80%)
    design            paired A/B, matched scene
    expected disagreement  ~30% of trials
    budget            57 paired trials = 114 rollouts
    at 60 s + 30 s reset   about 3 hours of bench time
    
  2. 2
    Pin the configuration

    Write both checkpoints, both sets of normalisation statistics, and the chunk settings into one file. ACT on this platform defaults to chunkSize 100 and nActionSteps 100; if the two checkpoints do not share those values you are comparing two controllers, not two datasets.

    yaml
    policy_a:
      name: act_so100_60ep
      checkpoint: run-4a1f/step-100000
      chunk_size: 100
      n_action_steps: 100
      seed: 1000
    policy_b:
      name: act_so100_120ep
      checkpoint: run-9c02/step-100000
      chunk_size: 100
      n_action_steps: 100
      seed: 1000
    inference: local        # 20 ms per action step for ACT
    instruction: "pick up the red cube and place it in the bin"
    
  3. 3
    Run the sheet

    For each line: reset the scene against the reference image, start the wrapper that randomly picks A or B, run, score, then run the other policy from the same reset. Two rollouts per line, one line per scene.

    bash
    while read -r line; do
      echo "scene: $line"
      read -rp "scene matched to reference? [enter]" _
      ./run_pair.sh --config bench.yaml --trial "$line" >> results.jsonl
    done < trials_2026-08-24.csv
    
  4. 4
    Count the disagreements, not the totals

    The paired comparison lives entirely in the trials where one policy succeeded and the other failed. Everything else cancels.

    python
    import json
    from statsmodels.stats.contingency_tables import mcnemar
    
    rows = [json.loads(l) for l in open("results.jsonl")]
    b = sum(1 for r in rows if r["a"] and not r["b"])   # A wins the scene
    c = sum(1 for r in rows if r["b"] and not r["a"])   # B wins the scene
    n11 = sum(1 for r in rows if r["a"] and r["b"])
    n00 = sum(1 for r in rows if not r["a"] and not r["b"])
    
    print(f"both {n11}  neither {n00}  A only {b}  B only {c}")
    print(mcnemar([[n11, b], [c, n00]], exact=True))
    
  5. 5
    Write the result down in full

    One paragraph with counts, interval, configuration and seed. If the paired test does not reach significance, say that, and say what gap your sample size could have detected. A null result you can trust is more useful than a positive result you cannot.

    text
    ACT/SO-100 pick-and-place, 2026-08-24, unit 2, local inference.
    57 paired scenes, grid seed 1000, blind endpoint selection, one operator.
    A (60 episodes): 34/57 = 59.6% (95% Wilson 46.7 to 71.3)
    B (120 episodes): 44/57 = 77.2% (95% Wilson 64.8 to 86.2)
    Discordant: A only 4, B only 14. McNemar exact p = 0.031.
    Powered to detect a 20-point gap; a 10-point gap would not have shown.
    

One caution about which weights you pick. Running the benchmark on eight checkpoints at 25 trials each and reporting the best is the same mistake as tuning on the test set: you have selected for luck. Screen on a small pass, benchmark the survivor properly, and say in the report that you did it that way.

Where this stops being worth it

Honest benchmarking has a point of diminishing returns, and knowing where it is saves you weeks. If your policy is at 20 percent, you do not need statistics, you need better data or a different setup; the data collection guide is a better use of an afternoon than 200 rollouts. If your policy works in exactly one lighting condition, that is a known failure pattern with a known set of causes, described on the page about policies that only work in one setup, and a bigger trial count will only measure it more precisely.

Rigorous evaluation pays off at the margin: when two options look similar and you have to choose, when you are about to spend real money scaling a dataset, or when someone outside your team will act on the number. Work on making it cheaper is active. SureSim combines large-scale simulation with a small number of real trials using prediction-powered inference and reports saving over 20 to 25 percent of hardware evaluation effort for similar bounds; RoboArena found its crowd-sourced ranking converged within roughly 100 pairwise comparisons. Neither removes the need to run the robot.

Related reading on this site

Not trained the policy yet? Start with train your first policy and ACT on the SO-100. If it trains but does nothing useful, see loss falls, policy does nothing, and for background the VLA overview and the complete SO-100 guide.

How many trials is the minimum for a benchmark I can quote?

For a single policy, 25 to 50 trials gives a Wilson interval roughly 25 to 33 percentage points wide at a mid-range success rate, which is enough to say whether the policy works reliably at all. For comparing two policies, 25 trials each fails to show the correct order about 27 percent of the time when the true gap is 10 points, so use a paired design and budget 50 or more paired scenes. Below 20 trials you are reporting an anecdote and should label it as one.

Should I report a percentage or a fraction?

Both, with the fraction first. 18/25 (72 percent) gives the reader the trial count, the granularity and the estimate in one string. A percentage alone hides the fact that on 25 trials the metric can only move in steps of 4 points, which is why every real-world number in the ACT paper's tables is a multiple of 4.

Do I need a simulator to benchmark properly?

No, but a simulator changes the economics. OpenVLA's published LIBERO protocol runs 500 rollouts per suite, 10 tasks at 50 rollouts each, across three seeds, because rollouts are cheap there. On a physical SO-100 each rollout costs a minute plus a human reset, so you buy power through pairing and a good condition grid instead of volume. SIMPLER exists because simulated evaluation that correlates with real evaluation is worth a lot: their visual-matching pipeline reached a Pearson r of 0.924 against real performance where validation MSE managed 0.308.

Can I compare my success rate to a number from a paper or from the arena?

Almost never directly. Different embodiment, different objects, different success rule, different timeout, different operator. Use published numbers to decide which model family to try, and your own benchmark to decide which of your checkpoints to ship. The arena links every value to its source, so you can check what the protocol was, which is usually enough to see why a direct comparison would be wrong.

How do I benchmark when training is not reproducible?

Make the irreproducibility part of the measurement. GR00T's fine-tuning CLI exposes no seed, so train the same configuration two or three times and see how far apart the results land. A run is roughly 1 to 3 USD on the 24 GB tier and 4 to 12 USD on the A100 or H100 tier, so seed variance is affordable to measure. If your policy-to-policy difference is smaller than your seed-to-seed difference, you have not found an improvement.

Is it cheating to throw away a trial where something went wrong?

It is if you decide after seeing the outcome. Write the exclusion rules before you start: a servo dropping out, an object falling off the table during the reset, an operator error before the policy takes over. Log every excluded trial with its reason and report how many you excluded. If more than about one trial in twenty is being excluded, the rig is the problem, not the policy.

Train the checkpoints worth benchmarking

Pick a model and an arm, and the guide gives you the exact GPU tier, dataset format and hyperparameters the trainer sends. A run is 1 to 3 USD on the 24 GB tier and 4 to 12 USD on the A100 or H100 tier, which makes training several seeds of the same configuration a real option.

Open the training matrix

Ready for high-quality robotics data?

AY-Robots connects your robots to skilled operators worldwide.

Get Started