LeRobot documentation
Colonnes de langue et recettes
Colonnes de langue et recettes
La plupart des jeux de données LeRobot sont livrés avec une seule chaîne task par épisode — ce qui convient aux compétences courtes et à instruction unique, mais qui est insuffisant pour les politiques robotiques à long horizon et multimodales vers lesquelles le domaine évolue (planification de haut niveau, mémoire, interjections, VQA, utilisation d’outils). Pour prendre en charge ces politiques sans forker le format de jeu de données, LeRobot étend LeRobotDataset avec deux colonnes de langage facultatives et une petite couche de recette qui transforme ces lignes en échantillons d’entraînement de type chat à la volée.
La conception se découpe nettement en trois couches :
- Données dans le jeu de données — annotations de langue stockées à côté des images dans
data/chunk-*/file-*.parquetsous forme de deux colonnes facultatives (language_persistentetlanguage_events). Les jeux de données sans ces colonnes conservent leur comportement existant. - Recette — un fichier YAML qui déclare quelles lignes d'annotation lier et comment les disposer en tours de chat (
role,content, images facultatives, appels d'outils facultatifs). Les recettes sont de la pure configuration ; aucun Python n'est requis pour en ajouter une nouvelle. - Format d’entraînement — au moment de l’échantillonnage,
RenderTrainingMessagesSteprésout la recette par rapport aux annotations par image et émet desmessagesau format HF ainsi que des fichiers secondaires spécifiques à LeRobot (message_streams,target_message_indices) que les processeurs de politique consomment.
Cette page décrit chaque couche à son tour.
Couche 1 — colonnes de langue dans le jeu de données
Les deux colonnes facultatives se trouvent à côté des données de trame dans data/chunk-*/file-*.parquet :
language_persistent: une liste de lignes diffusées sur chaque image d'un épisode pour l'état qui reste actif, tel quesubtask,planetmemory.language_events: une liste de lignes uniquement sur le cadre exact où un événement a été émis, tel queinterjection,vqaet les appels d’outils vocaux.
Les deux colonnes partagent la même forme de ligne (les lignes d'événement omettent timestamp car le cadre sur lequel se trouve la ligne le fournit déjà) :
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
Le champ camera étiquette les lignes dont le content est ancré dans une vue de caméra spécifique. Les lignes des styles dépendants de la vue (vqa et trace) DOIVENT définir camera sur la clé de fonctionnalité correspondante de observation.images.*. Les lignes de tous les autres styles — y compris motion, qui décrit des primitives du repère du robot en termes articulaires / cartésiens — DOIVENT laisser camera à null. Les rédacteurs du pipeline et le validateur appliquent cette règle via validate_camera_field(style, camera).
meta/tasks.parquet reste la source canonique pour la tâche. Le binding de recette spécial ${task} lit toujours cette chaîne de caractères de tâche et ne dépend pas des annotations de langue.
Architecture
La pile de langage elle-même comporte trois modules internes soutenant la couche 1 :
lerobot.datasets.languagedéfinit le schéma, le registre de styles etcolumn_for_style.lerobot.datasets.language_renderrésout les lignes et affiche les messages.RenderTrainingMessagesSteptransforme les échantillons du jeu de données enmessages,message_streamsettarget_message_indices.
LeRobotDataset reste indépendant des recettes. Il transmet language_persistent et language_events lorsqu’ils sont présents, et les jeux de données non annotés conservent leur comportement existant.
Couche 2 — anatomie de la recette
Les recettes sont des fichiers YAML adossés à TrainingRecipe et MessageTurn de lerobot.datasets.recipe. Elles
déclarent quelles lignes d’annotation extraire (via bindings) et comment les composer
en tours de chat (messages).
messages:
- { role: user, content: "${task}", stream: high_level }
- { role: assistant, content: "${subtask}", stream: low_level, target: true }Une recette peut également se ramifier en un mélange pondéré de sous-recettes. Au moment de l'échantillonnage, exactement une branche est sélectionnée de manière déterministe à partir de l'index de l'échantillon, de sorte que différentes images entraînent différents objectifs (par exemple, mises à jour de la mémoire par rapport à l'exécution de bas niveau par rapport à la VQA) sans aucun câblage Python.
Sémantique temporelle
Les styles persistants restent actifs après leur émission jusqu'à ce qu'ils soient remplacés :
active_at(t, style=subtask)nth_prev(style=memory, offset=1)nth_next(style=subtask, offset=1)
Les styles d'événement n'existent que sur leur horodatage exact :
emitted_at(t, style=interjection)emitted_at(t, style=vqa, role=user, camera=observation.images.top)emitted_at(t, role=assistant, tool_name=say)
La correspondance exacte des événements n’a pas de fenêtre de tolérance, les rédacteurs doivent donc horodater les lignes d’événements avec les horodatages des images issus des données parquet.
Résolution dépendante de la vue
Pour les styles dépendants de la vue (vqa et trace), le résolveur gagne un filtre camera= parallèle à role= et tool_name=. Les jeux de données avec plusieurs caméras émettent typiquement une paire (vqa, user) + (vqa, assistant) par caméra au même horodatage ; sans camera=, ces résolveurs voient deux correspondances et lèvent une erreur d’ambiguïté. Les recettes consomment chaque caméra via sa propre liaison plus un bloc d’image correspondant, par exemple
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,
}Ajoutez un tel sous-réceptacle pour chaque caméra enregistrée par le jeu de données. Le marqueur explicite route: vqa permet à une annotation VQA correspondante de prendre le pas sur la sélection pondérée standard ; les noms des composants sont purement descriptifs.
Couche 3 — format d'entraînement
Les échantillons rendus utilisent des messages de chat au format HF ainsi que des sidecars LeRobot :
sample["messages"]
sample["message_streams"]
sample["target_message_indices"]Le renderer n’applique pas de modèle de chat du tokenizer. Les processeurs de politique décident comment sérialiser les messages pour leur backbone, ce qui permet de réutiliser le même jeu de données avec SmolVLA, Pi0.5 et tout futur VLM qui s’attend à des messages de chat au format OpenAI.
Mélanges
Les recettes de mélange sélectionnent de manière déterministe une sous-recette pondérée à partir de l’index de l’échantillon. recipes/subtask_mem.yaml entraîne le mélange compact du cœur — prédiction de sous-tâches de haut niveau, exécution de bas niveau et mémoire. recipes/subtask_mem_vqa_speech.yaml est la variante plus complète qui ajoute également les réponses VQA et les interjections orales.
recipes/subtask_joint.yaml illustre un entraînement conjoint de séquences plutôt qu’un mélange pondéré. Pour un même échantillon, sa sous-tâche assistant est supervisée par l’entropie croisée de texte sur le flux low_level tandis que la prédiction d’action reste active, conformément à la configuration conjointe du papier π0.5. Il est actuellement réservé à l’entraînement : le runtime ne reconstruit pas encore ce préfixe conjoint lors de l’inférence.
Absence élégante
Si les deux colonnes de langue sont absentes, None ou vides, RenderTrainingMessagesStep utilise la chaîne de tâche comme supervision de bas niveau lorsqu’elle est disponible, et laisse sinon l’échantillon inchangé. Pour un échantillon annoté, si aucune branche de recette ne s’applique et qu’aucun repli sur la tâche n’existe, le rendu renvoie None, permettant à un chargeur de réessayer avec un autre échantillon.