Downloads · 30 days
0
Twu31/smolvla-cross-embodiment-mps
smolvla-cross-embodiment-mps is a robotics model from Twu31. Use it for the robotics task on the model card, and read the license before you ship it in a product. It is set up for lerobot. The card lists the license as apache-2.0.
Sixteen SmolVLA checkpoints, one per LeRobot v3 dataset, spanning bimanual ALOHA (sim and real robot), single-arm xArm, and the 2-DOF PushT planar pusher. Every run was trained on one M5 MacBook (Apple MPS, no NVIDIA…
Downloads · 30 days
0
Access
Public
Updated Aug 20, 2026
Repo size
14.5 GB
Likes
0
Public
Click a slice to open those files.
.pt14.5 GB · 100%
From the Hugging Face model README
Sixteen SmolVLA checkpoints, one per LeRobot v3 dataset, spanning bimanual ALOHA (sim and real robot), single-arm xArm, and the 2-DOF PushT planar pusher. Every run was trained on one M5 MacBook (Apple MPS, no NVIDIA GPU) — 16 SmolVLA runs plus the 5 RT-1 runs in the companion repo come to roughly 20 hours of total compute.
Code: https://github.com/twu3202/SmolVLA_ALOHA
Companion releases: Twu31/rt1-lerobot-mps (same datasets, RT-1 architecture) ·
Twu31/smolvla-libero-eeg
Open-loop action prediction against held-out episodes. L2 is in the dataset's native action units (radians for ALOHA, normalised position for xArm, pixels for PushT — not comparable across groups).
| Rank | Checkpoint | L2 ↓ | MAE ↓ | Final-step loss | Notes |
|---|---|---|---|---|---|
| 1 | xarm_push | 0.216 | 0.105 | 0.636 | 3-DOF, no gripper — simplest task in the set |
| 2 | xarm_push_replay | 0.529 | 0.269 | 1.457 | replay variant |
| 3 | aloha_static_ziploc_slide ★real | 0.556 | 0.106 | 0.114 | best real-robot result |
| 4 | aloha_static_battery ★real | 0.651 | 0.121 | 0.115 | real-robot insertion |
| 5 | aloha_static_cups_open ★real | 0.694 | 0.139 | 0.111 | real-robot |
| 6 | aloha_insertion | 0.716 | 0.154 | 0.118 | sim, human demos |
| 7 | aloha_transfer | 0.729 | 0.149 | 0.119 | sim, human demos |
| 8 | aloha_static_coffee ★real | 0.802 | 0.168 | 0.110 | real-robot |
| 9 | aloha_insertion_scripted | 0.864 | 0.186 | 0.040 | lowest train loss, worse eval |
| 10 | xarm_lift_replay | 1.042 | 0.448 | 1.513 | 84×84 images, gripper timing |
| 11 | aloha_transfer_scripted | 1.156 | 0.214 | 0.060 | sim, scripted |
| 12 | xarm_lift | 1.324 | 0.565 | 1.503 | 84×84 resolution bottleneck |
| 13 | aloha_multitask | 1.327 | 0.276 | 0.456 | 2 tasks, 5000 steps |
| 14 | aloha_static_towel ★real | 1.479 | 0.250 | 0.108 | deformable object — hardest real-robot task |
| 15 | aloha_multitask_scripted | 1.531 | 0.282 | 3.547 | ⚠️ normalisation mismatch, see below |
| — | pusht | 40.4 px | 25.7 px | 0.239 | pixel units, not comparable |

aloha_static_towel (1.479) is the worst
real-robot run — a towel's shape changes through the episode, so visual state stops mapping
cleanly onto joint targets.aloha_insertion_scripted reaches
3× lower train loss than the human version (0.040 vs 0.118) and evaluates worse
(L2 0.864 vs 0.716). Human inconsistency acts as regularisation.xarm_push (84×84, no gripper) is
the best result in the set; xarm_lift (same 84×84, with gripper) is near the worst. The
images are too coarse to time the gripper's open/close transitions.aloha_multitask L2 = 1.33 against ~0.72
single-task, even with the step budget raised to 5000.aloha_multitask_scripted trains at loss
3.5–55 because the two scripted datasets have std[joint0] differing 40× (0.004 vs 0.161);
z-scoring both with one dataset's stats blows up the other. This checkpoint is published as
evidence of the failure, not as a usable model.One directory per dataset, each holding the final checkpoint plus the normalisation statistics it was trained with:
<dataset>/step_003000.pt # or step_005000.pt for aloha_multitask
<dataset>/dataset_stats.json # per-key mean/std used for z-scoring — required for inference
eval_output/ # per-dataset .npz + .png, and the cross-dataset figure
aloha_transfer was produced by an earlier trainer and stores its stats under a stats key
inside the checkpoint instead of loss_log/dataset/cfg; the other fifteen share the
train_generic.py schema. Its dataset_stats.json is present either way.
SmolVLA — SmolVLM2-500M VLM plus a flow-matching action expert, 450.0 M parameters total.
| Component | Params | Trained? |
|---|---|---|
| VLM text tower | 204.6 M | ✅ yes |
| VLM vision tower | 86.4 M | ❌ frozen |
| VLM connector | 11.8 M | ✅ yes |
| I/O embeddings & heads | 48.9 M | ✅ yes |
| Flow-matching action expert | 98.2 M | ✅ yes |
Built with load_vlm_weights=True, freeze_vision_encoder=True, train_expert_only=False.
Note that this means the checkpoints are not fine-tunes of lerobot/smolvla_base: the VLM
backbone starts from HuggingFaceTB/SmolVLM2-500M-Video-Instruct and the action expert is
randomly initialised. Only the 197 frozen vision tensors remain bit-identical to
lerobot/smolvla_base; the other 249 differ.
Training: 3000 steps (5000 for aloha_multitask), batch 4–16, images resized to 512×512 with
padding, 48-token language prompt, chunk size 50 (ALOHA) / 10 (xArm, PushT). Weights are
stored in bfloat16.
ALOHA (sim + real) — 14-dim bimanual joint space
observation.images.cam_high (3, 480, 640) overhead RGB
observation.state (14,) joint positions, z-scored
language tokens (48,) e.g. "Place the coffee capsule inside..."
→ action chunk (50, 14) 1 s of joint targets @ 50 fps
xArm — single arm, tiny images
observation.image (3, 84, 84)
observation.state (4,) x, y, z, gripper
→ action chunk (10, 4) lift; push is 3-dim, no gripper
PushT — 2-DOF planar pusher
observation.image (3, 96, 96) top-down
observation.state (2,) agent x, y in pixels
→ action chunk (10, 2) pixel coordinates, raw (not z-scored)
Internally: image → frozen SmolVLM2 vision encoder → transformer with the language tokens → context; state joins at the flow-matching expert, which denoises the whole chunk in 10 steps. One VLM forward pass produces 10–50 actions.
| Run | Steps | Time |
|---|---|---|
aloha_transfer, aloha_static_* | 3000 | 25–35 min |
aloha_insertion_scripted, aloha_transfer_scripted | 3000 | ~30 min |
aloha_multitask | 5000 | ~50 min |
xarm_lift | 3000 | ~20 min |
xarm_push, xarm_*_replay | 3000 | ~48 min |
pusht | 3000 | ~85 min |
Roughly 8 hours for the sixteen SmolVLA runs; about 20 hours including the RT-1 arm.
Plain torch.save dicts — you need dataset_configs.py and train_generic.py from the
GitHub repo to rebuild the policy config.
import torch, json
from huggingface_hub import hf_hub_download
REPO = "Twu31/smolvla-cross-embodiment-mps"
ck = torch.load(hf_hub_download(REPO, "aloha_static_ziploc_slide/step_003000.pt"),
map_location="cpu", weights_only=False)
ck["step"] # 3000
ck["loss"] # final-step training loss
ck["dataset"] # "aloha_static_ziploc_slide"
ck["cfg"] # image/state/action keys, dims, fps, chunk size
ck["loss_log"] # per-step loss, length == step
ck["policy_state"] # SmolVLAPolicy state_dict, 500 tensors, bfloat16
stats = json.load(open(hf_hub_download(REPO, "aloha_static_ziploc_slide/dataset_stats.json")))
Rebuilding for inference:
from lerobot.policies.smolvla.modeling_smolvla import SmolVLAPolicy
from train_generic import make_smolvla_config # from the GitHub repo
cfg = make_smolvla_config(ck["cfg"], device="mps")
cfg.load_vlm_weights = False # the checkpoint carries the full VLM state
policy = SmolVLAPolicy(cfg).to("mps")
policy.load_state_dict(ck["policy_state"])
Actions come out z-scored; multiply by stats["action"]["std"] and add
stats["action"]["mean"] to recover native units. pusht is the exception — it stores raw
pixel coordinates (raw_gt in the registry).
All sixteen datasets are public LeRobot v3 releases under the
lerobot organisation, listed in the metadata above. They
are not redistributed here — training auto-downloads them.
One exception, so it is on the record: each eval_output/eval_*.npz stores a gts array
alongside preds — the ground-truth action vectors for the held-out frames the evaluation
ran on (250–12,000 rows of 2–14 floats per dataset, ~9 MB in total). No images, no video, no
other observations. They are included so the reported MAE and L2 can be recomputed and checked
independently rather than taken on trust; the source datasets are Apache-2.0.
| Group | Datasets | Episodes each |
|---|---|---|
| ALOHA sim, human | aloha_transfer, aloha_insertion | 50 |
| ALOHA sim, scripted | aloha_transfer_scripted, aloha_insertion_scripted | 50 |
| ALOHA sim, multi-task | aloha_multitask, aloha_multitask_scripted | 100 (2 datasets) |
| ★ ALOHA real robot | aloha_static_coffee, _battery, _cups_open, _towel, _ziploc_slide | 50–56 |
| xArm | xarm_lift, xarm_push, xarm_lift_replay, xarm_push_replay | — |
| PushT | pusht | 206 |
aloha_multitask_scripted is a documented failure and should not be used as a model.| Repo | What it holds |
|---|---|
Twu31/rt1-lerobot-mps | RT-1 on 5 of these datasets — the architecture head-to-head |
Twu31/smolvla-libero-eeg | SmolVLA + LIBERO + EEG as a fourth modality |
Twu31/so101_hand_blue_napkin | Real SO-ARM101 handover demonstrations |
Architecture > scale > data quantity. Read together with the RT-1 repo, the headline of this project is that at 50–800 episodes the choice of action head and pretrained backbone matters more than parameter count — a 244 M RT-1 beats a 450 M SmolVLA on 3 of 5 shared tasks, and loses badly on the hardest one.
@software{smolvla_cross_embodiment_2026,
author = {Twu31},
title = {SmolVLA across 16 LeRobot datasets and 4 embodiments on Apple MPS},
year = {2026},
url = {https://github.com/twu3202/SmolVLA_ALOHA}
}
Built on SmolVLA (Shukor et al., 2025) and the LeRobot dataset ecosystem.