LeRobot documentation

Colonnes de langue et recettes

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

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 :

  1. Données dans le jeu de données — annotations de langue stockées à côté des images dans data/chunk-*/file-*.parquet sous forme de deux colonnes facultatives (language_persistent et language_events). Les jeux de données sans ces colonnes conservent leur comportement existant.
  2. 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.
  3. Format d’entraînement — au moment de l’échantillonnage, RenderTrainingMessagesStep résout la recette par rapport aux annotations par image et émet des messages au 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 que subtask, plan et memory.
  • language_events : une liste de lignes uniquement sur le cadre exact où un événement a été émis, tel que interjection, vqa et 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 :

  1. lerobot.datasets.language définit le schéma, le registre de styles et column_for_style.
  2. lerobot.datasets.language_render résout les lignes et affiche les messages.
  3. RenderTrainingMessagesStep transforme les échantillons du jeu de données en messages, message_streams et target_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.

Update on GitHub