LeRobot documentation
语言列和配方
语言列和配方
大多数 LeRobot 数据集每个 episode 仅附带一个 task 字符串——这对于简短的单指令技能来说已经足够,但不足以支撑该领域正在发展的长时程、多模态机器人策略(如高层规划、记忆、插话、VQA、工具使用)。为了在不分叉数据集格式的前提下支持这些策略,LeRobot 为 LeRobotDataset 扩展了两个可选的语言列,并添加了一个小型的 recipe 层,用于将这些行即时转换为 chat 风格的训练样本。
该设计清晰地分为三层:
- 数据集中的数据 — 以两个可选列(
language_persistent和language_events)的形式,将语言标注存储在data/chunk-*/file-*.parquet中帧的旁边。不包含这些列的数据集将保持其现有行为。 - 配方 — 一个 YAML 文件,用于声明要绑定哪些标注行,以及如何将它们布局为聊天轮次(
role、content、可选图像、可选工具调用)。配方是纯配置;添加新配方无需编写 Python 代码。 - 训练格式 — 在采样时,
RenderTrainingMessagesStep会根据逐帧注释解析配方,并输出 HF 风格的messages以及 LeRobot 特有的辅助字段(message_streams、target_message_indices),供策略处理器使用。
本页将依次介绍每一层。
第 1 层 — 数据集中的语言列
这两个可选列位于 data/chunk-*/file-*.parquet 中的帧数据旁边:
language_persistent:一个行列表,用于在剧集的每一帧中广播保持激活状态的状态,例如subtask、plan和memory。language_events:仅在事件发出的那一帧上出现的行列表,例如interjection、vqa以及语音工具调用。
两列共享相同的行结构(事件行省略了 timestamp,因为该行所在的帧已经提供了它):
role: string content: string | null style: string | null timestamp: float32 # persistent rows only camera: string | null # observation.images.* feature key, view-dependent rows only tool_calls: list[Json] | null
camera 字段用于标记那些 content 基于特定相机视角的行。对于依赖视角的样式(vqa 和 trace)的行,必须将 camera 设置为对应的 observation.images.* 特征键。对于其他所有样式的行——包括描述关节/笛卡尔坐标系下机器人坐标系原语的 motion——必须将 camera 保留为 null。流水线写入器和验证器通过 validate_camera_field(style, camera) 来强制执行此规则。
meta/tasks.parquet 仍然是该任务的权威来源。特殊的 ${task} 配方绑定始终读取该任务字符串,且不依赖于语言注释。
架构
语言栈本身有三个内部模块支撑第一层:
lerobot.datasets.language定义了模式、样式注册表以及column_for_style。lerobot.datasets.language_render解析行并渲染消息。RenderTrainingMessagesStep将数据集样本转换为messages、message_streams和target_message_indices。
LeRobotDataset 与具体配方无关。当 language_persistent 和 language_events 存在时,它会将其透传;未标注的数据集则保持原有行为。
第 2 层 — 配方结构
Recipes 是由 lerobot.datasets.recipe 中的 TrainingRecipe 和 MessageTurn 支持的 YAML 文件。它们声明了要拉取哪些标注行(通过 bindings),以及如何将它们组合成聊天轮次(messages)。
messages:
- { role: user, content: "${task}", stream: high_level }
- { role: assistant, content: "${subtask}", stream: low_level, target: true }配方还可以分支为子配方的加权混合。在采样时,会根据样本索引确定性地选择其中一个分支,因此不同的帧会训练不同的目标(例如记忆更新、底层执行或 VQA),而无需任何 Python 代码接线。
时间语义
持久化样式在发出后保持激活状态,直到被替换:
active_at(t, style=subtask)nth_prev(style=memory, offset=1)nth_next(style=subtask, offset=1)
事件样式仅存在于其精确的时间戳上:
emitted_at(t, style=interjection)emitted_at(t, style=vqa, role=user, camera=observation.images.top)emitted_at(t, role=assistant, tool_name=say)
精确事件匹配没有容差窗口,因此写入器必须使用 parquet 数据中的帧时间戳为事件行打上时间戳。
基于视角的分辨率
对于依赖视角的样式(vqa 和 trace),解析器会获得一个与 role= 和 tool_name= 并列的 camera= 过滤器。包含多个相机的数据集通常会在同一时间戳为每个相机输出一个(vqa,user)+(vqa,assistant)对;如果不使用 camera=,这些解析器会看到两个匹配项并引发歧义错误。配方通过各自的绑定以及匹配的图片块来消费每个相机,例如
ask_vqa_top:
route: vqa
bindings:
vqa_query: "emitted_at(t, style=vqa, role=user, camera=observation.images.top)"
vqa: "emitted_at(t, style=vqa, role=assistant, camera=observation.images.top)"
messages:
- role: user
stream: high_level
if_present: vqa_query
content:
- { type: image, feature: observation.images.top }
- { type: text, text: "${vqa_query}" }
- {
role: assistant,
content: "${vqa}",
stream: high_level,
target: true,
if_present: vqa,
}为数据集中记录的每个相机添加一个这样的子配方。显式的 route: vqa 标记会使匹配的稀疏 VQA 注释优先于常规的加权混合选择;组件名称仅用于描述。
第 3 层 — 训练格式
渲染的样本使用 HF 风格的聊天消息以及 LeRobot 边车:
sample["messages"]
sample["message_streams"]
sample["target_message_indices"]渲染器不会应用分词器的聊天模板。策略处理器决定如何为其骨干网络序列化消息,这使得同一数据集可以在 SmolVLA、Pi0.5 以及任何期望 OpenAI 风格聊天消息的未来 VLM 中通用。
混合
Blend 配方根据样本索引确定性地选择一个加权子配方。recipes/subtask_mem.yaml 用于训练紧凑的核心 blend——高层子任务预测、低层执行以及记忆。recipes/subtask_mem_vqa_speech.yaml 是更完整的变体,还额外添加了 VQA 和口语插话响应。
recipes/subtask_joint.yaml 演示的是联合序列训练,而非加权混合。对于同一个样本,其 assistant 子任务在 low_level 流上使用文本交叉熵进行监督,同时动作预测保持激活状态,这与 π0.5 论文中的联合设置一致。目前它仅用于训练:运行时在推理阶段尚不会重建此联合前缀。
优雅缺席
如果两个语言列均缺失、为 None 或为空,RenderTrainingMessagesStep 会在可用时使用任务字符串作为低层监督信号,否则保持样本不变。对于已标注的样本,如果没有任何配方分支适用且不存在任务回退机制,渲染将返回 None,以便加载器重试另一个样本。