Documentation menu

transfer()

Measure what a policy loses moving to a new embodiment — source and target rates with intervals, and the clusters that opened.

Policies are trained on one body and deployed on another, and the distance between those two numbers is where deployments die. roborama.transfer() measures it: the same policy on the same task, on the embodiment it was trained on and the embodiment you intend to ship — both with n and intervals, plus the failure clusters that exist only on the new body.

The call

roborama.transfer()
import roborama  # reads ROBORAMA_API_KEY from the environment

policy = roborama.Policy.checkpoint(hf="acme/skill-v4", runtime="openpi")

gap = roborama.transfer(
    policy=policy,
    source="aloha-bimanual@fw3.1",   # the embodiment it was trained on
    target="g1-edu-pro@fw2.3",
    task="fold_towel@v2",
)

print(gap.report())
# source: n=380  rate=0.942  ci95=(0.914, 0.961)
# target: n=340  rate=0.715  ci95=(0.665, 0.760)
# failure clusters opened in transfer: [grasp_slip, wrist_singularity]

Reading the gap

The canonical fold_towel@v2 gap: on the source, aloha-bimanual@fw3.1 — the rig the policy was trained on — the rate is 0.942 (n=380, ci95 0.914–0.961). On the target, g1-edu-pro@fw2.3, it is 0.715 (n=340, ci95 0.665–0.760). The intervals are nowhere near overlapping: a 22.7-point drop that no amount of sampling luck explains. That is the real number to plan a deployment around — not the source rate that made the demo look ready.

What opened in transfer

The gap report does more than subtract two rates. It names the failure clusters that were absent or negligible on the source and material on the target — here, grasp_slip and wrist_singularity — which turns "the policy got worse" into a work list. The target's dex3-1 hands present different contact geometry than the source's grippers, and grasp_slip is that difference biting; wrist_singularity is the target's arm kinematics hitting configurations the source arms never encountered on the same trajectories. Each cluster links to its episodes, so the diagnosis comes with video, MCAP telemetry, and commanded-versus-executed traces rather than a hunch.

Closing the gap

The episodes are also the remedy. Target-embodiment failures export in training-ready formats — run.export(format="lerobot"), or "rlds" — subject to your own data posture, since train_on_failures guards our use of them, not yours. Fine-tune on target-embodiment data, re-run transfer(), and watch the two intervals converge; when they are close enough to argue about, graduate to matrix() and put the new embodiment in the release grid.

The full workflow — measure, fine-tune, re-measure, and when to stop — is the transfer gap guide.

Where next