LeRobot documentation

LingBot-VLA 2.0

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

LingBot-VLA 2.0

LingBot-VLA 2.0 est le modèle vision-langage-action de Robbyant, successeur de LingBot-VLA 1.0. Il associe un squelette Qwen3-VL-4B à un expert d’action Qwen2 en Mixture-of-Experts creux (32 experts, routage top-4) et génère des blocs d’actions par flow matching dans un espace d’état/action canonique de 55 dimensions partagé entre les incarnations.

Le port LeRobot est la politique lingbot_vla_v2. Il utilise les jeux de données, les processeurs, lerobot-train, lerobot-eval et lerobot-rollout standards de LeRobot, y compris la distillation de profondeur et de vidéo à double requête de l’amont.

Pour plus de détails sur le modèle, consultez le dépôt amont et le rapport technique.

Installation

pip install -e ".[training,lingbot_vla_v2]"

Le tokenizer et le processeur d'images de Qwen3-VL sont chargés depuis Qwen/Qwen3-VL-4B-Instruct (--policy.tokenizer_path) lors de la construction du processeur. flash-attn n'est pas nécessaire ; l'attention utilise PyTorch SDPA.

Points de contrôle

Point de contrôleSourceUtiliser
lerobot/lingbot_vla_v2_baserobbyant/lingbot-vla-v2-6b, conversion au format uniquementPoint de départ pour le fine-tuning. Les caractéristiques correspondent à la disposition canonique complète de 55 dimensions ; passez les correspondances de slots pour votre robot.
lerobot/lingbot_vla_v2_robotwinrobbyant/lingbot-vla-v2-6b-robotwin, étape 50000Évaluation RoboTwin 2.0. État/action 14-D, caméras cam_high, cam_left_wrist, cam_right_wrist, normalisation QUANTILES (q01/q99).

Chargez l’un ou l’autre avec --policy.path ; le type de politique est lu depuis le config.json du point de contrôle.

Cartographier un robot sur la disposition canonique

Le modèle reçoit un état de 55 dimensions et prédit des actions de 55 dimensions. La disposition est définie par canonical_joints dans la configuration :

SlotDimensionsContenu
arm.position14positions des articulations du bras
end.position14poses de l'effecteur terminal
effector.position2positions du gripper
hand.position12articulations de la main habile
waist.position4articulations de la taille
head.position2articulations de tête
base.velocity3vitesse de base mobile
reserved.slots4réservé

--policy.state_slots et --policy.action_slots associent les plages de observation.state et action de votre jeu de données à ces slots, au format JSON :

{
  "observation.state.arm.position": {
    "origin_keys": [{ "observation.state": { "start": 0, "end": 5 } }]
  }
}
  • Les noms de slots sont les noms canoniques ci-dessus, éventuellement préfixés par observation.state. ou action.. Les noms inconnus déclenchent une erreur.
  • Chaque slot lit une ou plusieurs plages {start, end} depuis observation.state (slots d'état) ou action (slots d'action). Les plages sont concaténées et empilées depuis le début du slot ; le reste du slot est complété par des zéros et exclu de la perte.
  • En l'absence de correspondance de slots, les caractéristiques brutes sont interprétées selon la disposition canonique de 55 dimensions, comme dans le point de contrôle de base.
  • Les actions relatives sont désactivées par défaut. --policy.use_relative_actions=true soustrait l'état actuel de l'action, à l'exception des dimensions dont le nom contient une entrée de --policy.relative_exclude_joints (par défaut ["gripper"]).

Le postprocesseur inverse le mappage, de sorte que select_action renvoie des actions dans l’espace d’actions brut de votre robot. Les points de contrôle affinés enregistrent les mappages de slots et les statistiques du jeu de données avec leurs processeurs.

Caméras

L’étape d’image lit les caméras listées dans input_features du checkpoint, dans cet ordre. Pour le checkpoint de base, il s’agit de camera_top, camera_wrist_left et camera_wrist_right. Associez les caméras de votre jeu de données à celles-ci à l’aide de --rename_map ; les vues dont votre robot ne dispose pas sont masquées.

Ajustement fin

Exemple sur maximellerbach/omx_multicubes, un bras unique avec 5 articulations et une pince et deux caméras (top, wrist) :

lerobot-train \
  --dataset.repo_id=maximellerbach/omx_multicubes \
  --policy.path=lerobot/lingbot_vla_v2_base \
  --policy.state_slots='{"observation.state.arm.position": {"origin_keys": [{"observation.state": {"start": 0, "end": 5}}]}, "observation.state.effector.position": {"origin_keys": [{"observation.state": {"start": 5, "end": 6}}]}}' \
  --policy.action_slots='{"action.arm.position": {"origin_keys": [{"action": {"start": 0, "end": 5}}]}, "action.effector.position": {"origin_keys": [{"action": {"start": 5, "end": 6}}]}}' \
  --rename_map='{"observation.images.top": "observation.images.camera_top", "observation.images.wrist": "observation.images.camera_wrist_left"}' \
  --policy.dtype=float32 \
  --accelerator.mixed_precision=bf16 \
  --policy.repo_id=your_repo_id \
  --batch_size=1 \
  --steps=30000 \
  --save_freq=5000 \
  --output_dir=outputs/train/lingbot_vla_v2_omx

Conservez les poids en fp32 et effectuez les calculs en bf16 (--policy.dtype=float32 --accelerator.mixed_precision=bf16), comme le fait l’implémentation amont. Avec --policy.dtype=bfloat16, l’optimiseur met à jour directement les poids en bf16, et la plupart des mises à jour sont trop faibles pour les modifier : sur ce jeu de données, 66 % des poids sont restés identiques au bit près par rapport au point de contrôle de base, et la politique affinée était beaucoup plus saccadée. Effectuez également l’inférence en fp32 (la valeur par défaut d’un point de contrôle entraîné de cette manière) ; l’inférence en bf16 rend les segments d’actions nettement moins fluides.

Les statistiques de normalisation proviennent du jeu de données. L’entraînement multi-GPU utilise le lanceur standard torchrun avec les drapeaux --parallelism.* et --accelerator.*. Les poids, gradients et état de l’optimiseur en fp32 occupent environ 96 Go, il est donc recommandé de les sharder avec --parallelism.dp_shard=<num_gpus> si une seule GPU est trop petite.

Distillation à double requête

LingBot-VLA 2.0 ajoute des jetons de requête appris (profondeur et vidéo actuelles et futures) après les jetons de langage, et l’expert d’action leur accorde de l’attention. Les deux points de contrôle contiennent la recette amont dans align_params, de sorte que les jetons de requête sont toujours utilisés lors de l’inférence. Pendant l’entraînement, de petites têtes lisent ces jetons et sont distillées à partir d’enseignants figés (LingBot-Depth avec MoGe-2, et DINO-Video) avec les poids de perte amont ; les pertes supplémentaires sont journalisées sous la forme de depth_loss, future_depth_loss, current_video_loss et future_video_loss.

Les modèles enseignants sont téléchargés lors de la première étape d’entraînement (environ 3 Go depuis robbyant/lingbot-vla-v2-6b et Ruicheng/moge-2-vitb-normal), occupent environ 2 Go de mémoire GPU et ajoutent approximativement 130 ms par échantillon à chaque étape. Chaque échantillon charge également le cadre chunk_size - 1 étapes en avance, ce dont ont besoin les cibles futures. Rien d’autre ne s’exécute lors de l’inférence.

Paramètres d'entraînement clés

ParamètrePar défautDescription
state_slots / action_slotsnullSpans bruts vers slots canoniques (voir ci-dessus).
use_relative_actionsfalseEntraînez sur des actions relatives à l'état actuel.
loss_typeL1_fmPerte de flow-matching sur la vitesse.
normalization_mappingÉtat et action MEAN_STDLe checkpoint RoboTwin utilise QUANTILES.
train_expert_onlyfalseGeler le backbone de Qwen3-VL et entraîner uniquement l'expert d'action.
freeze_vision_encoderfalseGeler la tour de vision.
gradient_checkpointingfalseRecalculer les activations lors de la rétropropagation pour économiser de la mémoire au détriment du temps d'étape.
use_moe_expert_lrtrueLes experts routés s'entraînent à lr * sqrt(num_experts / top_k), comme en amont.
optimizer_lr / scheduler_decay_lr1e-5 / 1e-5Taux d'apprentissage maximal et final d'AdamW.
resize_imgs_with_padding[256, 256]Taille du cadre avant le processeur d'images Qwen3-VL, comme en amont.
image_max_pixels / image_min_pixels65536 / 65536Budget de pixels de Qwen3-VL : 64 jetons par caméra, comme en amont.
chunk_size / n_action_steps50 / 50Horizon prédit et nombre d'actions exécutées par bloc.
num_steps10Étapes de débruitage lors de l'inférence.
tokenizer_pathQwen/Qwen3-VL-4B-InstructTokeniseur et processeur d'images de Qwen3-VL. Utilisez un chemin local hors ligne.

Pour utiliser un GPU plus petit, combinez --policy.train_expert_only=true et --policy.gradient_checkpointing=true avec une petite valeur de --batch_size.

Évaluation

Évaluez le point de contrôle RoboTwin dans l’environnement RoboTwin de LeRobot (voir RoboTwin pour la configuration). La carte de renommage aligne les noms des caméras de l’environnement avec ceux du point de contrôle :

lerobot-eval \
  --policy.path=lerobot/lingbot_vla_v2_robotwin \
  --env.type=robotwin \
  --env.task=beat_block_hammer \
  --eval.batch_size=1 \
  --eval.n_episodes=100 \
  --rename_map='{"observation.images.head_camera": "observation.images.cam_high", "observation.images.left_camera": "observation.images.cam_left_wrist", "observation.images.right_camera": "observation.images.cam_right_wrist"}'

Taux de réussite moyen sur les 50 tâches de RoboTwin 2.0 (100 épisodes chacune), tel que rapporté dans le README amont pour le point de contrôle RoboTwin publié (post-entraînement Muon sur des données propres et aléatoires, inférence en FP32 avec le lanceur RoboTwin amont). Il s’agit de chiffres amont, non mesurés via ce portage.

Configurationπ0.5LingBot-VLA 1.0LingBot-VLA 2.0
Propre82.74%88.56%93.52%
Aléatoire76.76%86.68%92.80%

Accélération de l'inférence

Quatre drapeaux, tous désactivés par défaut, accélèrent select_action. Ils nécessitent CUDA et des formes d’entrée fixes, et n’entraînent aucune dépendance supplémentaire :

  • --policy.use_cudagraph_denoise=true : capture la boucle de débruitage en tant que graphique CUDA unique.
  • --policy.use_cudagraph_prefix=true : capture le remplissage KV du préfixe vision-langage.
  • --policy.use_cudagraph_prefix_full=true : capture également la tour de vision dans le graphe préfixe.
  • --policy.compile_predict_velocity=true : compile la prédiction de vitesse par étape avec torch.compile. Le premier appel prend environ une minute à compiler.

Il est temps pour un chunk d'action de 50 étapes avec 10 étapes de débruitage, checkpoint RoboTwin, une RTX PRO 6000 :

Drapeauxbf16fp32
none~756 ms~614 ms
les trois drapeaux de graphes CUDA~180 ms~203 ms
les trois drapeaux CUDA graph + compile~120 ms~156 ms

En bf16, les graphes CUDA produisent les mêmes résultats que le mode eager ; torch.compile modifie légèrement les valeurs numériques.

Déploiement

Exécuter un point de contrôle affiné sur un robot avec lerobot-rollout, en transmettant le même --rename_map que lors de l’entraînement :

lerobot-rollout \
  --strategy.type=base \
  --policy.path=outputs/train/lingbot_vla_v2_omx/checkpoints/last/pretrained_model \
  --robot.type=<your_robot_type> \
  --robot.port=<port> \
  --task="pick up the cube" \
  --fps=30 \
  --device=cuda

Le découpage en temps réel est disponible avec --inference.type=rtc, comme pour les autres politiques de flow-matching.

Citation

@article{lingbotvla2,
      title={From Foundation to Application: Improving VLA Models in Practice},
      author={Wei Wu and Fangjing Wang and Fan Lu and He Sun and Shi Liu and Yunnan Wang and Yibin Yan and Yong Wang and Shuailei Ma and Xinyang Wang and Yibin Liu and Shuai Yang and Tianxiang Zhou and Kejia Zhang and Lei Zhou and Cheng Su and Nan Xue and Bin Tan and Han Zhang and Youchao Zhang and Fei Liao and Xing Zhu and Yujun Shen and Kecheng Zheng},
      journal={arXiv preprint arXiv:2607.06403},
      year={2026}
}

Licence

Le code et les points de contrôle convertis sont sous licence Apache-2.0, tout comme les versions amont de LingBot-VLA 2.0 et Qwen3-VL.

L’entraînement par distillation télécharge trois enseignants figés sous leurs propres licences (l’inférence ne les charge jamais) :

EnseignantPoidsLicence
MoGe-2Ruicheng/moge-2-vitb-normalMIT
LingBot-Depthrobbyant/lingbot-vla-v2-6b (depth/)Apache-2.0
DINO-Videorobbyant/lingbot-vla-v2-6b (dino_video/)License de DINOv3

Les poids de DINO-Video sont dérivés de DINOv3 de Meta, de sorte que l’entraînement par distillation implique de les utiliser sous la DINOv3 License, qui, entre autres conditions, vous demande de citer DINOv3 dans vos publications et restreint certains usages finaux.

Update on GitHub