EVO1 是一种用于机器人控制的视觉-语言-action policy,围绕 InternVL3 骨干和连续流匹配 action 头构建。此 LeRobot 集成将 EVO1 作为标准 policy 类型公开,因此可以用常见的 LeRobot dataset、checkpoint 和处理器 API 对其进行训练和评估。
该 policy 使用 InternVL3 嵌入一个或多个相机图像以及语言任务提示,将机器人 state/action 向量填充到固定的最大维度,并使用流匹配 action 头预测未来的 action chunk。inference 时,policy 采样一个 action chunk,并在再次采样之前从该 action chunk 返回 n_action_steps 个 action。
policy.type=evo1 配置lerobot-train 进行训练,并使用标准 policy inference API 进行评估更广泛的 EVO1 项目可能包含额外的训练脚本和 dataset 工具。本页重点介绍 LeRobot 机器人控制 policy 路径。
按照安装指南安装 LeRobot。
安装 EVO1 依赖项:
pip install -e ".[training,evo1]"对于 LIBERO 训练和评估,还需安装 LIBERO extra:
pip install -e ".[training,evo1,libero]"仅当 flash-attn wheel 与你的 Python、PyTorch、CUDA 和 GPU 技术栈兼容时才安装它。当 flash_attn 不可用时,EVO1 会回退到标准注意力。
EVO1 使用原生 Hugging Face transformers InternVL 实现,因此 policy.vlm_model_name 必须指向原生转换的 checkpoint,例如 OpenGVLab/InternVL3-1B-hf(注意 -hf 后缀)。首次运行会下载配置的 VLM checkpoint,后续运行会从 Hugging Face 缓存中复用它。
EVO1 期望 LeRobot dataset 具有:
policy.max_views 个视觉 observation,例如 observation.images.imageobservation.stateactiontask 字段中的语言任务指令,或使用 policy.task_field 配置的另一个字段state 和 action 向量会填充到 policy.max_state_dim 和 policy.max_action_dim。预测结果在返回之前会被裁剪回 dataset 的 action 维度。
要在 LeRobot 配置中使用 EVO1,请指定:
policy.type=evo1默认情况下,新的 EVO1 policy 从以下位置初始化其 VLM:
policy.vlm_model_name=OpenGVLab/InternVL3-1B-hf
一旦获得 LeRobot 格式的 EVO1 checkpoint,请使用以下方式加载:
policy.path=your-org/your-evo1-checkpoint
阶段 1 冻结 VLM 并训练 action 头:
lerobot-train \ --dataset.repo_id=your_org/your_dataset \ --policy.type=evo1 \ --policy.training_stage=stage1 \ --policy.vlm_model_name=OpenGVLab/InternVL3-1B-hf \ --policy.device=cuda \ --policy.chunk_size=50 \ --policy.n_action_steps=50 \ --policy.max_state_dim=24 \ --policy.max_action_dim=24 \ --policy.optimizer_lr=1e-5 \ --batch_size=4 \ --steps=5000 \ --output_dir=./outputs/evo1_stage1
阶段 2 加载阶段 1 的 policy,但启动全新的优化器和调度器:
lerobot-train \ --dataset.repo_id=your_org/your_dataset \ --policy.path=./outputs/evo1_stage1/checkpoints/005000/pretrained_model \ --policy.training_stage=stage2 \ --policy.vlm_model_name=OpenGVLab/InternVL3-1B-hf \ --policy.device=cuda \ --policy.chunk_size=50 \ --policy.n_action_steps=50 \ --policy.max_state_dim=24 \ --policy.max_action_dim=24 \ --policy.optimizer_lr=1e-5 \ --batch_size=4 \ --steps=80000 \ --output_dir=./outputs/evo1_stage2
默认情况下,policy.training_stage 会重新应用该阶段的 fine-tune 默认值。当从阶段 1 checkpoint 启动阶段 2 时,这一点很重要,因为阶段 1 checkpoint 配置将 VLM fine-tune
标志存储为禁用 state。这些阶段默认值优先于已保存或手动提供的 policy.finetune_* 标志,除非 policy.apply_training_stage_defaults=false,因此仅当你手动控制
每个 fine-tune 标志时才设置该标志。
| 参数 | 默认值 | 描述 |
|---|---|---|
policy.vlm_model_name | OpenGVLab/InternVL3-1B-hf | 原生转换的 InternVL3 checkpoint 或本地模型目录 |
policy.training_stage | stage1 | stage1 训练 action 头;stage2 fine-tune VLM 分支 |
policy.apply_training_stage_defaults | true | 加载 checkpoint 后重新应用阶段 fine-tune 默认值 |
policy.vlm_num_layers | 14 | 为 policy 保留的 InternVL3 语言层数 |
policy.vlm_dtype | bfloat16 | 请求的 VLM 数据类型 |
policy.use_flash_attn | true | 安装时请求 FlashAttention;否则回退 |
policy.enable_gradient_checkpointing | true | 在支持的 InternVL3 模块上启用 checkpoint |
policy.gradient_checkpointing_use_reentrant | false | 在支持时传递给梯度 checkpoint 的 reentrant 设置 |
policy.chunk_size | 50 | 每个 action chunk 预测的未来 action 数 |
policy.n_action_steps | 50 | 从采样的 action chunk 中消耗的 action 数 |
policy.max_state_dim | 24 | state 填充维度 |
policy.max_action_dim | 24 | action 填充维度 |
policy.postprocess_action_dim | null | EVO1 后处理之后返回的可选 action 维度 |
policy.binarize_gripper | false | 为 LIBERO 风格评估对后处理的 gripper 通道进行二值化 |
policy.task_field | task | 用作语言提示的批次字段 |
使用训练好的 EVO1 checkpoint 试用:
lerobot-rollout \
--policy.path=your-org/your-evo1-checkpoint \
--inference.type=rtc \ # optional
...发布的 Stage-2 checkpoint 通过了干净下载和 rollout 验证:
zuoxingdong/evo1_libero,revision515921f4a2c1d3f3ad523721eafa26fdf2af315b。 干净下载评估使用了 LeRobot revisione40b58a8dfa9e7b86918c374791599d070518d11。
第 70,000 步的单次运行 Stage-2 checkpoint 产生了:
| 套件 | 成功 episode | episode | 成功率 |
|---|---|---|---|
| LIBERO Spatial | 485 | 500 | 97.0% |
| LIBERO Object | 496 | 500 | 99.2% |
| LIBERO Goal | 483 | 500 | 96.6% |
| LIBERO-10 | 469 | 500 | 93.8% |
| 总体 | 1,933 | 2,000 | 96.65% |
这些结果使用一个训练好的 checkpoint 和评估种子 1000;它们不是多种子平均值或置信度估计。
发布的 checkpoint 在 train_config.json 中记录了完整解析后的 Stage-2 配置。
实测运行使用两块 H100 GPU 和两个 DDP 进程,每个进程批次为 64,因此全局批次为 128。两个阶段使用相同的拓扑。基础 VLM 来自 OpenGVLab/InternVL3-1B-hf 的 revision 014c0583a0d4bedf29fbe2dbff4f865eb998e171。
发布的产物没有记录确切的 LeRobot 训练提交或其原始依赖锁定,
因此下面的命令从当前检出重现记录的配置和拓扑,
而不是逐位重建软件环境。
在 LeRobot 源码检出中,安装锁定的依赖并下载该确切的 VLM revision:
uv sync --locked --extra training --extra evo1 --extra libero
VLM_DIR=$(uv run hf download OpenGVLab/InternVL3-1B-hf \
--revision=014c0583a0d4bedf29fbe2dbff4f865eb998e171)阶段 1 冻结 VLM 并训练 action 头 5,000 步:
uv run accelerate launch --num_processes=2 -m lerobot.scripts.lerobot_train \
--dataset.repo_id=lerobot/libero \
--dataset.revision=a1aaacb7f6cd6ee5fb43120f673cebb0cfea7dd4 \
--dataset.video_backend=torchcodec \
--dataset.return_uint8=true \
--dataset.image_transforms.enable=true \
--dataset.use_imagenet_stats=true \
--dataset.eval_split=0.0 \
--policy.type=evo1 \
--policy.training_stage=stage1 \
--policy.apply_training_stage_defaults=true \
--policy.vlm_model_name="${VLM_DIR}" \
--policy.vlm_num_layers=14 \
--policy.vlm_dtype=bfloat16 \
--policy.device=cuda \
--policy.use_amp=true \
--policy.use_flash_attn=true \
--policy.enable_gradient_checkpointing=true \
--policy.gradient_checkpointing_use_reentrant=false \
--policy.image_resolution='[448,448]' \
--policy.chunk_size=50 \
--policy.n_action_steps=50 \
--policy.max_state_dim=24 \
--policy.max_action_dim=24 \
--policy.dropout=0.2 \
--policy.optimizer_lr=1e-5 \
--policy.optimizer_weight_decay=1e-3 \
--policy.optimizer_grad_clip_norm=1.0 \
--policy.scheduler_warmup_steps=1000 \
--policy.push_to_hub=false \
--use_policy_training_preset=true \
--batch_size=64 \
--steps=5000 \
--save_checkpoint=true \
--save_checkpoint_to_hub=false \
--save_freq=2500 \
--log_freq=10 \
--env_eval_freq=0 \
--num_workers=4 \
--prefetch_factor=2 \
--persistent_workers=true \
--seed=1000 \
--wandb.enable=false \
--output_dir=./outputs/evo1-libero-stage1-g128-5k阶段 2 加载 Stage-1 policy,但启动全新的优化器和调度器。它训练 80,000 步; 报告的 checkpoint 是第 70,000 步保存的版本:
uv run accelerate launch --num_processes=2 -m lerobot.scripts.lerobot_train \
--dataset.repo_id=lerobot/libero \
--dataset.revision=a1aaacb7f6cd6ee5fb43120f673cebb0cfea7dd4 \
--dataset.video_backend=torchcodec \
--dataset.return_uint8=true \
--dataset.image_transforms.enable=true \
--dataset.use_imagenet_stats=true \
--dataset.eval_split=0.0 \
--policy.path=./outputs/evo1-libero-stage1-g128-5k/checkpoints/005000/pretrained_model \
--policy.training_stage=stage2 \
--policy.apply_training_stage_defaults=true \
--policy.vlm_model_name="${VLM_DIR}" \
--policy.vlm_num_layers=14 \
--policy.vlm_dtype=float32 \
--policy.device=cuda \
--policy.use_amp=true \
--policy.use_flash_attn=true \
--policy.enable_gradient_checkpointing=true \
--policy.gradient_checkpointing_use_reentrant=false \
--policy.image_resolution='[448,448]' \
--policy.chunk_size=50 \
--policy.n_action_steps=50 \
--policy.max_state_dim=24 \
--policy.max_action_dim=24 \
--policy.dropout=0.2 \
--policy.optimizer_lr=1e-5 \
--policy.optimizer_weight_decay=1e-3 \
--policy.optimizer_grad_clip_norm=1.0 \
--policy.scheduler_warmup_steps=1000 \
--policy.push_to_hub=false \
--use_policy_training_preset=true \
--batch_size=64 \
--steps=80000 \
--resume=false \
--save_checkpoint=true \
--save_checkpoint_to_hub=false \
--save_freq=10000 \
--log_freq=10 \
--env_eval_freq=0 \
--num_workers=4 \
--prefetch_factor=2 \
--persistent_workers=true \
--seed=1000 \
--wandb.enable=false \
--output_dir=./outputs/evo1-libero-stage2-g128-80k作者格式的 EVO1 LIBERO 配置使用原始 LIBERO 相机特征名
(observation.images.agentview_image 和 observation.images.robot0_eye_in_hand_image),每
14 个 action 重新规划,并在推进 simulation 器之前对 gripper 命令进行二值化。EVO1 policy 后处理器
可以将填充的 24 维 action 裁剪回 7 维 LIBERO action space,并应用该 gripper 二值化。要在
相同的每任务一个 episode 设置下评估作者格式 checkpoint,请保留原始相机名,
而不是默认的 image/image2 映射,并设置 LIBERO action 后处理标志:
lerobot-eval \
--policy.path=your-org/your-evo1-libero-checkpoint \
--policy.vlm_model_name=OpenGVLab/InternVL3-1B-hf \
--policy.device=cuda \
--policy.use_flash_attn=true \
--policy.n_action_steps=14 \
--policy.postprocess_action_dim=7 \
--policy.binarize_gripper=true \
--env.type=libero \
--env.task=libero_object \
--env.camera_name_mapping="{agentview_image: agentview_image, robot0_eye_in_hand_image: robot0_eye_in_hand_image}" \
--env.observation_height=448 \
--env.observation_width=448 \
--eval.batch_size=1 \
--eval.n_episodes=1Revision a1aaacb7f6cd6ee5fb43120f673cebb0cfea7dd4 将相机特征存储为 image 和 image2。此示例评估全部十个 LIBERO Object 任务,每个任务在全新进程中启动:
export MUJOCO_GL=egl
export PYOPENGL_PLATFORM=egl
suite=libero_object
horizon=280
for task_id in {0..9}; do
lerobot-eval \
--policy.path=zuoxingdong/evo1_libero \
--policy.pretrained_revision=515921f4a2c1d3f3ad523721eafa26fdf2af315b \
--policy.vlm_model_name=OpenGVLab/InternVL3-1B-hf \
--policy.device=cuda \
--policy.use_amp=true \
--policy.vlm_dtype=bfloat16 \
--policy.use_flash_attn=false \
--policy.enable_gradient_checkpointing=false \
--policy.vlm_num_layers=14 \
--policy.image_resolution='[448,448]' \
--policy.max_text_length=1024 \
--policy.chunk_size=50 \
--policy.n_action_steps=14 \
--policy.max_state_dim=24 \
--policy.max_action_dim=24 \
--policy.num_inference_timesteps=32 \
--policy.postprocess_action_dim=7 \
--policy.binarize_gripper=true \
--policy.gripper_threshold=0.0 \
--policy.gripper_below_threshold_value=-1.0 \
--policy.gripper_above_threshold_value=1.0 \
--env.type=libero \
--env.task="${suite}" \
--env.task_ids="[${task_id}]" \
--env.camera_name=agentview_image,robot0_eye_in_hand_image \
--env.camera_name_mapping="{agentview_image: image, robot0_eye_in_hand_image: image2}" \
--env.control_mode=relative \
--env.obs_type=pixels_agent_pos \
--env.observation_width=448 \
--env.observation_height=448 \
--env.init_states=true \
--env.episode_length="${horizon}" \
--env.render_mode=rgb_array \
--env.max_parallel_tasks=1 \
--eval.n_episodes=50 \
--eval.batch_size=1 \
--eval.use_async_envs=false \
--eval.recording=false \
--seed=1000 \
--output_dir="./outputs/evo1-libero-stage2-70k-eval/${suite}/task-${task_id}" \
--job_name="evo1-libero-stage2-70k-${suite}-task-${task_id}"
done使用以下视界运行每个套件的全部十个任务 ID:
env.task | env.episode_length |
|---|---|
libero_spatial | 280 |
libero_object | 280 |
libero_goal | 300 |
libero_10 | 520 |
为每一行设置 suite 和 horizon。这样每个套件有 500 个 episode,总共 2,000 个 episode,而
循环中每个任务使用全新进程与实测的 RNG 重置拓扑相匹配。
此 LeRobot 集成遵循 LeRobot 使用的 Apache 2.0 License。请查看上游 EVO1 和 InternVL3 模型页面,了解已发布 checkpoint 和数据的许可证。
在 GitHub 上更新