EVO1

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。

LeRobot 集成涵盖的内容

  • 通过 LeRobot 的标准 policy.type=evo1 配置
  • InternVL3 图像/文本嵌入,并带有可选的 FlashAttention 回退
  • 面向仅 action 头 fine-tune 和 VLM fine-tune 运行的基于阶段的 fine-tune 控制
  • 连续流匹配 action prediction
  • 通过 LeRobot policy API 保存/加载 checkpoint
  • 使用 lerobot-train 进行训练,并使用标准 policy inference API 进行评估

更广泛的 EVO1 项目可能包含额外的训练脚本和 dataset 工具。本页重点介绍 LeRobot 机器人控制 policy 路径。

安装要求

  1. 按照安装指南安装 LeRobot。

  2. 安装 EVO1 依赖项:

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

    对于 LIBERO 训练和评估,还需安装 LIBERO extra:

    pip install -e ".[training,evo1,libero]"
  3. 仅当 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.image
  • observation.state
  • action
  • dataset task 字段中的语言任务指令,或使用 policy.task_field 配置的另一个字段

state 和 action 向量会填充到 policy.max_state_dimpolicy.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

阶段 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

阶段 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_nameOpenGVLab/InternVL3-1B-hf原生转换的 InternVL3 checkpoint 或本地模型目录
policy.training_stagestage1stage1 训练 action 头;stage2 fine-tune VLM 分支
policy.apply_training_stage_defaultstrue加载 checkpoint 后重新应用阶段 fine-tune 默认值
policy.vlm_num_layers14为 policy 保留的 InternVL3 语言层数
policy.vlm_dtypebfloat16请求的 VLM 数据类型
policy.use_flash_attntrue安装时请求 FlashAttention;否则回退
policy.enable_gradient_checkpointingtrue在支持的 InternVL3 模块上启用 checkpoint
policy.gradient_checkpointing_use_reentrantfalse在支持时传递给梯度 checkpoint 的 reentrant 设置
policy.chunk_size50每个 action chunk 预测的未来 action 数
policy.n_action_steps50从采样的 action chunk 中消耗的 action 数
policy.max_state_dim24state 填充维度
policy.max_action_dim24action 填充维度
policy.postprocess_action_dimnullEVO1 后处理之后返回的可选 action 维度
policy.binarize_gripperfalse为 LIBERO 风格评估对后处理的 gripper 通道进行二值化
policy.task_fieldtask用作语言提示的批次字段

inference

使用训练好的 EVO1 checkpoint 试用:

lerobot-rollout \
  --policy.path=your-org/your-evo1-checkpoint \
  --inference.type=rtc \ # optional
  ...

结果

LIBERO 评估

参考结果

发布的 Stage-2 checkpoint 通过了干净下载和 rollout 验证: zuoxingdong/evo1_libero,revision 515921f4a2c1d3f3ad523721eafa26fdf2af315b。 干净下载评估使用了 LeRobot revision e40b58a8dfa9e7b86918c374791599d070518d11

第 70,000 步的单次运行 Stage-2 checkpoint 产生了:

套件成功 episodeepisode成功率
LIBERO Spatial48550097.0%
LIBERO Object49650099.2%
LIBERO Goal48350096.6%
LIBERO-1046950093.8%
总体1,9332,00096.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_imageobservation.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=1

原生 lerobot/libero v3 配置

Revision a1aaacb7f6cd6ee5fb43120f673cebb0cfea7dd4 将相机特征存储为 imageimage2。此示例评估全部十个 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.taskenv.episode_length
libero_spatial280
libero_object280
libero_goal300
libero_10520

为每一行设置 suitehorizon。这样每个套件有 500 个 episode,总共 2,000 个 episode,而 循环中每个任务使用全新进程与实测的 RNG 重置拓扑相匹配。

参考

许可证

此 LeRobot 集成遵循 LeRobot 使用的 Apache 2.0 License。请查看上游 EVO1 和 InternVL3 模型页面,了解已发布 checkpoint 和数据的许可证。

在 GitHub 上更新