FastOPD: On-Policy Distillation for Lightweight VLA Deployment
Organizations: KAIST · Sungkyunkwan University
Abstract
Vision-Language-Action (VLA) foundation models have scaled rapidly to enhance manipulation performance and generalizability, but this scaling incurs high computational costs that render real-world deployment increasingly challenging. Existing approaches typically mitigate this issue by designing smaller architectures or reducing the iterative denoising steps in flow-based policies. In this work, we propose FastOPD, a foundation-to-lightweight VLA framework that enables the practical deployment of large-scale VLAs through efficient on-policy distillation. Specifically, FastOPD adapts a flow map for single-state teacher supervision and combines it with a self-consistency objective to construct a compact student that learns the teacher dynamics. Furthermore, we theoretically demonstrate that minimizing this objective allows the distilled student to recover a distribution on par with that induced by an ideal few-step teacher model. We evaluate FastOPD across diverse foundation policies in simulation and real-world experiments. On LIBERO, FastOPD retains 84% of the performance of with only two inference steps, reducing inference latency by 78.1% while outperforming existing few-step distillation baselines in average success rate. With LingBot-VLA as the teacher, FastOPD improves the single-step success rate over the base student by 15.9 percentage points on RoboTwin 2.0. We further demonstrate its applicability to a World Action Model (WAM) and deploy a compact student distilled from MolmoAct2 on a real robot.
Figures & tables
Appendix figures & tables13 assets
Supplementary material from the paper’s appendix.
Appendix
| Benchmark | Model | Checkpoint |
| LIBERO | lerobot/pi05_libero_finetuned_v044 | |
| SmolVLA | HuggingFaceVLA/smolvla_libero | |
| SmolVLA (OPD Init) | lerobot/smolvla_base | |
| RoboTwin 2.0 | LingBot-VLA | robbyant/lingbot-vla-4b-posttrain-robotwin |
| Fast-WAM | lerobot/fastwam_robotwin_uncond_3cam_384 | |
| SmolVLA | lerobot/smolvla_robotwin |
| LIBERO | RoboTwin 2.0 | Real-world | ||
| Model | ||||
| Teacher (Params) | (3.3B) | LingBot-VLA (4.2B) | Fast-WAM (6B) | MolmoAct2 (5B) |
| Student (Params) | SmolVLA + (451M) | SmolVLA + (451M) | SmolVLA + (451M) | SmolVLA + (451M) |
| Optimization | ||||
| Optimizer | AdamW | AdamW | AdamW | AdamW |
| Adam | ||||
| Experiment | Hardware |
| LIBERO (main) | NVIDIA RTX 4090 (24 GB) |
| LIBERO (ablations) | NVIDIA RTX 4090 or RTX 3090 (24 GB each) |
| RoboTwin 2.0 (LingBot-VLA) | NVIDIA RTX 4090 (24 GB each) |
| RoboTwin 2.0 (Fast-WAM) | NVIDIA H200 (141 GB) |
| Real-world | NVIDIA B200 (180 GB) |
| Task | Language instruction | Episodes | Frames | Avg. Length (s) |
| pnp-plate | “Pick up the ball and place it on the plate.” | 106 | 47,002 | 14.8 |
| pnp-box | “Pick up the basketball and place it in the box.” | 108 | 47,616 | 14.7 |
| open-close | “Open the box, put the ball inside, and close it.” | 53 | 44,780 | 28.2 |
| “Open the box, put the basketball inside, and close it.” | 55 | 46,834 | 28.4 | |
| open-place | “Open the box, take the ball out, and place it in the pot.” | 52 | 41,637 | 26.7 |
| “Open the box, take the ball out, and place it on the tray.” | 50 | 40,676 | 27.1 |
| MolmoAct2 | SmolVLA (warm-up) | Ours | |
| Execution | async (re-plan every 0.5 s) | sync | sync |
| Sampler | Euler, 10 steps | Euler, 4 / 10 steps | flow map, 4 steps |
| Actions executed per chunk | 15 | 30 | 30 |
| Chunk blending | linear (2–10 steps) | none | none |
| Inference latency | 300–450 ms | 118 / 178 ms | 120 ms |
| Re-planning rate | 1.8–1.9 Hz | 0.89 / 0.86 Hz | 0.87 Hz |
| Method | NFE | Spatial | Object | Goal | Long | Avg. |
| OPD init. | 1 | 78.0 | 94.2 | 78.2 | 40.2 | 72.7 |
| 2 | 84.4 | 95.4 | 87.8 | 45.0 | 78.2 | |
| 4 | 58.0 | 59.8 | 53.8 | 5.0 | 44.2 | |
| 10 | 82.6 | 94.6 | 89.0 | 48.2 | 78.6 | |
| + FastOPD | 1 | 84.2 | 92.8 | 90.8 | 54.0 | 80.5 |
| 2 | 84.6 | 95.2 | 94.2 | 57.8 | 83.0 |
| Task | LingBot-VLA | Fast-WAM | SmolVLA | Ours (LingBot-VLA) | Ours (Fast-WAM) | |||||
| Clean | Random | Clean | Random | Clean | Random | Clean | Random | Clean | Random | |
| adjust_bottle | 98 | 90 | 100 | 100 | 100 | 98 | 100 | 98 | 100 | 98 |
| beat_block_hammer | 78 | 78 | 100 | 96 | 66 | 66 | 56 | 40 | 76 | 78 |
| blocks_ranking_rgb | 96 | 92 | 100 | 100 | 50 | 46 | 50 | 58 | 30 | 30 |
| blocks_ranking_size | 74 | 66 | 88 | 96 | 20 | 22 | 28 | 26 | 20 | 10 |
| click_alarmclock | 70 | 42 | 100 | 100 | 90 | 94 | 34 | 50 | 92 | 96 |
| Task | Ours (LingBot-VLA) | Ours (Fast-WAM) | ||||||||||
| 1-step | 2-step | 4-step | 1-step | 2-step | 4-step | |||||||
| Clean | Random | Clean | Random | Clean | Random | Clean | Random | Clean | Random | Clean | Random | |
| adjust_bottle | 94 | 96 | 100 | 98 | 100 | 98 | 94 | 98 | 100 | 96 | 100 | 98 |
| beat_block_hammer | 72 | 58 | 84 | 68 | 66 | 66 | 56 | 50 | 76 | 68 | 80 | 74 |
| blocks_ranking_rgb | 34 | 32 | 38 | 44 | 52 | 56 | 34 | 32 | 44 | 32 | 32 | 32 |
| blocks_ranking_size | 6 | 6 | 20 | 18 | 28 | 16 | 12 | 8 | 12 | 10 | 20 | 14 |