跳到主要内容

数据与后训练

后训练 LingBot-VA​

LingBot-VA 支持使用自定义机器人操作数据进行后训练。训练流程使用 FSDP 进行分布式训练,并采用 LeRobot 数据集格式。

额外依赖​

在基础安装之上,后训练还需要:

pip install lerobot==0.3.3 scipy wandb --no-deps

数据准备​

从 HuggingFace 下载后训练数据集:

huggingface-cli download --repo-type dataset robbyant/robotwin-clean-and-aug-lerobot --local-dir /path/to/your/dataset

自定义数据集准备​

如果你想在自己的机器人操作数据上微调 LingBot-VA,请按照以下步骤操作:

示例数据集​

示例数据集 已转换为训练所需格式,可用于检查数据目录和字段结构:

该示例可作为将你自己的机器人操作数据转换为正确格式的参考。

数据流程概览​

在准备自定义数据集时,数据会经历以下处理流程:

  1. 原始数据 → 转换为 LeRobot 格式(包含元数据和视频文件)
  2. 添加动作分段 → 在 episodes.jsonl 中添加 action_config
  3. 提取潜变量(Latents) → 根据视频规格通过 VAE 处理视频
  4. 数据集加载 → 加载处理后的数据,并附带用于训练的正确动作维度

最终数据应符合以下规格:

动作格式:

  • 输出维度:30 维,结构如下:
    • 左臂 EEF(末端执行器):7 维
    • 右臂 EEF(末端执行器):7 维
    • 左臂关节:7 维
    • 右臂关节:7 维
    • 左臂夹爪:1 维
    • 右臂夹爪:1 维
  • 在你的数据集类加载器中,将你机器人的动作维度映射到这个标准的 30 维格式。缺失的维度用 0 填充。

视频格式:

  • 在 VAE 潜变量提取期间,将视频缩放到 ~256 × 256 像素,并下采样到 5-15 fps 作为参考(请根据你的任务需求进行调整)。

实现步骤​

步骤 1:将你的数据转换为 LeRobot 格式

按照官方 LeRobot 数据集文档 将你的原始数据(例如 HDF5、视频文件等)转换为标准的 LeRobot 数据集格式。确保每个 episode 都包含所需的观测视频、动作和元数据。

步骤 2:在 episodes.jsonl 中添加 action_config 字段

转换为 LeRobot 格式后,你需要修改 meta/episodes.jsonl 文件,为每一行添加一个 action_config 字段。该字段描述了每个 episode 中机器人动作的时间分段和自然语言描述。

episodes.jsonl 中的每一行应遵循以下格式:

{
"episode_index": 0,
"tasks": ["task description"],
"length": 450,
"action_config": [
{
"start_frame": 0,
"end_frame": 450,
"action_text": "Natural language description of the robot action in this segment.",
}
]
}
  • start_frame / end_frame:该动作分段在 episode 内的帧范围(从 0 开始索引)。
  • action_text:对机器人在该分段中所做动作的自然语言描述。

对于具有单个连续动作的 episode,start_frame 应为 0,end_frame 应等于 episode 的 length。如果你的数据包含连续的子任务,你也可以为每个 episode 定义多个分段。

步骤 3:使用 Wan2.2 VAE 提取视频潜变量

LingBot-VA 在视频潜变量表示上运行,而非原始像素。你需要使用 Wan2.2 VAE 编码器提取潜变量特征,并将其放置在转换后的 LeRobot 数据集目录下。有关如何运行 VAE 编码器的说明,请参阅 Wan-Video 文档。

提取出的潜变量文件应放置在数据集目录下的 latents/ 中,并镜像 videos/ 的结构:

your_dataset/
├── videos/
│ └── chunk-000/
│ └── observation.images.cam_high/
│ ├── episode_000000.mp4
│ └── ...
├── latents/
│ └── chunk-000/
│ └── observation.images.cam_high/
│ ├── episode_000000_0_450.pth # named as episode_{index}_{start_frame}_{end_frame}.pth
│ └── ...
└── meta/
└── episodes.jsonl

每个 .pth 文件是一个字典,包含以下字段:

键类型描述
latentTensor [N, C] (bfloat16)展平后的 VAE 潜变量特征(例如,形状为 [latent_num_frames * latent_height * latent_width, C])
latent_num_framesint潜空间中的时间帧数
latent_heightint潜空间中的空间高度
latent_widthint潜空间中的空间宽度
video_num_framesint(采样后)源视频中的帧数
video_heightint原始视频高度(像素)
video_widthint原始视频宽度(像素)
text_embTensor [L, D] (bfloat16)动作描述的文本嵌入(由 Wan2.2 文本编码器编码)
textstr原始动作描述文本
frame_idslist[int]从原始 episode 中采样的帧索引(以目标 fps)
start_frameint与 episodes.jsonl 中 action_config 匹配的起始帧索引
end_frameint与 episodes.jsonl 中 action_config 匹配的结束帧索引
fpsint用于潜变量提取的目标采样 fps
ori_fpsintepisode 数据的原始 fps

潜变量文件命名约定 episode_{index}_{start_frame}_{end_frame}.pth 对应于 episodes.jsonl 中定义的 action_config 分段。例如,一个 "start_frame": 0, "end_frame": 450 的 episode 会生成一个名为 episode_000000_0_450.pth 的潜变量文件。

训练​

# RoboTwin
NGPU=8 CONFIG_NAME='robotwin_train' bash script/run_va_posttrain.sh

# LIBERO
NGPU=8 CONFIG_NAME='libero_train' bash script/run_va_posttrain.sh

为获得更好的训练性能,请使用更大的全局批大小(例如 32、64)。如果你的 GPU 资源有限,可以增大 gradient_accumulation_steps 以实现更大的有效批大小。