Instructions to use AlexWortega/tinyvla with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- LeRobot
How to use AlexWortega/tinyvla with LeRobot:
# No code snippets available yet for this library. # To use this model, check the repository files and the library's documentation. # Want to help? PRs adding snippets are welcome at: # https://github.com/huggingface/huggingface.js
- Notebooks
- Google Colab
- Kaggle
File size: 9,494 Bytes
1601a2f f818890 1601a2f ddd826b 804441b ddd826b 1601a2f 49cc5f9 1601a2f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | ---
license: apache-2.0
base_model: Qwen/Qwen3.5-0.8B
tags:
- robotics
- vla
- lerobot
- libero
- dual-rate
pipeline_tag: robotics
---
# TinyVLA: a dual-rate VLA that beats OpenVLA-7B on LIBERO-Spatial at 0.64B params
**Headline result: 86% success on LIBERO-Spatial (n=100) in dual-rate mode (semantic latent
refreshed at 1 Hz), 79% full-rate β vs OpenVLA-7B's 84.7% β with 140M parameters on the
online control path.** Built and trained end-to-end in ~5 days on a single RTX A6000.
## 1. Architecture
```
SLOW / SMART path (0.5β2 Hz, cached)
instruction ββββββββββββββββββββββ
camera β Qwen3.5-0.8B vision tower β Qwen3.5 language stack (first 12 of 24 layers)
β β
β 8 readout tokens β linear β semantic latent (8Γ512)
β β cached between refreshes
βββββββββββββββββββΌββββββββββββββββββββββββΌββββββββββββββββββββββββββ
β FAST / MOTOR path (10β20 Hz, ~140M online)
βββ 64 spatial tokens per camera ββ
proprio (padded 16d) ββββββββββββββββββββββββββββββββ€
embodiment-id embedding βββββββββββββββββββββββββββββ€
βΌ
flow-matching action expert (38M, 12 blocks,
interleaved cross-/self-attention, AdaLN-free)
βΌ
50-step action chunk (padded 8d + validity mask)
```
- **Single shared encoder**: the Qwen3.5-0.8B native ViT (100.6M) feeds both paths.
- **Slow path**: image + instruction + 8 trailing pad-token "readout" slots through the
truncated language stack (L/2 layer-skip a la SmolVLA); their hidden states β latent 8Γ512.
- **Fast path**: raw vision-tower spatial tokens (bypassing the LM) + proprio + embodiment
token, cross-attended by the flow expert. 10 Euler steps at inference.
- **Flow matching**: linear-OT path, t ~ Beta(1.5, 1), velocity target, masked MSE.
- Totals: 643M stored / 39.5Mβ575M trainable depending on stage / ~140M online per tick.
- Implemented as an **out-of-tree LeRobot policy plugin**
(`--policy.type=tinyvla --policy.discover_packages_path=tinyvla`, lerobot 0.6.1).
## 2. Training recipe
| Stage | Data | Steps | Trainable | Result |
|---|---|---|---|---|
| 1. Overfit smoke | svla_so100_stacking (56 eps) | 5k | expert+proj (40M) | loss 1.885β0.099 |
| 2. Mixture pretrain | 40 SO100/101 community datasets (~10.7K eps, weight 0.65, per-dataset proportional) + Bridge V2 10K eps (0.35) | 40k, bs 64Γ2, lr 1e-4 | 39.5M (backbone frozen) | held-out RMSE@t0 0.30Ο; **stale-latent 2s == fresh** |
| 2b. Staleness aug | same | from step 20k | β | latent from frame tβk, k~U(0,2s), p=0.5 |
| 3. Spatial distillation | + 132K teacher labels (Qwen3.5-4B, center-point β 32Γ32 grid), CE Γ0.15 on cam0 tokens | 20k, lr 5e-5 | same + head | head top-1 20.8%, top-5 44.8% (random 0.1%) |
| 4. LIBERO FT (ft4) | HuggingFaceVLA/libero (1693 eps, all suites) | 40k, bs 48, lr 1e-4 / backbone 0.1Γ | **575M** (LM layers + vision unfrozen; vocab embeddings frozen) | loss 0.066 |
Ablation FTs: ft1 (all frozen) β 0% closed-loop; ft2 (vision unfrozen) β 60%;
ft3 (= ft2 from distilled ckpt) β 61%; **ft4 (LM+vision unfrozen) β 79/86%**.
Unfreezing the LM was the single largest gain; distillation was neutral on LIBERO
(likely overwritten by vision unfreezing during FT β bake it into pretraining next time).
Cross-embodiment handling: canonical schema (cam0=scene/cam1=wrist via regex mapping,
per-dataset mean/std normalization, action pad-to-8 + validity mask, state pad-to-16,
learned embodiment-id token). Weighted mixture sampler with per-source retry on corrupt
frames (IndexError/KeyError/decode RuntimeError).
## 3. Results
### LIBERO β all four suites (dual-rate, latent @ 1 Hz)
| Suite | TinyVLA | OpenVLA-7B (published) |
|---|---|---|
| Spatial | **86%** (n=100; full-rate 79%) | 84.7% |
| Object | **94%** (n=50) | 88.4% |
| Goal | **86%** (n=50) | 79.2% |
| Long (libero_10) | **70%** (n=50) | 53.7% |
| **Average** | **84.0%** | 76.5% |
Beats OpenVLA-7B on every suite at 1/11 the parameters and ~1/50 the online compute.
XS-VLA (90.3 avg) remains ahead β their latent flow matching is future work for us.
### LIBERO-Spatial (100 episodes, 10 per task, init states 0-9)
| Mode | Success |
|---|---|
| Full-rate (latent every chunk) | 79/100 = **79%** |
| **Dual-rate (latent @ 1 Hz)** | 86/100 = **86%** |
Dual-rate β₯ full-rate consistently across all evals (also 65% vs 58% at ft3, n=50) β
a stable cached latent appears to act as temporal regularization.
### Context (published numbers, their own eval protocols)
| Model | Params | LIBERO-Spatial | 4-suite avg |
|---|---|---|---|
| MolmoAct2-LIBERO | 5B | 98.4% (**97.2% re-measured on our rig**, n=500) | **98.25%** |
| Ο0 | 3.3B | 98% | β |
| SmolVLA-2.25B | 2.25B | 93% | β |
| XS-VLA | 0.26B | ~93% | 90.3% |
| MolmoAct-7B (v1) | 7B | 87.0% | 86.6% |
| **TinyVLA (this)** | **0.64B (140M online)** | **86% dual-rate** | **84.0%** |
| OpenVLA | 7B | 84.7% | 76.5% |
**MolmoAct2 context** (from their cards/repo, no numeric tables published outside the
LIBERO-LeRobot card): 5B params on Molmo2-ER backbone + flow expert; claims to beat Ο0.5;
Molmo2-ER reportedly surpasses GPT-5 / Gemini-Robotics-ER-1.5 on 13 embodied-reasoning
benchmarks; #1 VLA on the MolmoSpace leaderboard. Inference needs ~26GB fp32 (16GB bf16),
cuda-graphs for ~2Γ speedup β H100-class serving vs our Raspberry-Pi-class 140M fast path.
Notably they ship **MolmoAct2-SO100_101** (absolute joint control) β a 5B competitor on our
target embodiment; a head-to-head offline eval on SO101 held-out data is an obvious next test.
Honesty notes: our n=100 (Β±8pp) vs their 500; single suite; eval covers init states 0β9
per task (demos of same tasks/init states are in training data β this is the standard
LIBERO protocol used by all listed models). Multi-suite evals (object/goal/long) and an
identically-protocoled SmolVLA baseline run are in progress.
### Dual-rate validation (the architectural claim)
- Offline: held-out chunk MSE with latent from a frame 2s earlier == fresh (0.772 vs 0.772).
- Closed-loop: 86% @ 1 Hz refresh vs 79% full-rate.
- Deployment implication (Raspberry Pi 5): the 0.5B slow path can run at 0.5β1 Hz
(llama.cpp GGUF Q4 territory), only the 140M fast path needs real-time rates.
## 4. Pitfalls we hit (read before reproducing)
1. **robosuite/LIBERO renders are 180Β°-rotated** vs recorded datasets. A vertical flip
alone leaves a horizontal MIRROR β the policy reaches to the wrong side and scores 0%.
Use `img[::-1, ::-1]`. (lerobot's `LiberoEnv.render()` flips for visualization but
`_format_raw_obs` feeds policies raw rotated frames β check your eval path.)
2. **eef orientation antipodal ambiguity**: env quat β rotvec gives βΟ-ish x-component,
datasets store +Ο-ish. Canonicalize (flip antipodal representation when rotvec_x < 0)
or your normalized state input is off by ~17Ο.
3. **HuggingFaceVLA/libero meta says fps=10 but frames are native 20 Hz** (~161
frames/episode β 8s demos). Do NOT action-repeat at eval.
4. **GT-replay harness is the decisive convention test**: replay dataset actions in the env
(first episode per task β init_state 0). 4/5 success = conventions right; policy-independent.
5. HuggingFaceVLA community_dataset v1/v3 are aggregates of v2.1 sub-datasets β convert with
lerobot's `convert_dataset_v21_to_v30.py`; 4/44 sources have metaβ parquet row counts
(broken at source) β validate `len(reader.hf_dataset) == meta.total_frames`.
6. Qwen3.5 custom forwards need `mm_token_type_ids` for M-RoPE; patchify must match the
official processor bit-exact (verify!). Linear-attention needs fla-core + causal-conv1d
or you get a 5Γ slower torch fallback.
7. Flow-matching loss can drop while conditioning is ignored β A/B with shuffled
observations to verify the model actually uses them.
## 5. Repository layout
```
src/tinyvla/ # LeRobot plugin: configuration/modeling/processor + modules
scripts/train.py # accelerate loop: weighted mixture, staleness aug, distill loss, resume
scripts/eval_libero.py # closed-loop LIBERO eval (all convention fixes, dual-rate, video)
scripts/replay_libero.py, diag_obs_gap.py # convention diagnostics
scripts/prepare_community_v3.py, label_spatial.py, eval_offline.py
configs/ # stage2/stage3/libero_ft* yaml
checkpoints/ # stage2_final, stage3_final, libero_ft4_final (main)
videos/ # sample eval episodes
```
## 6. Quick start
```python
from tinyvla.modeling_tinyvla import TinyVLAPolicy
policy = TinyVLAPolicy.from_pretrained("AlexWortega/tinyvla") # ft4 checkpoint at root
# closed-loop LIBERO: python scripts/eval_libero.py --checkpoint <ckpt> \
# --suite libero_spatial --episodes 100 --n-action-steps 10 --refresh-s 1.0
```
Trained 2026-08-14 β 2026-08-19 on 1Γ RTX A6000 (48GB), lerobot 0.6.1, torch 2.10, transformers 5.5.4.
|