LeRobot documentation
LingBot-VLA 2.0
LingBot-VLA 2.0
LingBot-VLA 2.0 é o modelo de visão-linguagem-ação da Robbyant, sucessor do LingBot-VLA 1.0. Ele combina um backbone Qwen3-VL-4B com um especialista de ação Qwen2 baseado em Mixture-of-Experts esparsa (32 especialistas, roteamento top-4) e gera blocos de ações por meio de flow matching em um espaço canônico de estado/ação de 55 dimensões compartilhado entre diferentes embodiments.
A port do LeRobot é a política lingbot_vla_v2. Ela usa datasets, processadores, lerobot-train, lerobot-eval e lerobot-rollout padrão do LeRobot, incluindo a destilação de profundidade e vídeo de consulta dupla do upstream.
Para mais detalhes sobre o modelo, consulte o repositório original e o relatório técnico.
Instalação
pip install -e ".[training,lingbot_vla_v2]"O tokenizer e o processador de imagens do Qwen3-VL são carregados de Qwen/Qwen3-VL-4B-Instruct (--policy.tokenizer_path)
quando o processador é construído. flash-attn não é necessário; a atenção usa PyTorch SDPA.
Checkpoints
| Checkpoint | Fonte | Usar |
|---|---|---|
lerobot/lingbot_vla_v2_base | robbyant/lingbot-vla-v2-6b, conversão apenas de formato | Ponto de partida para o ajuste fino. Os recursos são o layout canônico completo de 55 dimensões; passe os mapeamentos de slots para o seu robô. |
lerobot/lingbot_vla_v2_robotwin | robbyant/lingbot-vla-v2-6b-robotwin, etapa 50000 | Avaliação do RoboTwin 2.0. Estado/ação de 14 dimensões, câmeras cam_high, cam_left_wrist, cam_right_wrist, normalização QUANTILES (q01/q99). |
Carregue um deles com --policy.path; o tipo de política é lido do config.json do checkpoint.
Mapeando um robô para o layout canônico
O modelo vê um estado de 55-D e prevê ações de 55-D. O layout é definido por canonical_joints na configuração:
| Slot | Dimensões | Conteúdo |
|---|---|---|
arm.position | 14 | posições das articulações do braço |
end.position | 14 | poses do efector |
effector.position | 2 | posições do garfo |
hand.position | 12 | juntas de mão ágil |
waist.position | 4 | juntas da cintura |
head.position | 2 | juntas da cabeça |
base.velocity | 3 | velocidade base do celular |
reserved.slots | 4 | reservado |
--policy.state_slots e --policy.action_slots mapeiam os intervalos de observation.state e action do seu conjunto de dados para esses slots, como JSON:
{
"observation.state.arm.position": {
"origin_keys": [{ "observation.state": { "start": 0, "end": 5 } }]
}
}- Os nomes dos slots são os nomes canônicos acima, opcionalmente prefixados com
observation.state.ouaction.. Nomes desconhecidos geram um erro. - Cada slot lê um ou mais intervalos
{start, end}deobservation.state(slots de estado) ouaction(slots de ação). Os intervalos são concatenados e empacotados a partir do início do slot; o restante do slot é preenchido com zeros e excluído da perda. - Sem o mapeamento de slots, os recursos brutos são assumidos como o layout canônico de 55-D, como no checkpoint base.
- Ações relativas estão desativadas por padrão.
--policy.use_relative_actions=truesubtrai o estado atual da ação, exceto para dimensões cujo nome contém uma entrada de--policy.relative_exclude_joints(padrão["gripper"]).
O pós-processador inverte o mapeamento, de modo que select_action retorna ações no espaço de ação bruto do seu robô.
Os checkpoints de ajuste fino salvam os mapeamentos de slots e as estatísticas do conjunto de dados junto com seus processadores.
Câmeras
A etapa de imagem lê as câmeras listadas em input_features do checkpoint, nessa ordem. Para o checkpoint base, elas são camera_top, camera_wrist_left e camera_wrist_right. Mapeie as câmeras do seu conjunto de dados para elas com --rename_map; as visões que seu robô não possui são mascaradas.
Ajuste fino
Exemplo em maximellerbach/omx_multicubes, um
braço único com 5 juntas e uma garra e duas câmeras (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_omxMantenha os pesos em fp32 e calcule em bf16 (--policy.dtype=float32 --accelerator.mixed_precision=bf16), como o upstream faz. Com --policy.dtype=bfloat16, o otimizador atualiza os pesos em bf16 diretamente, e a maioria das atualizações é pequena demais para alterá-los: neste conjunto de dados, 66% dos pesos permaneceram idênticos bit a bit ao checkpoint base, e a política ajustada ficou muito mais irregular. Execute a inferência também em fp32 (o padrão de um checkpoint treinado dessa forma); a inferência em bf16 torna os blocos de ações visivelmente menos suaves.
As estatísticas de normalização vêm do conjunto de dados. O treinamento multi-GPU usa o lançador padrão torchrun com as flags --parallelism.* e --accelerator.*. Os pesos, gradientes e estado do otimizador em fp32 ocupam cerca de 96 GB, portanto, fragmente-os com --parallelism.dp_shard=<num_gpus> quando uma GPU for pequena demais.
Destilação de consulta dupla
O LingBot-VLA 2.0 adiciona tokens de consulta aprendidos (profundidade e vídeo atuais e futuros) após os tokens de linguagem, e o especialista de ações presta atenção a eles. Ambos os checkpoints carregam a receita do upstream em align_params, de modo que os tokens de consulta são sempre usados na inferência. Durante o treinamento, cabeças pequenas leem esses tokens e são destiladas de professores congelados (LingBot-Depth com MoGe-2 e DINO-Video) com os pesos de perda do upstream; as perdas extras são registradas como depth_loss, future_depth_loss, current_video_loss e future_video_loss.
Os professores são baixados no primeiro passo de treinamento (cerca de 3 GB de robbyant/lingbot-vla-v2-6b e Ruicheng/moge-2-vitb-normal), ocupam cerca de 2 GB de memória de GPU e adicionam aproximadamente 130 ms por amostra a cada passo.
Cada amostra também carrega o quadro chunk_size - 1 passos à frente, o que é necessário para os alvos futuros. Nada extra
é executado na inferência.
Principais parâmetros de treinamento
| Parâmetro | Padrão | Descrição |
|---|---|---|
state_slots / action_slots | null | Spans brutos para slots canônicos (veja acima). |
use_relative_actions | false | Treine com ações relativas ao estado atual. |
loss_type | L1_fm | Perda de flow-matching na velocidade. |
normalization_mapping | estado e ação MEAN_STD | O checkpoint do RoboTwin usa QUANTILES. |
train_expert_only | false | Congele o backbone do Qwen3-VL e treine apenas o especialista de ação. |
freeze_vision_encoder | false | Congele a torre de visão. |
gradient_checkpointing | false | Recalcule as ativações no passo de retropropagação para economizar memória, com o custo de aumentar o tempo de cada passo. |
use_moe_expert_lr | true | Os especialistas roteados treinam com lr * sqrt(num_experts / top_k), como no upstream. |
optimizer_lr / scheduler_decay_lr | 1e-5 / 1e-5 | Taxa de aprendizado de pico e final do AdamW. |
resize_imgs_with_padding | [256, 256] | Tamanho do quadro antes do processador de imagem do Qwen3-VL, conforme o upstream. |
image_max_pixels / image_min_pixels | 65536 / 65536 | Orçamento de pixels do Qwen3-VL: 64 tokens por câmera, conforme o upstream. |
chunk_size / n_action_steps | 50 / 50 | Horizonte previsto e número de ações executadas por bloco. |
num_steps | 10 | Etapas de remoção de ruído na inferência. |
tokenizer_path | Qwen/Qwen3-VL-4B-Instruct | Tokenizer e processador de imagem do Qwen3-VL. Use um caminho local offline. |
Para caber em uma GPU menor, combine --policy.train_expert_only=true e --policy.gradient_checkpointing=true com um
--batch_size pequeno.
Avaliação
Avalie o checkpoint do RoboTwin no ambiente RoboTwin do LeRobot (veja RoboTwin para a configuração). O mapa de renomeação alinha os nomes das câmeras do ambiente com os do checkpoint:
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"}'Sucesso médio nas 50 tarefas do RoboTwin 2.0 (100 episódios cada), conforme relatado no README upstream para o checkpoint do RoboTwin liberado (Muon pós-treinamento em dados limpos e randomizados, inferência em FP32 com o launcher upstream do RoboTwin). Estes são números upstream, não medidos por meio deste port.
| Configuração | π0.5 | LingBot-VLA 1.0 | LingBot-VLA 2.0 |
|---|---|---|---|
| Limpo | 82.74% | 88.56% | 93.52% |
| Aleatório | 76.76% | 86.68% | 92.80% |
Aceleração de inferência
Quatro flags, todas desativadas por padrão, aceleram o select_action. Elas exigem CUDA e formatos de entrada fixos, e não requerem dependências extras:
--policy.use_cudagraph_denoise=true: captura o loop de denoising como um único grafo CUDA.--policy.use_cudagraph_prefix=true: captura o preenchimento do KV do prefixo de visão-linguagem.--policy.use_cudagraph_prefix_full=true: também captura a torre de visão no grafo de prefixo.--policy.compile_predict_velocity=true: aplicatorch.compileà previsão de velocidade por etapa. A primeira chamada leva cerca de um minuto para compilar.
Tempo para um chunk de ação de 50 passos com 10 passos de desruidamento, checkpoint do RoboTwin, uma RTX PRO 6000:
| Flags | bf16 | fp32 |
|---|---|---|
| none | ~756 ms | ~614 ms |
| os três flags de CUDA graph | ~180 ms | ~203 ms |
| os três flags de CUDA graph + compile | ~120 ms | ~156 ms |
Em bf16, os CUDA graphs produzem as mesmas saídas que o modo eager; torch.compile altera levemente os valores numéricos.
Implantação
Execute um checkpoint ajustado em um robô com lerobot-rollout, passando o mesmo --rename_map usado no treinamento:
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=cudaO Real-Time Chunking está disponível com --inference.type=rtc, assim como as outras políticas de flow-matching.
Citação
@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}
}Licença
O código e os checkpoints convertidos são Apache-2.0, assim como as versões upstream do LingBot-VLA 2.0 e do Qwen3-VL.
O treinamento por destilação baixa três professores congelados sob suas próprias licenças (a inferência nunca os carrega):
| Professor | Pesos | Licença |
|---|---|---|
| MoGe-2 | Ruicheng/moge-2-vitb-normal | MIT |
| LingBot-Depth | robbyant/lingbot-vla-v2-6b (depth/) | Apache-2.0 |
| DINO-Video | robbyant/lingbot-vla-v2-6b (dino_video/) | Licença do DINOv3 |
Os pesos do DINO-Video são derivados do DINOv3 da Meta, portanto, treinar com destilação significa usá-los sob a Licença DINOv3, que, entre outros termos, exige que você reconheça o DINOv3 em publicações e restringe alguns usos finais.
Update on GitHub