Robotics
LeRobot
Safetensors
imitation-learning
act
b-spline
so101
bspline_act
aryankakad's picture
Upload README.md with huggingface_hub
d2f77bd verified
|
Raw
History Blame Contribute Delete
6.98 kB
---
license: apache-2.0
library_name: lerobot
pipeline_tag: robotics
tags:
- robotics
- lerobot
- imitation-learning
- act
- b-spline
- so101
- bspline_act
datasets:
- aryankakad/CUPSTACKING
model_name: cupstack_bspline_act
---
# cupstack_bspline_act
An [ACT](https://huggingface.co/papers/2304.13705) policy that predicts **B-spline
trajectory segments** instead of discrete action chunks, trained on SO-101 cup
stacking. This is the "Reg.+BSP" variant from
[B-spline Policy: Accelerating Manipulation Policies via B-spline Action Representations](https://arxiv.org/abs/2607.09648).
The practical consequence: **you can run this checkpoint faster without retraining it.**
The policy outputs a curve, so executing `a(n·t)` replays the same trajectory geometry
n times faster. Speed-up is an inference flag.
> [!WARNING]
> **This checkpoint has never been evaluated on held-out data or on hardware.**
> It was trained on all 50 episodes with no validation split, so its numbers measure
> fit, not generalization. Treat first hardware runs as untested — keep the e-stop
> within reach. See [Limitations](#limitations).
## Usage
```bash
lerobot-rollout \
--strategy.type=base \
--policy.path=aryankakad/cupstack_bspline_act \
--policy.speed_up=1.0 \
--device=cuda \
--robot.type=so101_follower --robot.port=/dev/ttyACM0 --robot.id=FOLLOWER \
--robot.cameras='{front: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30}, gripper: {type: opencv, index_or_path: 4, width: 640, height: 480, fps: 30}}' \
--task="stack the cups" \
--fps=30 --duration=30 --display_data=true
```
Raise `--policy.speed_up` to 2.0 or 4.0 to execute faster. Start at 1.0 and step up
only once the task succeeds.
### Camera naming is not optional
The policy requires exactly these observation keys, so the `--robot.cameras` dict keys
must be **`front`** and **`gripper`**, lowercase:
| Key | Shape |
|---|---|
| `observation.images.front` | `(3, 480, 640)` |
| `observation.images.gripper` | `(3, 480, 640)` |
| `observation.state` | `(6,)` |
Joint order is `shoulder_pan, shoulder_lift, elbow_flex, wrist_flex, wrist_roll, gripper`.
Swapping the two cameras produces confident but wrong behaviour rather than an error.
### Requirements
This policy type is not in upstream LeRobot. You need a checkout containing the
`bspline_act` policy, installed with the scipy extra:
```bash
uv pip install -e ".[feetech,bspline]"
```
`scipy>=1.15` is required for `interpolate.generate_knots`.
### No dataset needed at inference
Unnormalization statistics are stored as buffers inside `model.safetensors`, so the
checkpoint is self-contained. You do not need the training dataset on the robot machine.
## Training
| | |
|---|---|
| Steps | **100,000** |
| Batch size | 32 |
| Epochs | 133.09 |
| Dataset | [`aryankakad/CUPSTACKING`](https://huggingface.co/datasets/aryankakad/CUPSTACKING) → B-spline converted |
| Episodes / frames | 50 / 24,044 @ 30 fps |
| Optimizer | AdamW, lr 2e-5 (backbone 1e-5), wd 1e-4 |
| Precision | bf16 autocast + `channels_last` |
| Hardware | 1× RTX 4090, 5 h 24 min |
| Seed | 1000 |
Learning rate is 2e-5 rather than ACT's default 1e-5, sqrt-scaled for batch 32.
### Loss
| Step | loss | l1_loss | kld_loss |
|---|---|---|---|
| 500 | 3.027 | 0.390 | 0.264 |
| 10k | 0.166 | 0.104 | 0.007 |
| 50k | ~0.111 | 0.041 | 0.007 |
| **100k** | **0.095** | **0.026** | **0.007** |
Training loss only — there was no validation split.
## Architecture
Standard ACT with one change: the decoder emits a B-spline **parameter matrix** rather
than an action chunk.
```
(n_knots, 1 + action_dim) = (16, 7) = 112 values per prediction
column 0 knot vector, in source-frame units, 0 = "now"
columns 1: control points, one per joint
```
| | |
|---|---|
| Params | 52 M |
| Vision backbone | ResNet18 (ImageNet init) |
| dim_model / chunk_size | 512 / 16 |
| VAE | enabled, kl_weight 10.0 |
| B-spline degree | 3 (cubic, C² continuous) |
| bspline_chunk_size | 10 |
| Fitting tolerance ε | 0.2 (degrees) |
Knot spacing is fitted adaptively per episode, so a fixed 16 rows covers a **variable**
time horizon — 0.53 s to 1.47 s per segment on this dataset, 0.84 s mean. The network
only runs when a segment is exhausted, which decouples policy rate from control rate.
### On the fitting tolerance
ε = 0.2 is not the paper's value. The paper uses 0.002 for metre-scale end-effector
actions; SO-101 stores joint targets in **degrees** (~±120), roughly 100× larger. At
ε = 0.002 compression is 1.06× — one knot per frame, which defeats the representation.
| ε | Compression | p99 reconstruction | Segment span |
|---|---|---|---|
| 0.05 | 1.4× | 0.05° | 0.44 s |
| **0.2** | **2.7×** | **0.19°** | **0.84 s** |
| 0.5 | 4.1× | 0.48° | 1.24 s |
2.7× sits inside the paper's reported 1.12×–3.34× range.
## Evaluation
**Offline only. No hardware evaluation has been performed.**
Open-loop prediction error — decoded trajectory vs ground-truth actions, measured on
**training data**:
| Checkpoint | Mean | Median | p90 | Max |
|---|---|---|---|---|
| 20k | 5.99° | 4.12° | 8.78° | 45.2° |
| 50k | 3.34° | 2.28° | 6.53° | 30.8° |
| **100k** | **2.10°** | **1.61°** | **3.86°** | **18.6°** |
Error was still falling at 100k and 2.10° is far from zero, which argues against
outright memorization — but this is training data, so it is not evidence of
generalization.
The representation is not the bottleneck: B-spline fitting reconstructs to 0.19° p99,
so essentially all of the 2.10° is policy prediction error.
Temporal rescaling is **exact**. On a real predicted segment (0.76 s span), `a(2t)` and
`a(4t)` reproduce the 1× samples to 0.00e+00, consuming the segment in 22 / 11 / 5
control ticks.
## Limitations
- **No validation split.** All 50 episodes were used for training (`eval_steps: 0`).
Generalization is unmeasured.
- **No hardware evaluation.** Task success rate is unknown.
- **Speed-up has a hardware ceiling.** The paper reaches 4× on cube picking but only 2×
on speed stacking before the low-level controller loses tracking. Cup stacking is the
same precise-placement regime, so expect degradation near 2×. Retiming does not make
the arm faster — past the tracking limit it overshoots rather than stopping.
- **Single task, single scene.** 50 demonstrations of one cup-stacking setup; no
robustness to lighting, camera placement, or cup position changes should be assumed.
- **Camera assignment is silent when wrong.** Swapped views degrade behaviour without
raising an error.
## Citation
```bibtex
@article{han2026b,
title={B-spline Policy: Accelerating Manipulation Policies via B-spline Action Representations},
author={Han, Xiaoshen and Xiong, Haoyu and Chen, Haonan and Liu, Chaoqi and
Torralba, Antonio and Zhu, Yuke and Du, Yilun},
journal={arXiv preprint arXiv:2607.09648},
year={2026}
}
```