pi05-libero: pi 0.5 (π0.5) tuned for the LIBERO benchmark, as a per-call API
pi05-libero is this platform's name for a metered lane serving the LIBERO tune of pi 0.5, the open-weights VLA from Physical Intelligence. The tune is real, public, and downloadable today from two publishers. Its row sits in the platform's model data, behind the public list. The family head, the pi05 page, carries the architecture, the size, the memory needs, and the license position. This page owns one question: the LIBERO tune, its honest scores, and how to run it without the traps that fill the issue trackers.
Last verified: 2026-10-05
What it is
Pi 0.5 ships as three public checkpoints: the base for tuning onto your own demos, one tuned on the DROID robot dataset, and one tuned on LIBERO demonstrations, the subject here. The publisher's repository describes it plainly: the model fine-tuned for the LIBERO benchmark, meant for inference. The tune learns the scenes, the objects, and the action patterns of that one simulation benchmark. It is a specialist. You would not put it on a warehouse arm. You put it in a LIBERO evaluation, or study it as a scored reference in open research.
| Fact | Value | Owner of the number |
|---|---|---|
| What it is | pi 0.5 weights tuned on LIBERO demonstrations | openpi repository |
| Reference tune | 30,000 fine-tune steps, scored 96.85 average | openpi LIBERO benchmark run |
| Port refinement | 6,000 more steps, bfloat16, batch 256, on 8 H100 GPUs | LeRobot LIBERO docs |
| Scored checkpoint | lerobot/pi05_libero_finetuned_v044 (renamed in 2026; the old address redirects) | Hugging Face, checked 2026-10-05 |
| Port downloads | 25,091 for the finetuned port, 4,537 for the base port | Hugging Face counters, read 2026-10-05 |
| Benchmark world | MuJoCo simulation, Linux only, 130 tasks, four benchmark suites (five in the LeRobot docs count) | LeRobot LIBERO docs |
| License shape | openpi repo code Apache-2.0; the port cards carry a Gemma tag | read 2026-10-05, see the family page |
| Lane state | in the platform's model data, not on the public list | this platform |
The license line is short here because the family page owns it. Three artifacts carry three terms: repository code, port model cards, and the gated PaliGemma tokenizer. A commercial buyer reads all three before shipping a product on the weights. The GR00T license guide walks that decision for open robot models.
The five LIBERO suites, decoded
The suite names look like code because they are code: the values you pass on the command line. This is the vocabulary every LIBERO conversation assumes and almost no page explains:
| Suite | CLI name | Tasks | What it asks of the model |
|---|---|---|---|
| LIBERO-Spatial | libero_spatial | 10 | move correctly given where things sit, with distractors placed to break spatial reasoning |
| LIBERO-Object | libero_object | 10 | handle target objects whose identity changes while the scene stays put |
| LIBERO-Goal | libero_goal | 10 | reach the goal named in the instruction, with the goal changing per task |
| LIBERO-90 | libero_90 | 90 | short-horizon tasks from the LIBERO-100 collection |
| LIBERO-Long | libero_10 | 10 | long-horizon tasks, the hardest standard suite for this model family |
One line matters more than the table: the published pi 0.5 runs cover the four standard suites; LIBERO-90 is part of the benchmark and outside the reported set. The LeRobot LIBERO docs, read on October 5, 2026, are the source for every number in that table.
The observation shape is fixed. The policy reads an 8-value state vector, end-effector position, orientation, and gripper joints. It reads two camera views, outer and wrist, at 256 by 256 pixels. It outputs 7 values per step: a 6-value end-effector delta plus a gripper command, all in the range minus one to one. If your robot speaks a different dialect, you convert on your side. That conversion is where most reproduction trouble enters.
What a LIBERO score tells a buyer, and what it does not
A LIBERO score is a simulation score. The tasks run in MuJoCo, on a Franka-class arm in a rendered kitchen. That is a real signal. The tune learned the task family, the instruction following, and the motion. It is not a forecast for your lab. Three dated findings frame the limit.
First, the scores sit near the ceiling, and a benchmark near its ceiling stops separating good policies. Both published runs for this tune average above 96. Differences of a point inside that band are mostly protocol noise, which is why the docs say average over seeds.
Second, two research teams stress-tested LIBERO itself. LIBERO-PRO (posted October 2025, revised May 2026) perturbs objects, start states, instructions, and environments. Its abstract reports models above 90 percent collapsing to zero under perturbation. The gap is memorized layouts and action sequences, not task understanding. LIBERO-plus (October 2025, revised December 2025) perturbs seven dimensions across roughly 10,000 task variants and reports the same class of brittleness. Both papers are about what a standard LIBERO number means. Our stance follows their evidence. Quote the suite. Quote the source. Treat the score as a smoke test.
Third, your numbers are yours. Two honest runs of the same tune differ by suite because implementations differ. That is normal; the next two sections show how to keep your own runs honest.
Use cases
- Benchmark evaluation. The direct job. You run the scored checkpoint across the four standard suites and compare against the reference tables, with the revision and seed discipline below.
- A baseline for your own tunes. The publisher's repository describes this tune as state-of-the-art on the benchmark. Train your variant, measure it against these numbers, and report both.
- Sim-first development. Build your perception, your driver, and your safety layer in simulation before you touch hardware. The tune gives you a policy that is known-good in this world.
- Research reproduction. The issue trackers are full of people trying to reproduce these tables. This page's checkpoint menu and triage list exist to make that a one-read fix.
- Teaching and labs. One GPU, no robot, and a full manipulation benchmark with published numbers to grade against. The published port finetune used 8 H100 GPUs, but you do not need that to run inference on the result.
Where it is the wrong tool: any real-world deployment. The tune is a benchmark specialist. For broad real-robot behavior, the family page covers the base checkpoint; the sibling pi05-droid covers the DROID tune.
The checkpoint menu
Four names cover one tune, and the differences are the whole story:
| Checkpoint | Publisher | What it is | Use it for |
|---|---|---|---|
| pi05_libero | Physical Intelligence (openpi) | the reference tune, 30,000 steps, JAX weights | the publisher's docker evaluation workflow; the 96.85 run |
| lerobot/pi05_libero_base | LeRobot | the PyTorch conversion of the reference tune | the starting point for your own PyTorch fine-tune |
| lerobot/pi05_libero_finetuned_v044 | LeRobot | the conversion plus 6,000 more training steps | evaluation and serving; the 97.5 run |
| community finetunes | various | small variants, for example spatial-reasoning retunes | study each model card before use |
Two facts about this table save people days. The scored port checkpoint is the finetuned one, not the base port. And its address changed: renamed in 2026, the old address redirecting, so old commands keep working. Citations and scripts should carry the new name. The LeRobot docs still name the old address in one section. That rename was checked at the redirect level on October 5, 2026.
Why does the base port score zero while the finetuned port scores 97? The port team answered in the tracker. Their pipeline differs from the publisher's. Image processing and normalization do not transfer cleanly. So they trained the extra 6,000 steps to adapt the weights, rather than ship a conversion that silently underperforms. The base port stays a starting point, not a scored model. An open thread from November 2025 shows the cost. A reader evaluated all three, read 0.0 from both base checkpoints and 0.96 to 1.0 from the finetuned one, and asked what was broken. Nothing was. The wrong row of the menu was in the harness.
Zero success rate: five checks
Run these in order before you conclude the model failed.
- The checkpoint. Are you evaluating the finetuned port or the reference tune? The base port is a fine-tuning start. Expect zeros from it in a benchmark run.
- The stats. Pi 0.5 normalizes state and actions with quantiles by default. Datasets that only carry min, max, mean, and std stop on the first batch with this error: ValueError: QUANTILES normalization mode requires q01 and q99 stats. Recompute the dataset stats, or run with mean/std normalization, which is what the scored checkpoint uses. Norm stats cause both loud and silent failures in this family. A dedicated guide to normalization stats sits in this docs set.
- The control mode. The environment defaults to relative actions. A checkpoint trained on absolute actions will move wrongly, not error out. Set the mode to match the weights.
- The initial states. With one environment and the default setup, all ten episodes reset to the same start state. The publisher's own script draws a fresh start per episode. Same seed, same init states, one batch per task: that is the comparable setup.
- The dataset revision. Hub datasets get re-uploaded. Success rates are only comparable against the same data revision. Pin it when you report.
Then average over three seeds. A single seed can swing a suite by points. Community tooling automates multi-seed runs and tells you whether a gap is real.
API usage
The lane's contract speaks the platform's action route, POST /v1/action, with a Bearer key from the console. Multipart form data goes in. JSON comes out. The model id is pi05-libero.
| Form field | Required | Notes |
|---|---|---|
model | yes | pi05-libero |
instruction | yes | the task sentence, non-empty |
state | yes | a JSON array of numbers: your joint positions. The empty array [] is the legal stateless case |
image | yes, one or more | camera frames as file parts. LIBERO sends the outer view and the wrist view |
One served request returns three things. actions is the action chunk, a list of actuator deltas in the checkpoint's own shape. normalization is the norm stats the endpoint applied, untouched. Your driver converts back into your units with the same numbers. usage is the metering line: the call count and the cost. One served request is one billed call. A refused request bills nothing. The prepaid wallet balance is the spending stop. The 25 MiB body cap bounds the frame sizes. Every field, error code, and limit lives in the run-action reference.
One honesty note. LIBERO runs on your machine: Linux and a MuJoCo rendering backend. The API serves the policy, not the simulator. Your evaluation loop stays local and sends observations over; a robot loop does the same with real frames. That is the shape that runs a benchmark or an arm without a local 8 GB-plus GPU.
The posture line, plain: this alias is not on the public list, and nothing answers under it. The tabs below are the contract the lane ships under, testable now.
curl
curl -X POST "https://api.ironstratum.com/v1/action" \
-H "Authorization: Bearer $KEY" \
-F "model=pi05-libero" \
-F "instruction=pick the alphabet soup and place it in the basket" \
-F 'state=[0.5, 0.1, 0.2, 0.0, 1.0, 0.0, 0.03, 0.03]' \
-F "image=@agentview.jpg" \
-F "image=@wrist.jpg"
python
import os
import requests
resp = requests.post(
"https://api.ironstratum.com/v1/action",
headers={"Authorization": "Bearer " + os.environ["KEY"]},
data={
"model": "pi05-libero",
"instruction": "pick the alphabet soup and place it in the basket",
"state": "[0.5, 0.1, 0.2, 0.0, 1.0, 0.0, 0.03, 0.03]",
},
files=[
("image", ("agentview.jpg", open("agentview.jpg", "rb"), "image/jpeg")),
("image", ("wrist.jpg", open("wrist.jpg", "rb"), "image/jpeg")),
],
timeout=30,
)
resp.raise_for_status()
answer = resp.json()
chunk = answer["actions"] # the action chunk: 7-value deltas per step
stats = answer["normalization"] # the norm stats this endpoint applied
print("actions in this chunk:", len(chunk))
print("cost of this call:", answer["usage"].get("cost"))
lerobot
import os
import requests
session = requests.Session()
session.headers["Authorization"] = "Bearer " + os.environ["KEY"]
def step(frames, state, instruction):
resp = session.post(
"https://api.ironstratum.com/v1/action",
data={
"model": "pi05-libero",
"instruction": instruction,
"state": "[" + ", ".join(str(s) for s in state) + "]",
},
files=[
("image", ("agentview.jpg", frames[0], "image/jpeg")),
("image", ("wrist.jpg", frames[1], "image/jpeg")),
],
timeout=30,
)
resp.raise_for_status()
return resp.json()["actions"]
# evaluation loop shape: pull frames from the LIBERO simulator
# (or any camera), run the chunk, send the new state back
state = [0.5, 0.1, 0.2, 0.0, 1.0, 0.0, 0.03, 0.03]
instruction = "pick the alphabet soup and place it in the basket"
for episode in range(10):
frames = env_reset() # your harness resets and renders both views
done = False
while not done:
chunk = step(frames, state, instruction)
for deltas in chunk: # 7-value rows: 6 end-effector deltas + gripper
state, frames, done, success = env_step(deltas)
if done:
break
print("episode", episode, "success:", success)
The loop is the whole pattern. Send frames, instruction, and state. Receive a chunk. Run it at your control rate. Send the new state with the next call. Frames come from the simulator's two cameras or any real pair. The contract is the form fields, not a client library.
Benchmarks
Two runs, one model, never averaged. Each number names its suite and its source.
| Run | Spatial | Object | Goal | LIBERO-10 | Average |
|---|---|---|---|---|---|
| Reference tune, openpi, 30,000 steps | 98.8 | 98.2 | 98.0 | 92.4 | 96.85 |
| Port refinement, LeRobot, plus 6,000 steps | 97.0 | 99.0 | 98.0 | 96.0 | 97.5 |
The reference row is the publisher's, from the openpi repository; the port row is the LeRobot team's, from the LeRobot LIBERO docs, both read on October 5, 2026. The port is not a correction of the reference. It is the same tune adapted to a second implementation. The docs place the two tables side by side and call the port consistent with the original. Read the per-suite columns, not just the averages. The port gave up 1.8 points on Spatial and gained 3.6 on the long-horizon suite. That trade says more about implementations than about the model.
The protocol behind both tables: 10 episodes per task across the four standard suites, 400 total, averaged over seeds, dataset revision pinned. Success rates are only comparable against the same data revision, in the docs' own words.
The honesty layer, again, because this section is where numbers get quoted: the robustness papers dated above show near-ceiling scores can hide brittleness under small shifts. Quote the suite, the implementation, and the date.
This platform has no measured numbers of its own: nothing serves under the alias, so there is nothing to measure. Our results publish only after they are measured and held, in later work this page does not date.
Getting started
- Read the primary sources. The LeRobot LIBERO docs for the suites, the commands, and both results tables. The openpi repository for the reference tune and its evaluation workflow. The pi 0.5 paper for the model itself.
- Pick your checkpoint before anything else. Evaluate the finetuned port. Tune your own from the base port. Run the publisher's workflow from the reference tune. The menu above is the decision.
- Write your client against the contract now. The tabs above are the shape the lane ships under. The run-action reference documents every field and error. The models index is the live catalog.
- Open the console when you build. The signup flow opens the wallet, the keys, and the billing history. The loaded balance is the spend bound. Each key revokes alone. The models index shows every live row, and the VLA category page collects this platform's action models.