LeRobot documentation
Столбцы и рецепты языков
Столбцы и рецепты языков
Большинство датасетов LeRobot поставляются с одной строкой task на эпизод — этого достаточно для коротких навыков с одной инструкцией, но этого мало для долгосрочных мультимодальных политик роботов, к которым движется область (высокоуровневое планирование, память, вставки, VQA, использование инструментов). Чтобы поддерживать такие политики без разветвления формата датасета, LeRobot расширяет LeRobotDataset двумя необязательными языковыми столбцами и небольшим слоем рецептов, который на лету превращает эти строки в обучающие примеры в формате чата.
Дизайн чётко разделяется на три уровня:
- Данные в наборе данных — языковые аннотации, хранящиеся рядом с кадрами в
data/chunk-*/file-*.parquetв виде двух необязательных столбцов (language_persistentиlanguage_events). Наборы данных без этих столбцов сохраняют свое существующее поведение. - Рецепт — это YAML-файл, в котором описывается, какие строки аннотаций привязать и как разложить их в виде реплик чата (
role,content, необязательные изображения, необязательные вызовы инструментов). Рецепты — это чистая конфигурация; для добавления нового не требуется писать код на Python. - Формат обучения — на этапе выборки
RenderTrainingMessagesStepсопоставляет рецепт с аннотациями для каждого кадра и формируетmessagesв стиле HF, а также специфичные для 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 — анатомия рецепта
Рецепты — это файлы YAML, основанные на TrainingRecipe и MessageTurn из lerobot.datasets.recipe. Они
объявляют, какие строки аннотаций извлекать (через 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), у резолвера появляется фильтр camera=, параллельный role= и tool_name=. Датасеты с несколькими камерами обычно выдают по одной паре (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 и любых будущих VLM, ожидающих сообщения в формате OpenAI.
Смеси
Blend-рецепты детерминированно выбирают один взвешенный под-рецепт по индексу образца. recipes/subtask_mem.yaml обучает компактный основной blend — предсказание подзадач высокого уровня, выполнение низкого уровня и память. recipes/subtask_mem_vqa_speech.yaml — более полный вариант, который также добавляет ответы на VQA и устные вставки.
recipes/subtask_joint.yaml демонстрирует совместное обучение последовательности, а не взвешенное смешивание. Для одного и того же примера его подзадача ассистента контролируется с помощью текстовой кросс-энтропии на потоке low_level, при этом предсказание действий остаётся активным, что соответствует совместной конфигурации из статьи π0.5. На данный момент это режим только для обучения: рантайм пока не перестраивает этот совместный префикс при инференсе.
Отсутствие без сбоев
Если обе языковые колонки отсутствуют, равны None или пусты, RenderTrainingMessagesStep использует строку задачи как низкоуровневое управление, если она доступна, а в противном случае оставляет образец без изменений. Для размеченного образца, если ни одна ветка рецепта не применяется и нет запасного варианта задачи, рендеринг возвращает None, что позволяет загрузчику повторить попытку с другим образцом.