LeRobot documentation

语言列和配方

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

语言列和配方

大多数 LeRobot 数据集每个 episode 仅附带一个 task 字符串——这对于简短的单指令技能来说已经足够,但不足以支撑该领域正在发展的长时程、多模态机器人策略(如高层规划、记忆、插话、VQA、工具使用)。为了在不分叉数据集格式的前提下支持这些策略,LeRobot 为 LeRobotDataset 扩展了两个可选的语言列,并添加了一个小型的 recipe 层,用于将这些行即时转换为 chat 风格的训练样本。

该设计清晰地分为三层:

  1. 数据集中的数据 — 以两个可选列(language_persistent 和 language_events)的形式,将语言标注存储在 data/chunk-*/file-*.parquet 中帧的旁边。不包含这些列的数据集将保持其现有行为。
  2. 配方 — 一个 YAML 文件,用于声明要绑定哪些标注行,以及如何将它们布局为聊天轮次(role、content、可选图像、可选工具调用)。配方是纯配置;添加新配方无需编写 Python 代码。
  3. 训练格式 — 在采样时,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} 配方绑定始终读取该任务字符串,且不依赖于语言注释。

架构

语言栈本身有三个内部模块支撑第一层:

  1. lerobot.datasets.language 定义了模式、样式注册表以及 column_for_style。
  2. lerobot.datasets.language_render 解析行并渲染消息。
  3. 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,以便加载器重试另一个样本。

Update on GitHub