LeRobot documentation
X-VLA:首个面向任意机器人、任意任务的软提示机器人基础模型
X-VLA:首个面向任意机器人、任意任务的软提示机器人基础模型
概述
多年来,机器人领域一直致力于构建能够遵循自然人类指令、并在多种环境和多种机器人本体上灵巧操作的智能体。大语言模型(LLM)和视觉语言模型(VLM)近期的突破指明了一条前进之路:将这些基础模型架构扩展到具身控制领域,使其以动作为基础。这推动了视觉-语言-动作(VLA)模型的兴起,人们期望一个通用的模型能够将广泛的语义理解能力与稳健的操作技能结合起来。
但训练此类模型颇具挑战。机器人数据分散在不同的平台、传感器、本体形态和数据采集协议中。异构性无处不在:不同的机械臂构型、不同的动作空间、不同的相机配置、不同的视觉域以及不同的任务分布。这些不一致性造成了严重的分布偏移,使得预训练过程不稳定,且模型适配不可靠。
受元学习和提示学习的启发,我们提出这样一个问题:“如果 VLA 模型能够像 LLM 通过提示学习任务一样,通过提示来学习每个机器人和数据集的结构,会怎样?”
X-VLA 是一个基于软提示和流匹配的 VLA 框架,它将每种硬件配置视为一个“任务”,并使用一组可学习的嵌入对其进行编码。这些 Soft Prompts 捕获了具身智能体和特定领域的差异,从多模态融合的最初阶段开始引导 Transformer。借助这一机制,X-VLA 能够在单一统一架构中协调多样的机器人形态、数据类型和传感器配置。

X-VLA 完全基于 Transformer 编码器构建,能够随着模型规模和数据集多样性的增加而自然扩展。在 6 个仿真基准测试和 3 台真实机器人上,Soft Prompts 在处理硬件和领域差异方面始终优于现有方法。X-VLA-0.9B 在涵盖七种机器人平台的 29 万个回合(episodes)上进行训练,在阶段 I 中学习了与具身无关的通用策略,并在阶段 II 中通过仅学习一组新的提示(prompts)即可高效适应新机器人,同时保持骨干网络冻结。

在仅微调 1% 的参数(9M)的情况下,X-VLA-0.9B 在 LIBERO 和 Simpler-WidowX 上实现了接近 π₀ 的性能,尽管其使用的可训练参数数量减少了 300 倍。此外,它仅凭极少的演示就展现了强大的真实世界灵巧性,包括在不到两分钟内完成折叠布料。

X-VLA 表明,通用机器人智能并不依赖于日益复杂的架构,而关键在于吸收异构性的正确方式。Soft Prompts 提供了一种简单且可扩展的机制,用于统一多样化的机器人数据,为构建可适应、跨具身的机器人基础模型铺平了道路。
安装
安装 LeRobot 后,安装 X-VLA 的依赖项:
pip install -e ".[xvla]"如果您是从 PyPI 安装的 LeRobot:
pip install 'lerobot[xvla]'快速入门
基本用法
要在您的 LeRobot 配置中使用 X-VLA,请将策略类型指定为:
policy.type=xvla
评估预训练检查点
使用 LIBERO 进行示例评估:
lerobot-eval \
--policy.path="lerobot/xvla-libero" \
--env.type=libero \
--env.task=libero_spatial,libero_goal,libero_10 \
--env.control_mode=absolute \
--eval.batch_size=1 \
--eval.n_episodes=1 \
--env.episode_length=800 \
--seed=142可用检查点
🎯 基础模型
X-VLA 的 0.9B 参数实例,采用精心设计的处理与学习方案进行训练。训练流程包含两个阶段:
阶段 I:预训练 - 基于来自 Droid、Robomind 和 Agibot 的 290K 个 episode 进行预训练,涵盖五种机械臂类型(从单臂到双臂配置)下的七个平台。通过利用软提示(soft prompts)来吸收具身特定的差异,该模型学习到一个与具身无关的通用策略。
第二阶段:领域适应 - 针对目标领域调整为可部署的策略。引入一组新的软提示(soft prompts)并进行优化,以编码新领域的硬件配置,同时保持预训练骨干网络冻结。
模拟检查点
在 LIBERO 基准测试中达到 93% 的成功率。针对模拟任务从基础模型微调而来。
在 BridgeData 上进行了微调,用于在紧凑型 WidowX 平台上进行拾取和放置实验。展示了强大的操作能力。
🤖 真实场景检查点
在高质量 Soft-FOLD 布料折叠数据集上训练的灵巧操作微调模型。在连续 2 小时的布料折叠任务中实现了 100% 的成功率。
针对 AgileX 机器人的灵巧操作任务进行了优化。
已适配 Google Robot 平台。
训练 X-VLA
推荐的训练配置
在为新的本体或任务微调 X-VLA 时,我们建议不要冻结 VLM,并将 policy.dtype=bfloat16 设置为 bfloat16,以避免出现 OOM 错误。
lerobot-train \
--dataset.repo_id=YOUR_DATASET \
--output_dir=./outputs/xvla_training \
--job_name=xvla_training \
--policy.path="lerobot/xvla-base" \
--policy.repo_id="HF_USER/xvla-your-robot" \
--policy.dtype=bfloat16 \
--policy.action_mode=auto \
--steps=20000 \
--policy.device=cuda \
--policy.freeze_vision_encoder=false \
--policy.freeze_language_encoder=false \
--policy.train_policy_transformer=true \
--policy.train_soft_prompts=true训练参数详解
| 参数 | 默认 | 描述 |
|---|---|---|
freeze_vision_encoder | false | 不要冻结 VLM 视觉编码器的权重 |
freeze_language_encoder | false | 不要冻结 VLM 语言编码器的权重 |
train_policy_transformer | true | 允许策略转换器层进行训练 |
train_soft_prompts | true | 允许训练软提示 |
💡 最佳实践:对于针对新实例的 Phase II 适配,不要冻结 VLM 编码器,同时训练策略 Transformer 和软提示。
示例:在双手机器人上进行训练
lerobot-train \
--dataset.repo_id=<USER>/bimanual-so100-handover-cube \
--output_dir=./outputs/xvla_bimanual \
--job_name=xvla_so101_training \
--policy.path="lerobot/xvla-base" \
--policy.dtype=bfloat16 \
--policy.repo_id="YOUR_USERNAME/xvla-biso101" \
--steps=3000 \
--policy.device=cuda \
--policy.action_mode=so101_bimanual \
--policy.freeze_vision_encoder=false \
--policy.freeze_language_encoder=false \
--policy.train_policy_transformer=true \
--policy.train_soft_prompts=true💡 最佳性能: 如果您拥有充足的计算资源并希望实现最佳的 X-VLA 微调性能,请遵循官方的微调策略:
🔥 使用自定义学习率方案对所有组件进行全量微调
为确保优化过程稳定,视觉语言模型(VLM)必须以基础学习率的 1/10 进行训练,而其他所有组件则使用完整的学习率。 该学习率比例对于实现强劲且稳定的微调性能至关重要。默认情况下已为您完成此设置。 ❕注意
要完全匹配官方报告的性能,可能还需要为 soft-prompts 添加额外的预热学习率调度,这可以带来微小的性能提升。 我们建议将此实现到您自定义的训练流程中,以获得最佳效果。
核心概念
1. 操作模式
X-VLA 使用 Action Registry 系统来处理不同的动作空间和具身形态。action_mode 参数定义了动作的处理方式、所使用的损失函数以及预测结果的后期处理方法。
可用的操作模式
| 操作模式 | 动作维度 | 描述 | 用例 |
|---|---|---|---|
ee6d | 20 | 带有 xyz、6D 旋转和夹爪的末端执行器 | 具有空间控制的双臂配置 |
joint | 14 | 带夹爪的关节空间 | 直接关节控制机器人 |
agibot_ee6d | 20 | 采用 MSE 损失的 AGI-bot 变体 | AGI-bot 平台 |
so101_bimanual | 20(模型),12(实际) | SO101 双臂机器人 | 双手操作任务 |
auto | 20(模型),auto(真实) | 自动从数据集中检测动作维度 | 适用于新机器人的推荐 |
为什么操作模式很重要
当您拥有一个使用 action_dim=20 训练的预训练检查点(例如 lerobot/xvla-base),并希望在一个具有不同动作维度(例如,双臂为 14)的数据集上进行训练时,您不能简单地裁剪动作维度。动作模式负责协调:
- 损失计算:针对不同动作分量使用不同的损失函数(关节使用 MSE,夹爪使用 BCE 等)
- 预处理:将夹爪通道置零,填充维度
- 后处理:对夹爪 logits 应用 sigmoid,去除填充
示例:BimanualSO101 动作空间
so101_bimanual 动作模式处理模型输出(20D)与真实机器人控制(12D)之间的不匹配:
# Model outputs 20 dimensions for compatibility
dim_action = 20
# Real robot only needs 12 dimensions
# [left_arm (6), right_arm (6)] = [joints (5) + gripper (1)] × 2
REAL_DIM = 12
# Preprocessing: Pad 12D actions to 20D for training
# Postprocessing: Trim 20D predictions to 12D for deployment有关详细信息,请参阅 action_hub.py 的实现。
自动操作模式(推荐)
auto 操作模式是使用 X-VLA 控制任意机器人的最简单方式。它会自动检测数据集的操作维度,并处理填充/裁剪:
lerobot-train \
--policy.path="lerobot/xvla-base" \
--policy.action_mode=auto \
--policy.max_action_dim=20 \
...工作原理:
- 从您的数据集中读取
action_feature.shape[-1](例如,Franka 为 7) - 模型输出
max_action_dim(默认值为 20)以兼容预训练模型 - 损失仅在真实维度上计算:
MSE(pred[:,:,:real_dim], target[:,:,:real_dim]) - Postprocess 将输出裁剪回
real_dim以用于机器人控制
这消除了为大多数机器人创建自定义操作模式的需要。
2. 域 ID
Domain ID 是用于不同机器人配置和相机设置的、可学习的标识符。它们使 X-VLA 能够区分:
- 不同的机器人(机器人 1 与机器人 2)
- 不同的相机配置(cam1 与 cam2)
- 不同的组合(Robot1-cam1-cam2 与 Robot1-cam1 与 Robot2-cam1)
设置域 ID
训练期间:默认情况下,通用训练的 domain_id 设置为 0。
评估期间:指定与检查点的训练配置相匹配的 domain_id。
# Example: LIBERO checkpoint uses domain_id=3
domain_id = 3XVLAAddDomainIdProcessorStep 会在预处理流水线中自动将 domain_id 添加到观测数据中。
lerobot/xvla-base 模型已在以下领域 ID 上进行训练。建议选择与您的机器人/配置最相似的一个:
微调数据集
| 数据集名称 | Domain ID |
|---|---|
| 桥接 | 0 |
| RT1 | 1 |
| Calvin | 2 |
| libero | 3 |
| widowx-air | 4 |
| AIR-AGILEX-HQ | 5 |
| robotwin2_abs_ee | 6 |
| robotwin2_clean | 6 |
| robocasa-human | 7 |
| VLABench | 8 |
| AGIBOT-challenge | 9 |
| AIR-AGILEX | 10 |
| AIRBOT | 18 |
3. 处理器步骤
X-VLA 需要特定的预处理和后处理步骤才能正常运行。
必需的预处理步骤
- XVLAImageToFloatProcessorStep:将图像从 [0, 255] 范围转换为 [0, 1] 范围
- XVLAImageNetNormalizeProcessorStep:应用 ImageNet 归一化(VLM 骨干网络所必需)
- XVLAAddDomainIdProcessorStep:向观测数据中添加 domain_id
自定义处理器示例
对于 LIBERO 环境,自定义处理器负责处理特定的观测格式:
from lerobot.policies.xvla.processor_xvla import LiberoProcessorStep
processor = LiberoProcessorStep()
# Handles robot_state dictionary, converts rotation matrices to 6D representation
# Applies 180° image rotation for camera convention4. 配置参数
X-VLA 的关键配置参数:
# Observation and action
n_obs_steps: int = 1 # Number of observation timesteps
chunk_size: int = 32 # Action sequence length
n_action_steps: int = 32 # Number of action steps to execute
# Model architecture
hidden_size: int = 1024 # Transformer hidden dimension
depth: int = 24 # Number of transformer layers
num_heads: int = 16 # Number of attention heads
num_domains: int = 30 # Maximum number of domain IDs
len_soft_prompts: int = 32 # Length of soft prompt embeddings
# Action space
action_mode: str = "ee6d" # Action space type (use "auto" for auto-detection)
use_proprio: bool = True # Use proprioceptive state
max_state_dim: int = 32 # Maximum state dimension
max_action_dim: int = 20 # Max action dim for padding (used by "auto" mode)
# Vision
num_image_views: int | None # Number of camera views
resize_imgs_with_padding: tuple[int, int] | None # Target image size with padding
# Training
num_denoising_steps: int = 10 # Flow matching denoising steps创建自定义操作模式
如果您的机器人具有独特的动作空间,您可以创建一个自定义的动作模式:
步骤 1:定义您的动作空间
from lerobot.policies.xvla.action_hub import BaseActionSpace, register_action
import torch
import torch.nn as nn
@register_action("my_custom_robot")
class MyCustomActionSpace(BaseActionSpace):
"""Custom action space for my robot."""
dim_action = 15 # Your robot's action dimension
gripper_idx = (7, 14) # Gripper channel indices
def __init__(self):
super().__init__()
self.mse = nn.MSELoss()
self.bce = nn.BCEWithLogitsLoss()
def compute_loss(self, pred, target):
"""Define your loss computation."""
# Example: MSE for joints, BCE for grippers
joints_loss = self.mse(pred[:, :, :7], target[:, :, :7])
gripper_loss = self.bce(pred[:, :, self.gripper_idx],
target[:, :, self.gripper_idx])
return {
"joints_loss": joints_loss,
"gripper_loss": gripper_loss,
}
def preprocess(self, proprio, action, mode="train"):
"""Preprocess actions before training."""
# Example: Zero out grippers in proprioception
proprio_m = proprio.clone()
action_m = action.clone() if action is not None else None
proprio_m[..., self.gripper_idx] = 0.0
if action_m is not None:
action_m[..., self.gripper_idx] = 0.0
return proprio_m, action_m
def postprocess(self, action):
"""Post-process predictions for deployment."""
# Example: Apply sigmoid to gripper logits
action[..., self.gripper_idx] = torch.sigmoid(action[..., self.gripper_idx])
return action步骤 2:使用您的自定义操作模式
lerobot-train \
--policy.action_mode=my_custom_robot \
--dataset.repo_id=YOUR_DATASET \
--policy.path="lerobot/xvla-base" \
...高级主题
多摄像头支持
X-VLA 通过 num_image_views 参数支持多个相机视角:
# Configure for 3 camera views
policy.num_image_views=3
# Add empty cameras if you have fewer physical cameras
policy.empty_cameras=1 # Adds 1 zero-padded camera view自定义预处理流水线
为您的环境创建自定义预处理流水线:
from lerobot.processor import PolicyProcessorPipeline
from lerobot.policies.xvla import (
XVLAImageToFloatProcessorStep,
XVLAImageNetNormalizeProcessorStep,
XVLAAddDomainIdProcessorStep,
)
# Build custom pipeline
preprocessor = PolicyProcessorPipeline(
steps=[
YourCustomProcessorStep(), # Your custom processing
XVLAImageToFloatProcessorStep(), # Required: convert to float
XVLAImageNetNormalizeProcessorStep(), # Required: ImageNet norm
XVLAAddDomainIdProcessorStep(domain_id=5), # Your domain ID
]
)处理不同的动作维度
当您的数据集的动作维度少于预训练模型时:
选项 1(推荐):使用 auto 操作模式
# Automatically detects your dataset's action dimension
# Works with any robot without custom code
policy.action_mode=auto
policy.max_action_dim=20 # Match pretrained model选项 2:使用内置填充的预定义操作模式
# Model expects 20D, dataset has 12D
# Action mode handles padding internally
action_mode = "so101_bimanual" # Pads 12 → 20选项 2:创建一个自定义操作模式,显式地映射维度
@register_action("my_mapped_action")
class MappedActionSpace(BaseActionSpace):
dim_action = 20
REAL_DIM = 12
def _pad_to_model_dim(self, x):
# Custom padding logic
...故障排除
常见问题
问题:“动作维度不匹配”
- 解决方案:检查您的
action_mode是否与机器人的动作空间匹配。如有需要,请创建自定义的动作模式。
问题:“图像值超出 [0, 1] 范围”
- 解决方案:确保在归一化之前使用
XVLAImageToFloatProcessorStep对图像进行预处理。
问题:“未找到域 ID”
- 解决方案:确保
XVLAAddDomainIdProcessorStep位于您的预处理流水线中,并且 domain_id 正确。
问题:“在新具身环境中的成功率较低”
- Solution:
- 验证您的 action_mode 是否正确
- 检查软提示是否正在被训练(
train_soft_prompts=True) - 确保进行正确的预处理(ImageNet 归一化、domain_id)
- 考虑增加训练步数
问题:“训练期间内存不足”
- Solution:
- 将
chunk_size减小(例如,从 32 减至 16) - 启用梯度检查点
- 减小批量大小
- 冻结更多组件
- 将
引用
如果您在研究中使用 X-VLA,请引用:
@article{zheng2025x,
title = {X-VLA: Soft-Prompted Transformer as Scalable Cross-Embodiment Vision-Language-Action Model},
author = {Zheng, Jinliang and Li, Jianxiong and Wang, Zhihao and Liu, Dongxiu and Kang, Xirui
and Feng, Yuchun and Zheng, Yinan and Zou, Jiayin and Chen, Yilun and Zeng, Jia and others},
journal = {arXiv preprint arXiv:2510.10274},
year = {2025}
}其他资源
贡献
我们欢迎贡献!如果您已为您的机器人实现了新的动作模式或处理器,请考虑提交 PR 以帮助社区。
Update on GitHub