LeRobot documentation

LingBot-VA

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v0.6.0).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

LingBot-VA

LingBot-VA is an autoregressive video-action world-model policy built on the Wan2.2 video-diffusion stack. It interleaves, in one autoregressive sequence, the prediction of future video latents and robot actions (“VA” = Video-Action). The LeRobot integration wires LingBot-VA into the standard training, evaluation and processor interfaces.

Model Overview

LingBot-VA is a dual-stream “mixture-of-transformers”: a video/latent stream (patch_embedding_mlp → blocks → proj_out) and an action stream (action_embedder → blocks → action_proj_out) share the same 30 transformer blocks and text conditioning.

ComponentClassRole
DiT backbone (trainable)WanTransformer3DModel~5B-param dual-stream transformer.
VAE (frozen)AutoencoderKLWanWan2.2 VAE, z_dim=48. Lazy-pulled from the source repo.
Text encoder (frozen)UMT5EncoderModelUMT5-XXL, d_model=4096. Lazy-pulled from the source repo.

At inference the policy runs an autoregressive loop per chunk: it denoises the video-latent stream (CFG, ~20 steps) and the action stream (~50 steps) with two independent flow-matching schedulers, maintaining a KV cache across chunks. Real observed keyframes are fed back into the KV cache as the chunk is executed (closed-loop world modeling).

What the LeRobot Integration Covers

  • Standard policy.type=lingbot_va configuration through LeRobot.
  • Ready-to-use LeRobot-format checkpoints on the Hub (converted from the released upstream ones).
  • Autoregressive dual-stream inference behind the standard select_action interface (single-environment eval, --eval.batch_size=1).
  • Opt-in saving of the policy’s predicted (imagined) videos during eval / training.
  • Evaluation with lerobot-eval on LIBERO and RoboTwin.
  • Training / fine-tuning via the dual-stream flow-matching loss (policy.forward), see below.

Installation

  1. Install LeRobot by following the Installation Guide.
  2. Install the LingBot-VA extra:
pip install -e ".[lingbot_va]"

Checkpoints

The released upstream checkpoints have been converted to LeRobot format and pushed to the Hub:

VariantLeRobot checkpoint
LIBERO-Long post-trainlerobot/lingbot_va_libero_long
RoboTwin post-trainlerobot/lingbot_va_robotwin
Pretrained baselerobot/lingbot_va_base

Only the trainable ~5B transformer is stored in the LeRobot model.safetensors. The frozen VAE + UMT5 + tokenizer (~20 GB) are pulled from config.wan_pretrained_path at load time (defaults to the source robbyant/* repo). The UMT5-XXL text encoder runs on CPU by default (config.text_encoder_device) so the 5B transformer + VAE fit on a single 24–32 GB GPU.

Evaluation (LIBERO)

lerobot-eval \
    --policy.path=lerobot/lingbot_va_libero_long \
    --policy.device=cuda \
    --env.type=libero --env.task=libero_10 \
    --env.observation_height=128 --env.observation_width=128 \
    --eval.n_episodes=50 --eval.batch_size=1 \
    --output_dir=outputs/eval/lingbot_va_libero

LingBot-VA’s streaming inference (KV cache + observed-keyframe feedback) is implemented for single-environment eval; use --eval.batch_size=1.

Evaluation (RoboTwin)

RoboTwin 2.0 needs the SAPIEN + CuRobo simulator stack. You can use the benchmark Docker image (docker/Dockerfile.benchmark.robotwin, which also needs warp-lang==1.3.1 and CuRobo built with the GPU’s compute capability in TORCH_CUDA_ARCH_LIST). RoboTwin uses end-effector-pose control, so run with --env.action_mode=ee: the policy predicts per-arm xyz+quaternion+gripper deltas (robotwin_tshape latent layout) that are composed onto the episode’s initial eef pose and executed via CuRobo IK.

lerobot-eval \
    --policy.path=lerobot/lingbot_va_robotwin \
    --policy.device=cuda \
    --env.type=robotwin --env.task=beat_block_hammer --env.action_mode=ee \
    --eval.n_episodes=10 --eval.batch_size=1 \
    --output_dir=outputs/eval/lingbot_va_robotwin

Saving predicted (imagined) videos

Set --policy.save_predicted_video=true to additionally VAE-decode the predicted video latents and write pred_episode_*.mp4 next to the env-rendered eval_episode_*.mp4 videos. The same flag works for the periodic eval during lerobot-train.

Training / fine-tuning

LingBotVAPolicy.forward(batch) implements the dual-stream flow-matching loss (latent_loss + action_loss, timestep-weighted, action-masked) from the paper: it VAE-encodes the camera clips into video latents, UMT5-encodes the task, noises both streams, runs the transformer’s block-causal training pass and returns (loss, metrics). Optimizer preset is AdamW with a linear-warmup-then-constant schedule (matching upstream).

Requirements:

  • The block-causal masks use PyTorch flex-attention, so build the policy with --policy.attn_mode=flex for training (the default torch SDPA is inference-only).
  • The full 5B DiT does not fit a single 24–32 GB GPU under AdamW; fine-tune with LoRA (--policy.use_peft=true) and/or optimizer offload. get_optim_params returns only the trainable (e.g. adapter) parameters; the VAE + UMT5 text encoder stay frozen.
lerobot-train \
  --policy.path=lerobot/lingbot_va_libero_long --policy.attn_mode=flex \
  --policy.use_peft=true \
  --dataset.repo_id=<your LeRobot-format dataset> \
  --batch_size=1 --steps=... --output_dir=outputs/train/lingbot_va

The dataset must provide camera clips (a temporal window per camera, VAE-encoded to frame_chunk_size latent frames) and frame_chunk_size * action_per_frame action steps per item.

Data format (action channels & camera order)

LingBot-VA is an end-effector (Cartesian) pose policy, it predicts EEF poses + gripper, not joint positions. Actions live in a fixed multi-embodiment 30-dim layout; map your robot’s action dimensions into these channels and pad the rest with 0 (used_action_channel_ids selects the channels a given checkpoint actually uses):

channelsmeaning
0–6Left-arm end-effector pose
7–13Right-arm end-effector pose
14–20Left-arm joints (unused by the released checkpoints)
21–27Right-arm joints (unused by the released checkpoints)
28Left gripper
29Right gripper
  • LIBERO uses channels 0–6: a 6-DoF EEF delta (xyz + rotation) + gripper (single arm).
  • RoboTwin uses channels [0–6, 28, 7–13, 29]: left EEF (xyz + quaternion) + left gripper + right EEF + right gripper (16 dims). The env converts these poses to joint trajectories via CuRobo IK — joints are never predicted.

Joint-space datasets (or a different EEF convention) must be remapped into this schema before fine-tuning these checkpoints.

Camera order is fixed and order-sensitive, per-camera latents are concatenated spatially in obs_cam_keys order, so the physical camera→slot mapping must match training:

benchmarkobs_cam_keys (in order)camera_layout
LIBEROobservation.images.image (agentview / 3rd-person), observation.images.image2 (eye-in-hand wrist)width_concat (latents concatenated on width)
RoboTwinobservation.images.head_camera, observation.images.left_camera, observation.images.right_camerarobotwin_tshape (full-res head below, two half-res wrists on top)

The first camera is the exterior/head view and the rest are wrist views.

Inference Hyperparameters (LIBERO)

KeyValue
height × width128 × 128
camerasobservation.images.image (agentview), observation.images.image2 (eye-in-hand)
action channels used0–6 (7-DoF arm + gripper)
action_per_frame / frame_chunk_size4 / 4
attn_window30
video / action denoising steps20 / 50
guidance_scale / action_guidance_scale5 / 1
snr_shift / action_snr_shift5.0 / 0.05

These are the defaults of LingBotVAConfig; override any of them via --policy.<name>=....

Notes

  • Attention backend: inference uses the torch SDPA backend (always available). The flashattn and flex backends are optional; flex is only needed for training.
  • Model size: the DiT is ~5B params and the frozen VAE+UMT5 add ~20 GB; inference needs roughly 18–24 GB of VRAM.

License

LingBot-VA is released under Apache-2.0. See the upstream repository.

Update on GitHub