Buckets:
| import"../chunks/DsnmJJEf.js";import{i as v,h as f,C as I,H as a,a as s,E as A,s as _}from"../chunks/C8NOCHVR.js";import{p as C,o as Z,s as e,f as Q,a as w,b as S,c as T,n as z}from"../chunks/CTvsL7Wh.js";const B='{"title":"Language columns and recipes","local":"language-columns-and-recipes","sections":[{"title":"Layer 1 — language columns in the dataset","local":"layer-1--language-columns-in-the-dataset","sections":[{"title":"Architecture","local":"architecture","sections":[],"depth":3}],"depth":2},{"title":"Layer 2 — recipe anatomy","local":"layer-2--recipe-anatomy","sections":[{"title":"Temporal semantics","local":"temporal-semantics","sections":[],"depth":3},{"title":"View-dependent resolution","local":"view-dependent-resolution","sections":[],"depth":3}],"depth":2},{"title":"Layer 3 — training format","local":"layer-3--training-format","sections":[],"depth":2},{"title":"Graceful absence","local":"graceful-absence","sections":[],"depth":2}],"depth":1}';var W=T('<meta name="hf:doc:metadata"/>'),E=T(`<p></p> <!> <!> <p>Most LeRobot datasets ship with a single <code>task</code> string per episode — fine for | |
| short, single-instruction skills, but not enough for the longer-horizon, | |
| multi-modal robot policies the field is moving toward (high-level planning, | |
| memory, interjections, VQA, tool use). To support those policies without | |
| forking the dataset format, LeRobot extends <code>LeRobotDataset</code> with two optional | |
| language columns and a small recipe layer that turns those rows into | |
| chat-style training samples on the fly.</p> <p>The design splits cleanly into three layers:</p> <ol><li><strong>Data in the dataset</strong> — language annotations stored next to frames in <code>data/chunk-*/file-*.parquet</code> as two optional columns (<code>language_persistent</code> and <code>language_events</code>). Datasets without these columns keep their existing | |
| behavior.</li> <li><strong>Recipe</strong> — a YAML file that declares which annotation rows to bind and | |
| how to lay them out as chat turns (<code>role</code>, <code>content</code>, optional images, | |
| optional tool calls). Recipes are pure config; no Python required to add a | |
| new one.</li> <li><strong>Training format</strong> — at sample time, <code>RenderMessagesStep</code> resolves the | |
| recipe against the per-frame annotations and emits HF-style <code>messages</code> plus | |
| LeRobot-specific sidecars (<code>message_streams</code>, <code>target_message_indices</code>) | |
| that policy processors consume.</li></ol> <p>This page describes each layer in turn.</p> <!> <p>The two optional columns live next to frame data in <code>data/chunk-*/file-*.parquet</code>:</p> <ul><li><code>language_persistent</code>: a list of rows broadcast across every frame in an episode for state that remains active, such as <code>subtask</code>, <code>plan</code>, and <code>memory</code>.</li> <li><code>language_events</code>: a list of rows only on the exact frame where an event was emitted, such as <code>interjection</code>, <code>vqa</code>, and speech tool calls.</li></ul> <p>Both columns share the same row shape (event rows omit <code>timestamp</code> because the | |
| frame the row sits on already provides it):</p> <!> <p>The <code>camera</code> field tags rows whose <code>content</code> is grounded in a specific camera | |
| view. Rows of view-dependent styles (<code>vqa</code> and <code>trace</code>) MUST set <code>camera</code> to | |
| the matching <code>observation.images.*</code> feature key. Rows of every other style — | |
| including <code>motion</code>, which describes robot-frame primitives in joint / Cartesian | |
| terms — MUST leave <code>camera</code> as <code>null</code>. Pipeline writers and the validator | |
| enforce this via <code>validate_camera_field(style, camera)</code>.</p> <p><code>meta/tasks.parquet</code> remains the canonical source for the task. The special <code>${task}</code> recipe binding always reads that task string and does not depend on language annotations.</p> <!> <p>The language stack itself has three internal modules backing layer 1:</p> <ol><li><code>lerobot.datasets.language</code> defines the schema, style registry, and <code>column_for_style</code>.</li> <li><code>lerobot.datasets.language_render</code> resolves rows and renders messages.</li> <li><code>RenderMessagesStep</code> turns dataset samples into <code>messages</code>, <code>message_streams</code>, and <code>target_message_indices</code>.</li></ol> <p><code>LeRobotDataset</code> stays recipe-agnostic. It passes <code>language_persistent</code> and <code>language_events</code> through when present, and unannotated datasets keep their existing behavior.</p> <!> <p>Recipes are YAML files backed by <code>TrainingRecipe</code> and <code>MessageTurn</code>. They | |
| declare which annotation rows to pull (via <code>bindings</code>) and how to compose them | |
| into chat turns (<code>messages</code>).</p> <!> <p>A recipe can also branch into a weighted <strong>blend</strong> of sub-recipes. At sample | |
| time, exactly one branch is selected deterministically from the sample index, | |
| so different frames train different objectives (e.g. memory updates vs. | |
| low-level execution vs. VQA) without any Python wiring.</p> <!> <p>Persistent styles are active after emission until replaced:</p> <ul><li><code>active_at(t, style=subtask)</code></li> <li><code>nth_prev(style=memory, offset=1)</code></li> <li><code>nth_next(style=subtask, offset=1)</code></li></ul> <p>Event styles only exist on their exact timestamp:</p> <ul><li><code>emitted_at(t, style=interjection)</code></li> <li><code>emitted_at(t, style=vqa, role=user, camera=observation.images.top)</code></li> <li><code>emitted_at(t, role=assistant, tool_name=say)</code></li></ul> <p>Exact event matching has no tolerance window, so writers must stamp event rows with frame timestamps from the parquet data.</p> <!> <p>For view-dependent styles (<code>vqa</code> and <code>trace</code>), the resolver gains a <code>camera=</code> filter parallel to <code>role=</code> and <code>tool_name=</code>. Datasets with multiple | |
| cameras typically emit one (<code>vqa</code>, <code>user</code>) + (<code>vqa</code>, <code>assistant</code>) pair per | |
| camera at the same timestamp; without <code>camera=</code>, those resolvers see two | |
| matches and raise an ambiguity error. Recipes consume each camera through its | |
| own binding plus a matching image block, e.g.</p> <!> <p>Add one such sub-recipe per camera the dataset records.</p> <!> <p>Rendered samples use HF-style chat messages plus LeRobot sidecars:</p> <!> <p>The renderer does not apply a tokenizer chat template. Policy processors decide how to serialize the messages for their backbone, which keeps the same dataset usable across SmolVLA, Pi0.5, and any future VLM that expects OpenAI-style chat messages.</p> <!> <p>If both language columns are missing, <code>None</code>, or empty, <code>RenderMessagesStep</code> is a no-op. | |
| If an event-scoped branch is selected on a frame without the required event row, rendering returns <code>None</code>, allowing a loader to retry another sample.</p> <!> <p></p>`,1);function x(J,U){C(U,!1),Z(()=>{new URLSearchParams(window.location.search).get("fw")}),v();var t=E();f("1yjjoj5",u=>{var j=W();_(j,"content",B),w(u,j)});var l=e(Q(t),2);I(l,{containerStyle:"float: right; margin-left: 10px; display: inline-flex; position: relative; z-index: 10;"});var n=e(l,2);a(n,{title:"Language columns and recipes",local:"language-columns-and-recipes",headingTag:"h1"});var o=e(n,10);a(o,{title:"Layer 1 — language columns in the dataset",local:"layer-1--language-columns-in-the-dataset",headingTag:"h2"});var c=e(o,8);s(c,{code:"cm9sZSUzQSUyMHN0cmluZyUwQWNvbnRlbnQlM0ElMjBzdHJpbmclMjAlN0MlMjBudWxsJTBBc3R5bGUlM0ElMjBzdHJpbmclMjAlN0MlMjBudWxsJTBBdGltZXN0YW1wJTNBJTIwZmxvYXQzMiUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMyUyMHBlcnNpc3RlbnQlMjByb3dzJTIwb25seSUwQWNhbWVyYSUzQSUyMHN0cmluZyUyMCU3QyUyMG51bGwlMjAlMjAlMjAlMjAlMjAlMjMlMjBvYnNlcnZhdGlvbi5pbWFnZXMuKiUyMGZlYXR1cmUlMjBrZXklMkMlMjB2aWV3LWRlcGVuZGVudCUyMHJvd3MlMjBvbmx5JTBBdG9vbF9jYWxscyUzQSUyMGxpc3QlNUJKc29uJTVEJTIwJTdDJTIwbnVsbA==",highlighted:`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`,lang:"text",wrap:!1});var i=e(c,6);a(i,{title:"Architecture",local:"architecture",headingTag:"h3"});var r=e(i,8);a(r,{title:"Layer 2 — recipe anatomy",local:"layer-2--recipe-anatomy",headingTag:"h2"});var d=e(r,4);s(d,{code:"bWVzc2FnZXMlM0ElMEElMjAlMjAtJTIwJTdCJTIwcm9sZSUzQSUyMHVzZXIlMkMlMjBjb250ZW50JTNBJTIwJTIyJTI0JTdCdGFzayU3RCUyMiUyQyUyMHN0cmVhbSUzQSUyMGhpZ2hfbGV2ZWwlMjAlN0QlMEElMjAlMjAtJTIwJTdCJTIwcm9sZSUzQSUyMGFzc2lzdGFudCUyQyUyMGNvbnRlbnQlM0ElMjAlMjIlMjQlN0JzdWJ0YXNrJTdEJTIyJTJDJTIwc3RyZWFtJTNBJTIwbG93X2xldmVsJTJDJTIwdGFyZ2V0JTNBJTIwdHJ1ZSUyMCU3RA==",highlighted:'<span class="hljs-attr">messages:</span>\n <span class="hljs-bullet">-</span> { <span class="hljs-attr">role:</span> <span class="hljs-string">user</span>, <span class="hljs-attr">content:</span> <span class="hljs-string">"${task}"</span>, <span class="hljs-attr">stream:</span> <span class="hljs-string">high_level</span> }\n <span class="hljs-bullet">-</span> { <span class="hljs-attr">role:</span> <span class="hljs-string">assistant</span>, <span class="hljs-attr">content:</span> <span class="hljs-string">"${subtask}"</span>, <span class="hljs-attr">stream:</span> <span class="hljs-string">low_level</span>, <span class="hljs-attr">target:</span> <span class="hljs-literal">true</span> }',lang:"yaml",wrap:!1});var p=e(d,4);a(p,{title:"Temporal semantics",local:"temporal-semantics",headingTag:"h3"});var h=e(p,12);a(h,{title:"View-dependent resolution",local:"view-dependent-resolution",headingTag:"h3"});var m=e(h,4);s(m,{code:"YXNrX3ZxYV90b3AlM0ElMEElMjAlMjBiaW5kaW5ncyUzQSUwQSUyMCUyMCUyMCUyMHZxYV9xdWVyeSUzQSUyMCUyMmVtaXR0ZWRfYXQodCUyQyUyMHN0eWxlJTNEdnFhJTJDJTIwcm9sZSUzRHVzZXIlMkMlMjBjYW1lcmElM0RvYnNlcnZhdGlvbi5pbWFnZXMudG9wKSUyMiUwQSUyMCUyMCUyMCUyMHZxYSUzQSUyMCUyMmVtaXR0ZWRfYXQodCUyQyUyMHN0eWxlJTNEdnFhJTJDJTIwcm9sZSUzRGFzc2lzdGFudCUyQyUyMGNhbWVyYSUzRG9ic2VydmF0aW9uLmltYWdlcy50b3ApJTIyJTBBJTIwJTIwbWVzc2FnZXMlM0ElMEElMjAlMjAlMjAlMjAtJTIwcm9sZSUzQSUyMHVzZXIlMEElMjAlMjAlMjAlMjAlMjAlMjBzdHJlYW0lM0ElMjBoaWdoX2xldmVsJTBBJTIwJTIwJTIwJTIwJTIwJTIwaWZfcHJlc2VudCUzQSUyMHZxYV9xdWVyeSUwQSUyMCUyMCUyMCUyMCUyMCUyMGNvbnRlbnQlM0ElMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAtJTIwJTdCJTIwdHlwZSUzQSUyMGltYWdlJTJDJTIwZmVhdHVyZSUzQSUyMG9ic2VydmF0aW9uLmltYWdlcy50b3AlMjAlN0QlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAtJTIwJTdCJTIwdHlwZSUzQSUyMHRleHQlMkMlMjB0ZXh0JTNBJTIwJTIyJTI0JTdCdnFhX3F1ZXJ5JTdEJTIyJTIwJTdEJTBBJTIwJTIwJTIwJTIwLSUyMCU3QiUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMHJvbGUlM0ElMjBhc3Npc3RhbnQlMkMlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjBjb250ZW50JTNBJTIwJTIyJTI0JTdCdnFhJTdEJTIyJTJDJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwc3RyZWFtJTNBJTIwaGlnaF9sZXZlbCUyQyUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMHRhcmdldCUzQSUyMHRydWUlMkMlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjBpZl9wcmVzZW50JTNBJTIwdnFhJTJDJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTdE",highlighted:`<span class="hljs-attr">ask_vqa_top:</span> | |
| <span class="hljs-attr">bindings:</span> | |
| <span class="hljs-attr">vqa_query:</span> <span class="hljs-string">"emitted_at(t, style=vqa, role=user, camera=observation.images.top)"</span> | |
| <span class="hljs-attr">vqa:</span> <span class="hljs-string">"emitted_at(t, style=vqa, role=assistant, camera=observation.images.top)"</span> | |
| <span class="hljs-attr">messages:</span> | |
| <span class="hljs-bullet">-</span> <span class="hljs-attr">role:</span> <span class="hljs-string">user</span> | |
| <span class="hljs-attr">stream:</span> <span class="hljs-string">high_level</span> | |
| <span class="hljs-attr">if_present:</span> <span class="hljs-string">vqa_query</span> | |
| <span class="hljs-attr">content:</span> | |
| <span class="hljs-bullet">-</span> { <span class="hljs-attr">type:</span> <span class="hljs-string">image</span>, <span class="hljs-attr">feature:</span> <span class="hljs-string">observation.images.top</span> } | |
| <span class="hljs-bullet">-</span> { <span class="hljs-attr">type:</span> <span class="hljs-string">text</span>, <span class="hljs-attr">text:</span> <span class="hljs-string">"\${vqa_query}"</span> } | |
| <span class="hljs-bullet">-</span> { | |
| <span class="hljs-attr">role:</span> <span class="hljs-string">assistant</span>, | |
| <span class="hljs-attr">content:</span> <span class="hljs-string">"\${vqa}"</span>, | |
| <span class="hljs-attr">stream:</span> <span class="hljs-string">high_level</span>, | |
| <span class="hljs-attr">target:</span> <span class="hljs-literal">true</span>, | |
| <span class="hljs-attr">if_present:</span> <span class="hljs-string">vqa</span>, | |
| }`,lang:"yaml",wrap:!1});var M=e(m,4);a(M,{title:"Layer 3 — training format",local:"layer-3--training-format",headingTag:"h2"});var g=e(M,4);s(g,{code:"c2FtcGxlJTVCJTIybWVzc2FnZXMlMjIlNUQlMEFzYW1wbGUlNUIlMjJtZXNzYWdlX3N0cmVhbXMlMjIlNUQlMEFzYW1wbGUlNUIlMjJ0YXJnZXRfbWVzc2FnZV9pbmRpY2VzJTIyJTVE",highlighted:`sample[<span class="hljs-string">"messages"</span>] | |
| sample[<span class="hljs-string">"message_streams"</span>] | |
| sample[<span class="hljs-string">"target_message_indices"</span>]`,lang:"python",wrap:!1});var y=e(g,4);a(y,{title:"Graceful absence",local:"graceful-absence",headingTag:"h2"});var b=e(y,4);A(b,{source:"https://github.com/huggingface/lerobot/blob/main/docs/source/language_and_recipes.mdx"}),z(2),w(J,t),S()}export{x as component}; | |
Xet Storage Details
- Size:
- 13.7 kB
- Xet hash:
- 9165432db56c0162aaf36abb9671a9cc6220a0a0827e50e8d42c05a151bb78a0
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.