Buckets:
| <meta charset="utf-8" /><meta name="hf:doc:metadata" content="{"title":"Implement your own Robot Processor","local":"implement-your-own-robot-processor","sections":[{"title":"Why would you need a custom processor?","local":"why-would-you-need-a-custom-processor","sections":[],"depth":2},{"title":"How to implement your own processor?","local":"how-to-implement-your-own-processor","sections":[{"title":"Implement the __call__ method","local":"implement-the-call-method","sections":[],"depth":3},{"title":"Configuration and State Management","local":"configuration-and-state-management","sections":[],"depth":3},{"title":"Transform features","local":"transform-features","sections":[],"depth":3},{"title":"Using overrides","local":"using-overrides","sections":[],"depth":3}],"depth":2},{"title":"Best Practices","local":"best-practices","sections":[{"title":"1. Safe Data Handling","local":"1-safe-data-handling","sections":[],"depth":3},{"title":"2. Choose Appropriate Base Classes","local":"2-choose-appropriate-base-classes","sections":[],"depth":3},{"title":"3. Registration and Naming","local":"3-registration-and-naming","sections":[],"depth":3},{"title":"4. State Management Patterns","local":"4-state-management-patterns","sections":[],"depth":3},{"title":"5. Input Validation and Error Handling","local":"5-input-validation-and-error-handling","sections":[],"depth":3},{"title":"6. Device and Dtype Awareness","local":"6-device-and-dtype-awareness","sections":[],"depth":3}],"depth":2},{"title":"Conclusion","local":"conclusion","sections":[],"depth":2}],"depth":1}"> | |
| <link href="/docs/lerobot/pr_3313/en/_app/immutable/assets/0.e3b0c442.css" rel="modulepreload"> | |
| <link rel="modulepreload" href="/docs/lerobot/pr_3313/en/_app/immutable/entry/start.d3f1c0f3.js"> | |
| <link rel="modulepreload" href="/docs/lerobot/pr_3313/en/_app/immutable/chunks/scheduler.eb244325.js"> | |
| <link rel="modulepreload" href="/docs/lerobot/pr_3313/en/_app/immutable/chunks/singletons.1f33814c.js"> | |
| <link rel="modulepreload" href="/docs/lerobot/pr_3313/en/_app/immutable/chunks/index.3c23fb4b.js"> | |
| <link rel="modulepreload" href="/docs/lerobot/pr_3313/en/_app/immutable/chunks/paths.17f05d75.js"> | |
| <link rel="modulepreload" href="/docs/lerobot/pr_3313/en/_app/immutable/entry/app.04bb7687.js"> | |
| <link rel="modulepreload" href="/docs/lerobot/pr_3313/en/_app/immutable/chunks/preload-helper.b00aacbc.js"> | |
| <link rel="modulepreload" href="/docs/lerobot/pr_3313/en/_app/immutable/chunks/index.3fe63ad3.js"> | |
| <link rel="modulepreload" href="/docs/lerobot/pr_3313/en/_app/immutable/nodes/0.07fbe93e.js"> | |
| <link rel="modulepreload" href="/docs/lerobot/pr_3313/en/_app/immutable/chunks/each.e59479a4.js"> | |
| <link rel="modulepreload" href="/docs/lerobot/pr_3313/en/_app/immutable/nodes/25.590626a0.js"> | |
| <link rel="modulepreload" href="/docs/lerobot/pr_3313/en/_app/immutable/chunks/CopyLLMTxtMenu.d0c64540.js"> | |
| <link rel="modulepreload" href="/docs/lerobot/pr_3313/en/_app/immutable/chunks/MermaidChart.svelte_svelte_type_style_lang.6453902c.js"> | |
| <link rel="modulepreload" href="/docs/lerobot/pr_3313/en/_app/immutable/chunks/CodeBlock.48dd2cc2.js"><!-- HEAD_svelte-u9bgzb_START --><meta name="hf:doc:metadata" content="{"title":"Implement your own Robot Processor","local":"implement-your-own-robot-processor","sections":[{"title":"Why would you need a custom processor?","local":"why-would-you-need-a-custom-processor","sections":[],"depth":2},{"title":"How to implement your own processor?","local":"how-to-implement-your-own-processor","sections":[{"title":"Implement the __call__ method","local":"implement-the-call-method","sections":[],"depth":3},{"title":"Configuration and State Management","local":"configuration-and-state-management","sections":[],"depth":3},{"title":"Transform features","local":"transform-features","sections":[],"depth":3},{"title":"Using overrides","local":"using-overrides","sections":[],"depth":3}],"depth":2},{"title":"Best Practices","local":"best-practices","sections":[{"title":"1. Safe Data Handling","local":"1-safe-data-handling","sections":[],"depth":3},{"title":"2. Choose Appropriate Base Classes","local":"2-choose-appropriate-base-classes","sections":[],"depth":3},{"title":"3. Registration and Naming","local":"3-registration-and-naming","sections":[],"depth":3},{"title":"4. State Management Patterns","local":"4-state-management-patterns","sections":[],"depth":3},{"title":"5. Input Validation and Error Handling","local":"5-input-validation-and-error-handling","sections":[],"depth":3},{"title":"6. Device and Dtype Awareness","local":"6-device-and-dtype-awareness","sections":[],"depth":3}],"depth":2},{"title":"Conclusion","local":"conclusion","sections":[],"depth":2}],"depth":1}"><!-- HEAD_svelte-u9bgzb_END --> <p></p> <div class="items-center shrink-0 min-w-[100px] max-sm:min-w-[50px] justify-end ml-auto flex" style="float: right; margin-left: 10px; display: inline-flex; position: relative; z-index: 10;"><div class="inline-flex rounded-md max-sm:rounded-sm"><button class="inline-flex items-center gap-1 h-7 max-sm:h-7 px-2 max-sm:px-1.5 text-sm font-medium text-gray-800 border border-r-0 rounded-l-md max-sm:rounded-l-sm border-gray-200 bg-white hover:shadow-inner dark:border-gray-850 dark:bg-gray-950 dark:text-gray-200 dark:hover:bg-gray-800" aria-live="polite"><span class="inline-flex items-center justify-center rounded-md p-0.5 max-sm:p-0 hover:text-gray-800 dark:hover:text-gray-200"><svg class="sm:size-3.5 size-3" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg></span> <span>Copy page</span></button> <button class="inline-flex items-center justify-center w-6 max-sm:w-5 h-7 max-sm:h-7 disabled:pointer-events-none text-sm text-gray-500 hover:text-gray-700 dark:hover:text-white rounded-r-md max-sm:rounded-r-sm border border-l transition border-gray-200 bg-white hover:shadow-inner dark:border-gray-850 dark:bg-gray-950 dark:text-gray-200 dark:hover:bg-gray-800" aria-haspopup="menu" aria-expanded="false" aria-label="Open copy menu"><svg class="transition-transform text-gray-400 overflow-visible sm:size-3.5 size-3 rotate-0" width="1em" height="1em" viewBox="0 0 12 7" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M1 1L6 6L11 1" stroke="currentColor"></path></svg></button></div> </div> <h1 class="relative group"><a id="implement-your-own-robot-processor" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#implement-your-own-robot-processor"><span><svg class="" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span></a> <span>Implement your own Robot Processor</span></h1> <p data-svelte-h="svelte-f2ydop">In this tutorial, you’ll learn how to implement your own Robot Processor. | |
| It begins by exploring the need for a custom processor, then uses the <code>NormalizerProcessorStep</code> as the running example to explain how to implement, configure, and serialize a processor. Finally, it lists all helper processors that ship with LeRobot.</p> <h2 class="relative group"><a id="why-would-you-need-a-custom-processor" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#why-would-you-need-a-custom-processor"><span><svg class="" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span></a> <span>Why would you need a custom processor?</span></h2> <p data-svelte-h="svelte-14012gf">In most cases, when reading raw data from sensors or when models output actions, you need to process this data to make it compatible with your target system. For example, a common need is normalizing data ranges to make them suitable for neural networks.</p> <p data-svelte-h="svelte-1pqilce">LeRobot’s <code>NormalizerProcessorStep</code> handles this crucial task:</p> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg class="" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg> <div class="absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0"><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent; "></div> Copied</div></button></div> <pre class=""><!-- HTML_TAG_START --><span class="hljs-comment"># Input: raw joint positions in [0, 180] degrees</span> | |
| raw_action = torch.tensor([<span class="hljs-number">90.0</span>, <span class="hljs-number">45.0</span>, <span class="hljs-number">135.0</span>]) | |
| <span class="hljs-comment"># After processing: normalized to [-1, 1] range for model training</span> | |
| normalizer = NormalizerProcessorStep(features=features, norm_map=norm_map, stats=dataset_stats) | |
| normalized_result = normalizer(transition) | |
| <span class="hljs-comment"># ...</span><!-- HTML_TAG_END --></pre></div> <p data-svelte-h="svelte-s4qb1l">Other common processing needs include:</p> <ul data-svelte-h="svelte-j94eby"><li><strong>Device placement</strong>: Moving tensors between CPU/GPU and converting data types</li> <li><strong>Format conversion</strong>: Transforming between different data structures</li> <li><strong>Batching</strong>: Adding/removing batch dimensions for model compatibility</li> <li><strong>Safety constraints</strong>: Applying limits to robot commands</li></ul> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg class="" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg> <div class="absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0"><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent; "></div> Copied</div></button></div> <pre class=""><!-- HTML_TAG_START --><span class="hljs-comment"># Example pipeline combining multiple processors</span> | |
| pipeline = PolicyProcessorPipeline([ | |
| RenameObservationsProcessorStep(rename_map={}), | |
| AddBatchDimensionProcessorStep(), | |
| NormalizerProcessorStep(features=features, stats=stats), | |
| DeviceProcessorStep(device=<span class="hljs-string">"cuda"</span>), | |
| <span class="hljs-comment"># ...</span> | |
| ])<!-- HTML_TAG_END --></pre></div> <p data-svelte-h="svelte-1vf7vne">LeRobot provides a pipeline mechanism to implement sequences of processing steps for both input data and output actions, making it easy to compose these transformations in the right order for optimal performance.</p> <h2 class="relative group"><a id="how-to-implement-your-own-processor" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#how-to-implement-your-own-processor"><span><svg class="" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span></a> <span>How to implement your own processor?</span></h2> <p data-svelte-h="svelte-1qsxaj2">We’ll use the <code>NormalizerProcessorStep</code> as our main example because it demonstrates essential processor patterns including state management, configuration serialization, and tensor handling that you’ll commonly need.</p> <p data-svelte-h="svelte-119p6dx">Prepare the sequence of processing steps necessary for your problem. A processor step is a class that implements the following methods:</p> <ul data-svelte-h="svelte-3mrreh"><li><code>__call__</code>: implements the processing step for the input transition.</li> <li><code>get_config</code>: gets the configuration of the processor step.</li> <li><code>state_dict</code>: gets the state of the processor step.</li> <li><code>load_state_dict</code>: loads the state of the processor step.</li> <li><code>reset</code>: resets the state of the processor step.</li> <li><code>feature_contract</code>: displays the modification to the feature space during the processor step.</li></ul> <h3 class="relative group"><a id="implement-the-call-method" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#implement-the-call-method"><span><svg class="" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span></a> <span>Implement the __call__ method</span></h3> <p data-svelte-h="svelte-ata62c">The <code>__call__</code> method is the core of your processor step. It takes an <code>EnvTransition</code> and returns a modified <code>EnvTransition</code>. Here’s how the <code>NormalizerProcessorStep</code> works:</p> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg class="" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg> <div class="absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0"><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent; "></div> Copied</div></button></div> <pre class=""><!-- HTML_TAG_START --><span class="hljs-meta">@dataclass</span> | |
| <span class="hljs-meta">@ProcessorStepRegistry.register(<span class="hljs-params"><span class="hljs-string">"normalizer_processor"</span></span>)</span> | |
| <span class="hljs-keyword">class</span> <span class="hljs-title class_">NormalizerProcessorStep</span>(<span class="hljs-title class_ inherited__">ProcessorStep</span>): | |
| <span class="hljs-string">"""Normalize observations/actions using dataset statistics."""</span> | |
| features: <span class="hljs-built_in">dict</span>[<span class="hljs-built_in">str</span>, PolicyFeature] | |
| norm_map: <span class="hljs-built_in">dict</span>[FeatureType, NormalizationMode] | |
| stats: <span class="hljs-built_in">dict</span>[<span class="hljs-built_in">str</span>, <span class="hljs-built_in">dict</span>[<span class="hljs-built_in">str</span>, <span class="hljs-type">Any</span>]] | <span class="hljs-literal">None</span> = <span class="hljs-literal">None</span> | |
| eps: <span class="hljs-built_in">float</span> = <span class="hljs-number">1e-8</span> | |
| _tensor_stats: <span class="hljs-built_in">dict</span> = field(default_factory=<span class="hljs-built_in">dict</span>, init=<span class="hljs-literal">False</span>, <span class="hljs-built_in">repr</span>=<span class="hljs-literal">False</span>) | |
| <span class="hljs-keyword">def</span> <span class="hljs-title function_">__post_init__</span>(<span class="hljs-params">self</span>): | |
| <span class="hljs-string">"""Convert stats to tensors for efficient computation."""</span> | |
| self.stats = self.stats <span class="hljs-keyword">or</span> {} | |
| self._tensor_stats = to_tensor(self.stats, device=self.device, dtype=torch.float32) | |
| <span class="hljs-keyword">def</span> <span class="hljs-title function_">__call__</span>(<span class="hljs-params">self, transition: EnvTransition</span>) -> EnvTransition: | |
| new_transition = transition.copy() | |
| <span class="hljs-comment"># Normalize observations</span> | |
| <span class="hljs-comment"># ...</span> | |
| <span class="hljs-comment"># Normalize action</span> | |
| <span class="hljs-comment"># ...</span> | |
| <span class="hljs-keyword">return</span> new_transition | |
| <!-- HTML_TAG_END --></pre></div> <p data-svelte-h="svelte-15o252k">See the full implementation in <code>src/lerobot/processor/normalize_processor.py</code> for complete details.</p> <p data-svelte-h="svelte-3wif3z"><strong>Key principles:</strong></p> <ul data-svelte-h="svelte-1mvgztx"><li><strong>Always use <code>transition.copy()</code></strong> to avoid side effects</li> <li><strong>Handle both observations and actions</strong> consistently</li> <li><strong>Separate config from state</strong>: <code>get_config()</code> returns JSON-serializable params, <code>state_dict()</code> returns tensors</li> <li><strong>Convert stats to tensors</strong> in <code>__post_init__()</code> for efficient computation</li></ul> <h3 class="relative group"><a id="configuration-and-state-management" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#configuration-and-state-management"><span><svg class="" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span></a> <span>Configuration and State Management</span></h3> <p data-svelte-h="svelte-b2vh7o">Processors support serialization through three methods that separate configuration from tensor state. The <code>NormalizerProcessorStep</code> demonstrates this perfectly - it carries dataset statistics (tensors) in its state, and hyperparameters in its config:</p> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg class="" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg> <div class="absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0"><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent; "></div> Copied</div></button></div> <pre class=""><!-- HTML_TAG_START --><span class="hljs-comment"># Continuing the NormalizerProcessorStep example...</span> | |
| <span class="hljs-keyword">def</span> <span class="hljs-title function_">get_config</span>(<span class="hljs-params">self</span>) -> <span class="hljs-built_in">dict</span>[<span class="hljs-built_in">str</span>, <span class="hljs-type">Any</span>]: | |
| <span class="hljs-string">"""JSON-serializable configuration (no tensors)."""</span> | |
| <span class="hljs-keyword">return</span> { | |
| <span class="hljs-string">"eps"</span>: self.eps, | |
| <span class="hljs-string">"features"</span>: {k: {<span class="hljs-string">"type"</span>: v.<span class="hljs-built_in">type</span>.value, <span class="hljs-string">"shape"</span>: v.shape} <span class="hljs-keyword">for</span> k, v <span class="hljs-keyword">in</span> self.features.items()}, | |
| <span class="hljs-string">"norm_map"</span>: {ft.value: nm.value <span class="hljs-keyword">for</span> ft, nm <span class="hljs-keyword">in</span> self.norm_map.items()}, | |
| <span class="hljs-comment"># ...</span> | |
| } | |
| <span class="hljs-keyword">def</span> <span class="hljs-title function_">state_dict</span>(<span class="hljs-params">self</span>) -> <span class="hljs-built_in">dict</span>[<span class="hljs-built_in">str</span>, torch.Tensor]: | |
| <span class="hljs-string">"""Tensor state only (e.g., dataset statistics)."""</span> | |
| flat: <span class="hljs-built_in">dict</span>[<span class="hljs-built_in">str</span>, torch.Tensor] = {} | |
| <span class="hljs-keyword">for</span> key, sub <span class="hljs-keyword">in</span> self._tensor_stats.items(): | |
| <span class="hljs-keyword">for</span> stat_name, tensor <span class="hljs-keyword">in</span> sub.items(): | |
| flat[<span class="hljs-string">f"<span class="hljs-subst">{key}</span>.<span class="hljs-subst">{stat_name}</span>"</span>] = tensor.cpu() <span class="hljs-comment"># Always save to CPU</span> | |
| <span class="hljs-keyword">return</span> flat | |
| <span class="hljs-keyword">def</span> <span class="hljs-title function_">load_state_dict</span>(<span class="hljs-params">self, state: <span class="hljs-built_in">dict</span>[<span class="hljs-built_in">str</span>, torch.Tensor]</span>) -> <span class="hljs-literal">None</span>: | |
| <span class="hljs-string">"""Restore tensor state at runtime."""</span> | |
| self._tensor_stats.clear() | |
| <span class="hljs-keyword">for</span> flat_key, tensor <span class="hljs-keyword">in</span> state.items(): | |
| key, stat_name = flat_key.rsplit(<span class="hljs-string">"."</span>, <span class="hljs-number">1</span>) | |
| <span class="hljs-comment"># Load to processor's configured device</span> | |
| self._tensor_stats.setdefault(key, {})[stat_name] = tensor.to( | |
| dtype=torch.float32, device=self.device | |
| ) | |
| <span class="hljs-comment"># ...</span><!-- HTML_TAG_END --></pre></div> <p data-svelte-h="svelte-qbjyqk"><strong>Usage:</strong></p> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg class="" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg> <div class="absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0"><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent; "></div> Copied</div></button></div> <pre class=""><!-- HTML_TAG_START --><span class="hljs-comment"># Save (e.g., inside a policy)</span> | |
| config = normalizer.get_config() | |
| tensors = normalizer.state_dict() | |
| <span class="hljs-comment"># Restore (e.g., loading a pretrained policy)</span> | |
| new_normalizer = NormalizerProcessorStep(**config) | |
| new_normalizer.load_state_dict(tensors) | |
| <span class="hljs-comment"># Now new_normalizer has the same stats and configuration</span><!-- HTML_TAG_END --></pre></div> <h3 class="relative group"><a id="transform-features" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#transform-features"><span><svg class="" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span></a> <span>Transform features</span></h3> <p data-svelte-h="svelte-zpl57h">The <code>transform_features</code> method defines how your processor transforms feature names and shapes. This is crucial for policy configuration and debugging.</p> <p data-svelte-h="svelte-1se5k3a">For <code>NormalizerProcessorStep</code>, features are typically preserved unchanged since normalization doesn’t alter keys or shapes:</p> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg class="" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg> <div class="absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0"><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent; "></div> Copied</div></button></div> <pre class=""><!-- HTML_TAG_START --><span class="hljs-keyword">def</span> <span class="hljs-title function_">transform_features</span>(<span class="hljs-params">self, features: <span class="hljs-built_in">dict</span>[PipelineFeatureType, <span class="hljs-built_in">dict</span>[<span class="hljs-built_in">str</span>, PolicyFeature]]</span>) -> <span class="hljs-built_in">dict</span>[PipelineFeatureType, <span class="hljs-built_in">dict</span>[<span class="hljs-built_in">str</span>, PolicyFeature]]: | |
| <span class="hljs-string">"""Normalization preserves all feature definitions."""</span> | |
| <span class="hljs-keyword">return</span> features <span class="hljs-comment"># No changes to feature structure</span> | |
| <span class="hljs-comment"># ...</span><!-- HTML_TAG_END --></pre></div> <p data-svelte-h="svelte-n4v86e">When your processor renames or reshapes data, implement this method to reflect the mapping for downstream components. For example, a simple rename processor:</p> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg class="" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg> <div class="absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0"><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent; "></div> Copied</div></button></div> <pre class=""><!-- HTML_TAG_START --><span class="hljs-keyword">def</span> <span class="hljs-title function_">transform_features</span>(<span class="hljs-params">self, features: <span class="hljs-built_in">dict</span>[<span class="hljs-built_in">str</span>, PolicyFeature]</span>) -> <span class="hljs-built_in">dict</span>[<span class="hljs-built_in">str</span>, PolicyFeature]: | |
| <span class="hljs-comment"># Simple renaming</span> | |
| <span class="hljs-keyword">if</span> <span class="hljs-string">"pixels"</span> <span class="hljs-keyword">in</span> features: | |
| features[<span class="hljs-string">"observation.image"</span>] = features.pop(<span class="hljs-string">"pixels"</span>) | |
| <span class="hljs-comment"># Pattern-based renaming</span> | |
| <span class="hljs-keyword">for</span> key <span class="hljs-keyword">in</span> <span class="hljs-built_in">list</span>(features.keys()): | |
| <span class="hljs-keyword">if</span> key.startswith(<span class="hljs-string">"env_state."</span>): | |
| suffix = key[<span class="hljs-built_in">len</span>(<span class="hljs-string">"env_state."</span>):] | |
| features[<span class="hljs-string">f"observation.<span class="hljs-subst">{suffix}</span>"</span>] = features.pop(key) | |
| <span class="hljs-comment"># ...</span> | |
| <span class="hljs-keyword">return</span> features<!-- HTML_TAG_END --></pre></div> <p data-svelte-h="svelte-3wif3z"><strong>Key principles:</strong></p> <ul data-svelte-h="svelte-4cbkzr"><li>Use <code>features.pop(old_key)</code> to remove and get the old feature</li> <li>Use <code>features[new_key] = old_feature</code> to add the renamed feature</li> <li>Always return the modified features dictionary</li> <li>Document transformations clearly in the docstring</li></ul> <h3 class="relative group"><a id="using-overrides" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#using-overrides"><span><svg class="" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span></a> <span>Using overrides</span></h3> <p data-svelte-h="svelte-1j2nqgx">You can override step parameters at load-time using <code>overrides</code>. This is handy for non-serializable objects or site-specific settings. It works both in policy factories and with <code>DataProcessorPipeline.from_pretrained(...)</code>.</p> <p data-svelte-h="svelte-1q1vmke"><strong>Foundational model adaptation</strong>: This is particularly useful when working with foundational pretrained policies where you rarely have access to the original training statistics. You can inject your own dataset statistics to adapt the normalizer to your specific robot or environment data.</p> <p data-svelte-h="svelte-4yxneh">Example: during policy evaluation on the robot, override the device and rename map. | |
| Use this to run a policy trained on CUDA on a CPU-only robot, or to remap camera keys when the robot uses different names than the dataset.</p> <p data-svelte-h="svelte-1lufxqo">Direct usage with <code>from_pretrained</code>:</p> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg class="" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg> <div class="absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0"><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent; "></div> Copied</div></button></div> <pre class=""><!-- HTML_TAG_START --><span class="hljs-keyword">from</span> lerobot.processor <span class="hljs-keyword">import</span> RobotProcessorPipeline | |
| <span class="hljs-comment"># Load a foundational policy trained on diverse robot data</span> | |
| <span class="hljs-comment"># but adapt normalization to your specific robot/environment</span> | |
| new_stats = LeRobotDataset(repo_id=<span class="hljs-string">"username/my-dataset"</span>).meta.stats | |
| processor = RobotProcessorPipeline.from_pretrained( | |
| <span class="hljs-string">"huggingface/foundational-robot-policy"</span>, <span class="hljs-comment"># Pretrained foundation model</span> | |
| overrides={ | |
| <span class="hljs-string">"normalizer_processor"</span>: {<span class="hljs-string">"stats"</span>: new_stats}, <span class="hljs-comment"># Inject your robot's statistics</span> | |
| <span class="hljs-string">"device_processor"</span>: {<span class="hljs-string">"device"</span>: <span class="hljs-string">"cuda:0"</span>}, <span class="hljs-comment"># registry name for registered steps</span> | |
| <span class="hljs-string">"rename_processor"</span>: {<span class="hljs-string">"rename_map"</span>: robot_key_map}, <span class="hljs-comment"># Map your robot's observation keys</span> | |
| <span class="hljs-comment"># ...</span> | |
| }, | |
| )<!-- HTML_TAG_END --></pre></div> <h2 class="relative group"><a id="best-practices" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#best-practices"><span><svg class="" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span></a> <span>Best Practices</span></h2> <p data-svelte-h="svelte-a9gap8">Based on analysis of all LeRobot processor implementations, here are the key patterns and practices:</p> <h3 class="relative group"><a id="1-safe-data-handling" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#1-safe-data-handling"><span><svg class="" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span></a> <span>1. Safe Data Handling</span></h3> <p data-svelte-h="svelte-d8shql">Always create copies of input data to avoid unintended side effects. Use <code>transition.copy()</code> and <code>observation.copy()</code> rather than modifying data in-place. This prevents your processor from accidentally affecting other components in the pipeline.</p> <p data-svelte-h="svelte-1tanh7n">Check for required data before processing and handle missing data gracefully. If your processor expects certain keys (like <code>"pixels"</code> for image processing), validate their presence first. For optional data, use safe access patterns like <code>transition.get()</code> and handle <code>None</code> values appropriately.</p> <p data-svelte-h="svelte-11gh8f3">When data validation fails, provide clear, actionable error messages that help users understand what went wrong and how to fix it.</p> <h3 class="relative group"><a id="2-choose-appropriate-base-classes" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#2-choose-appropriate-base-classes"><span><svg class="" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span></a> <span>2. Choose Appropriate Base Classes</span></h3> <p data-svelte-h="svelte-ajlzxq">LeRobot provides specialized base classes that reduce boilerplate code and ensure consistency. Use <code>ObservationProcessorStep</code> when you only need to modify observations, <code>ActionProcessorStep</code> for action-only processing, and <code>RobotActionProcessorStep</code> specifically for dictionary-based robot actions.</p> <p data-svelte-h="svelte-1de5ugl">Only inherit directly from <code>ProcessorStep</code> when you need full control over the entire transition or when processing multiple transition components simultaneously. The specialized base classes handle the transition management for you and provide type safety.</p> <h3 class="relative group"><a id="3-registration-and-naming" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#3-registration-and-naming"><span><svg class="" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span></a> <span>3. Registration and Naming</span></h3> <p data-svelte-h="svelte-14yccwa">Register your processors with descriptive, namespaced names using <code>@ProcessorStepRegistry.register()</code>. Use organization prefixes like <code>"robotics_lab/safety_clipper"</code> or <code>"acme_corp/vision_enhancer"</code> to avoid naming conflicts. Avoid generic names like <code>"processor"</code> or <code>"step"</code> that could clash with other implementations.</p> <p data-svelte-h="svelte-1td2c4">Good registration makes your processors discoverable and enables clean serialization/deserialization when saving and loading pipelines.</p> <h3 class="relative group"><a id="4-state-management-patterns" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#4-state-management-patterns"><span><svg class="" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span></a> <span>4. State Management Patterns</span></h3> <p data-svelte-h="svelte-1xtlp1l">Distinguish between configuration parameters (JSON-serializable values) and internal state (tensors, buffers). Use dataclass fields with <code>init=False, repr=False</code> for internal state that shouldn’t appear in the constructor or string representation.</p> <p data-svelte-h="svelte-1o9ps7u">Implement the <code>reset()</code> method to clear internal state between episodes. This is crucial for stateful processors that accumulate data over time, like moving averages or temporal filters.</p> <p data-svelte-h="svelte-11a1j3g">Remember that <code>get_config()</code> should only return JSON-serializable configuration, while <code>state_dict()</code> handles tensor state separately.</p> <h3 class="relative group"><a id="5-input-validation-and-error-handling" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#5-input-validation-and-error-handling"><span><svg class="" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span></a> <span>5. Input Validation and Error Handling</span></h3> <p data-svelte-h="svelte-gzrs9k">Validate input types and shapes before processing. Check tensor properties like <code>dtype</code> and dimensions to ensure compatibility with your algorithms. For robot actions, verify that required pose components or joint values are present and within expected ranges.</p> <p data-svelte-h="svelte-d41fwr">Use early returns for edge cases where no processing is needed. Provide clear, descriptive error messages that include the expected vs. actual data types or shapes. This makes debugging much easier for users.</p> <h3 class="relative group"><a id="6-device-and-dtype-awareness" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#6-device-and-dtype-awareness"><span><svg class="" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span></a> <span>6. Device and Dtype Awareness</span></h3> <p data-svelte-h="svelte-1kwzte0">Design your processors to automatically adapt to the device and dtype of input tensors. Internal tensors (like normalization statistics) should match the input tensor’s device and dtype to ensure compatibility with multi-GPU training, mixed precision, and distributed setups.</p> <p data-svelte-h="svelte-14re3q4">Implement a <code>to()</code> method that moves your processor’s internal state to the specified device. Check device/dtype compatibility at runtime and automatically migrate internal state when needed. This pattern enables seamless operation across different hardware configurations without manual intervention.</p> <h2 class="relative group"><a id="conclusion" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#conclusion"><span><svg class="" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span></a> <span>Conclusion</span></h2> <p data-svelte-h="svelte-18m2ax2">You now have all the tools to implement custom processors in LeRobot! The key steps are:</p> <ol data-svelte-h="svelte-1b1ldni"><li><strong>Define your processor</strong> as a dataclass with the required methods (<code>__call__</code>, <code>get_config</code>, <code>state_dict</code>, <code>load_state_dict</code>, <code>reset</code>, <code>transform_features</code>)</li> <li><strong>Register it</strong> using <code>@ProcessorStepRegistry.register("name")</code> for discoverability</li> <li><strong>Integrate it</strong> into a <code>DataProcessorPipeline</code> with other processing steps</li> <li><strong>Use base classes</strong> like <code>ObservationProcessorStep</code> when possible to reduce boilerplate</li> <li><strong>Implement device/dtype awareness</strong> to support multi-GPU and mixed precision setups</li></ol> <p data-svelte-h="svelte-w0jjpx">The processor system is designed to be modular and composable, allowing you to build complex data processing pipelines from simple, focused components. Whether you’re preprocessing sensor data for training or post-processing model outputs for robot execution, custom processors give you the flexibility to handle any data transformation your robotics application requires.</p> <p data-svelte-h="svelte-nopmtt">Key principles for robust processors:</p> <ul data-svelte-h="svelte-1o9k3ro"><li><strong>Device/dtype adaptation</strong>: Internal tensors should match input tensors</li> <li><strong>Clear error messages</strong>: Help users understand what went wrong</li> <li><strong>Base class usage</strong>: Leverage specialized base classes to reduce boilerplate</li> <li><strong>Feature contracts</strong>: Declare data structure changes with <code>transform_features()</code></li></ul> <p data-svelte-h="svelte-9erybv">Start simple, test thoroughly, and ensure your processors work seamlessly across different hardware configurations!</p> <a class="!text-gray-400 !no-underline text-sm flex items-center not-prose mt-4" href="https://github.com/huggingface/lerobot/blob/main/docs/source/implement_your_own_processor.mdx" target="_blank"><svg class="mr-1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M31,16l-7,7l-1.41-1.41L28.17,16l-5.58-5.59L24,9l7,7z"></path><path d="M1,16l7-7l1.41,1.41L3.83,16l5.58,5.59L8,23l-7-7z"></path><path d="M12.419,25.484L17.639,6.552l1.932,0.518L14.351,26.002z"></path></svg> <span data-svelte-h="svelte-zjs2n5"><span class="underline">Update</span> on GitHub</span></a> <p></p> | |
| <script> | |
| { | |
| __sveltekit_9kza6s = { | |
| assets: "/docs/lerobot/pr_3313/en", | |
| base: "/docs/lerobot/pr_3313/en", | |
| env: {} | |
| }; | |
| const element = document.currentScript.parentElement; | |
| const data = [null,null]; | |
| Promise.all([ | |
| import("/docs/lerobot/pr_3313/en/_app/immutable/entry/start.d3f1c0f3.js"), | |
| import("/docs/lerobot/pr_3313/en/_app/immutable/entry/app.04bb7687.js") | |
| ]).then(([kit, app]) => { | |
| kit.start(app, element, { | |
| node_ids: [0, 25], | |
| data, | |
| form: null, | |
| error: null | |
| }); | |
| }); | |
| } | |
| </script> | |
Xet Storage Details
- Size:
- 58.1 kB
- Xet hash:
- 555e0a5fe4ebb3fb9c2759c783d875d7102f1fe4912b652d392878a6e02e51df
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.