数据与后训练
后训练 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,请按照以下步骤操作:
示例数据集
示例数据集 已转换为训练所需格式,可用于检查数据目录和字段结构:
- 下载:示例数据集
该示例可作为将你自己的机器人操作数据转换为正确格式的参考。
数据流程概览
在准备自定义数据集时,数据会经历以下处理流程:
- 原始数据 → 转换为 LeRobot 格式(包含元数据和视频文件)
- 添加动作分段 → 在
episodes.jsonl中添加action_config - 提取潜变量(Latents) → 根据视频规格通过 VAE 处理视频
- 数据集加载 → 加载处理后的数据,并附带用于训练的正确动作维度
最终数据应符合以下规格:
动作格式:
- 输出维度: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 文件是一个字典,包含以下字段:
| 键 | 类型 | 描述 |
|---|---|---|
latent | Tensor [N, C] (bfloat16) | 展平后的 VAE 潜变量特征(例如,形状为 [latent_num_frames * latent_height * latent_width, C]) |
latent_num_frames | int | 潜空间中的时间帧数 |
latent_height | int | 潜空间中的空间高度 |
latent_width | int | 潜空间中的空间宽度 |
video_num_frames | int | (采样后)源视频中的帧数 |
video_height | int | 原始视频高度(像素) |
video_width | int | 原始视频宽度(像素) |
text_emb | Tensor [L, D] (bfloat16) | 动作描述的文本嵌入(由 Wan2.2 文本编码器编码) |
text | str | 原始动作描述文本 |
frame_ids | list[int] | 从原始 episode 中采样的帧索引(以目标 fps) |
start_frame | int | 与 episodes.jsonl 中 action_config 匹配的起始帧索引 |
end_frame | int | 与 episodes.jsonl 中 action_config 匹配的结束帧索引 |
fps | int | 用于潜变量提取的目标采样 fps |
ori_fps | int | episode 数据的原始 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 以实现更大的有效批大小。