Instructions to use Harrysunshine/so101-act-cube with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- LeRobot
How to use Harrysunshine/so101-act-cube with LeRobot:
- Notebooks
- Google Colab
- Kaggle
| license: apache-2.0 | |
| tags: | |
| - robotics | |
| - lerobot | |
| - act | |
| - so101 | |
| - so-arm101 | |
| - manipulation | |
| - pick-and-place | |
| pipeline_tag: robotics | |
| library_name: lerobot | |
| # SO-ARM101 pick-and-place — ACT, single task (cube) | |
| An [ACT](https://tonyzhaozh.github.io/aloha/) (Action Chunking Transformer) policy trained from | |
| scratch on one SO-ARM101 tabletop task: pick up a cube and place it in the bin. | |
| > **Read this first.** This checkpoint **does not clear our offline acceptance bar** — on every one of | |
| > its six joints, its best step still predicts motion with larger error amplitude than a | |
| > "hold current pose" baseline on at least one axis (`worst_ratio` 1.681, needs < 1). It is published | |
| > as a **reference and comparison artifact, not a deployable policy.** See | |
| > [Offline evaluation](#offline-evaluation). | |
| ## Task | |
| Single task, no language conditioning. LeRobot's ACT implementation **takes no language input** — | |
| which is exactly why a single task was chosen for it: on a multi-task mix ACT cannot see the | |
| instruction, so identical frames from different tasks would only teach it a cross-task average. | |
| | Task | Episodes | Frames | | |
| |---|---|---| | |
| | pick up a cube and place it in the bin | 300 | 106,085 | | |
| Chosen from a nine-task set because it has the joint-highest episode count, and a cube is a rigid | |
| body with clean geometry and stable appearance — the most standard pick-and-place benchmark of the | |
| nine. The two stacking tasks need precise alignment and are clearly harder, so they were excluded. | |
| ## Data | |
| - Source: the `pick_up_a_cube_and_place_in_the_bin` split of | |
| [`zhuzhuangtian/so101-pick-place-tasks`](https://www.modelscope.cn/datasets/zhuzhuangtian/so101-pick-place-tasks) | |
| on ModelScope (Apache-2.0), LeRobot v3.0 format. | |
| - Robot: SO-ARM101 follower arm, 6 DoF. | |
| - Cameras: two RGB streams, `observation.images.top` and `observation.images.wrist`, 480×640 each, 30 fps. | |
| - `observation.state` and `action` are both `float32(6)`: `shoulder_pan`, `shoulder_lift`, | |
| `elbow_flex`, `wrist_flex`, `wrist_roll`, `gripper` (joint positions, **absolute** targets). | |
| ## Training | |
| | | | | |
| |---|---| | |
| | Base | none — trained from scratch; vision backbone is torchvision ImageNet ResNet-18 | | |
| | Params | ≈ 51.6 M | | |
| | Architecture | 4 encoder / 1 decoder layers, `dim_model` 512, VAE objective enabled | | |
| | Steps | 50,000 (≈ 11.3 epochs at effective batch 24) | | |
| | Batch | 8 per device × 3 devices = 24 effective | | |
| | Optimizer | AdamW, lr **1e-5 constant**, wd 1e-4, betas (0.9, 0.999) | | |
| | Schedule | none — ACT's LeRobot preset returns no scheduler (no warmup, no decay) | | |
| | Action chunk | 100 (`chunk_size` = `n_action_steps` = 100) | | |
| | Augmentation | brightness/contrast 0.7–1.3, hue ±0.05, saturation 0.5–1.5, sharpness 0.5–1.5, affine ±5° / translate 0.05; up to 5 of 6 sampled per frame | | |
| | Normalization | state/action/visual all MEAN_STD from real dataset statistics | | |
| Final training loss 0.126. Note that ACT's loss is **not comparable** to that of the π0/SmolVLA | |
| siblings below — constant LR versus cosine schedules, and a different objective. | |
| **Published checkpoint = step 40,000**, the best of 10 saved checkpoints on the metrics below. | |
| ## Offline evaluation | |
| No simulator exists for this rig, so evaluation is offline only, against a | |
| **copy-the-current-joint-angles baseline**: | |
| - `ratio = MAE(prediction, action) / MAE(current_state, action)` — must be **< 1**. | |
| - `delta_corr = corr(prediction − state, action − state)` — must be **> 0**. | |
| - `delta_std` — ratio of predicted to true motion magnitude; ≈ 1 is healthy. | |
| Best checkpoint (step 40,000), 200 frames sampled uniformly across the task: | |
| | | value | verdict | | |
| |---|---|---| | |
| | worst_ratio | **1.681** (`wrist_roll`) | ✗ fails the < 1 bar | | |
| | best joint ratio | 0.475 (`gripper`) | ok | | |
| | worst delta_corr | 0.618 | direction is learned | | |
| | delta_std | **1.086 – 1.478, all six joints > 1** | over-shoots | | |
| **Failure mode: amplitude over-shoot, not wrong direction.** `delta_corr` is respectable | |
| (0.618–0.870), so the policy has learned *where* to move; but `delta_std > 1` on every joint means | |
| it predicts increments 9–48 % larger than ground truth, and that inflation pushes total error past | |
| the do-nothing baseline. All 10 checkpoints fail the bar (`worst_ratio` 1.905 → 1.688), and the | |
| curve is flat after step 20,000 — **this is not under-training**, so simply training longer is not | |
| the fix. Plausible directions instead: temporal ensembling of chunks at inference, a lower action | |
| chunk size, or loss/normalization changes. | |
| **The weakest axes are the two wrist DoF** (`wrist_roll`, `wrist_flex`) — the same weak spot the π0 | |
| and SmolVLA models show, on data from the same source. Across three different architectures, that | |
| points at the data rather than at any one model. | |
| ## Real-robot status | |
| **Not validated on hardware, and not recommended for hardware.** The over-shoot failure mode is the | |
| kind that gets worse in closed loop, where errors accumulate. If you run it anyway, reduce speed and | |
| keep a hand on the e-stop. | |
| ## Usage | |
| ```python | |
| from lerobot.policies.act.modeling_act import ACTPolicy | |
| policy = ACTPolicy.from_pretrained("Harrysunshine/so101-act-cube") | |
| # batch: observation.state (6,), observation.images.top (3,480,640), | |
| # observation.images.wrist (3,480,640). No language input. | |
| action = policy.select_action(batch) | |
| ``` | |
| The two `*normalizer_processor.safetensors` files are **required**. Without them LeRobot silently | |
| falls back to identity normalization: loss looks fine, but every action comes out at the wrong scale. | |
| Load the repo as a whole, do not cherry-pick `model.safetensors`. | |
| Only inference assets are published here. Optimizer/scheduler/RNG state is not included, so this repo | |
| cannot be used to resume training. | |
| ## Limitations | |
| - **Does not pass the offline acceptance bar** (`worst_ratio` 1.681 ≥ 1). Reference artifact, not a | |
| deployable policy. | |
| - No language conditioning — one task only, cannot be re-targeted by prompt. | |
| - **Rig-specific top camera.** The training data comes from a different physical setup than ours: the | |
| wrist view matches pixel-for-pixel (same SO-ARM101 follower hardware), but the **top camera | |
| extrinsics differ**. Dropping this checkpoint onto another SO-ARM101 will not work without camera | |
| adaptation or a short fine-tune on target-rig data. | |
| - Absolute joint-position action space; sending these as deltas will diverge in closed loop. | |
| - Fixed 480×640 dual-camera observation. | |
| - Single cube on the training tabletop; no generalization claims beyond it. | |
| ## Comparison note | |
| This model is a **single-task** run; the two siblings below are **9-task** mixes on a superset of the | |
| same source data. Different training sets, so **the metric magnitudes cannot be ranked against each | |
| other.** What is comparable is the failure mode and the location of the weak axes: ACT over-shoots | |
| (`delta_std` > 1) where π0 and SmolVLA under-shoot (0.71–0.99), and all three are weakest at the | |
| wrist. | |
| - [`Harrysunshine/so101-pi0-9task`](https://huggingface.co/Harrysunshine/so101-pi0-9task) — π0 full fine-tune, 9 tasks, passes the bar. | |
| - [`Harrysunshine/so101-smolvla-9task`](https://huggingface.co/Harrysunshine/so101-smolvla-9task) — SmolVLA, 9 tasks, passes the bar. | |
| ## License | |
| Apache-2.0, following LeRobot and the source dataset. | |
| --- | |
| ## 中文说明 | |
| SO-ARM101 桌面抓放 **ACT 单任务**(方块放进筐)权重,从零训练(视觉塔=torchvision ImageNet ResNet-18),约 51.6M 参数。 | |
| > **先看这条**:本 checkpoint **没过我们的离线硬底线**(`worst_ratio` 1.681,要求 < 1), | |
| > 作为**对照与参考产物**发布,**不是可部署策略**。 | |
| - **为什么是单任务**:lerobot 的 ACT **不接语言输入**。9 任务混训时它看不到任务描述, | |
| 同样画面+关节角下只能学跨任务平均动作。九任务里挑方块=集数并列最多、刚体几何清晰外观稳定, | |
| 两个 Stack 要精确对准明显更难,排除。 | |
| - 配方=ACT 官方默认:**LR 1e-5 恒定**(ACT 的 preset 不返回 scheduler,无 warmup 无衰减), | |
| 50k 步、有效 batch 24(epoch 11.31)、action chunk 100。 | |
| - **三个模型的 loss 不可横向比**:ACT 恒定 LR,π0/SmolVLA 都是余弦,只有各自收敛后的验收指标可比。 | |
| - **发布第 40,000 步**,10 存点里最优。 | |
| - **失效模式=幅度过冲**,与 π0/SmolVLA 方向相反:`delta_corr` 0.618–0.870 其实不低(方向学对了), | |
| 但 `delta_std` **六关节全 > 1**(1.086–1.478)=预测增量比真值大 9–48%,误差被放大到超过照抄基线。 | |
| 10 个点全不过门、**20k 步后曲线就平了 ⇒ 不是训练不足**,再训不解决;可试的方向是推理端 chunk 时序集成、 | |
| 减小 chunk、或改损失/归一化口径。 | |
| - **腕部两自由度最差**,与 π0/SmolVLA 一致 ⇒ 跨三个架构同一短板,是数据的难点。 | |
| - **真机未验证、也不建议上真机**:过冲这种失效模式在闭环里会累积。真要跑就降速 + 手放急停。 | |
| - 两个 `*normalizer_processor.safetensors` 必须一起加载,缺了静默退回恒等归一化、动作尺度整体错。 | |
| - **边界**:top 相机外参与我们自己的臂不同,换机器需相机适配或少量目标机器数据再微调。 | |