From 99f5659624545ace3e8a24ad0408ae39776da49d Mon Sep 17 00:00:00 2001 From: Pepijn Kooijmans Date: Tue, 7 Apr 2026 13:38:37 +0200 Subject: [PATCH] docs: update adding_benchmarks for async env changes - Replace add_envs_task reference with env.call("task_description") - Update use_async_envs default to True - Add note about lazy GPU init for AsyncVectorEnv compatibility Made-with: Cursor --- docs/source/adding_benchmarks.mdx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/source/adding_benchmarks.mdx b/docs/source/adding_benchmarks.mdx index 73a951276..77ccd3d4a 100644 --- a/docs/source/adding_benchmarks.mdx +++ b/docs/source/adding_benchmarks.mdx @@ -26,7 +26,7 @@ During evaluation, data moves through four stages: 1. gym.Env ──→ raw observations (numpy dicts) 2. Preprocessing ──→ standard LeRobot keys + task description - (preprocess_observation, add_envs_task in envs/utils.py) + (preprocess_observation in envs/utils.py, env.call("task_description")) 3. Processors ──→ env-specific then policy-specific transforms (env_preprocessor, policy_preprocessor) @@ -161,6 +161,8 @@ class MyBenchmarkEnv(gym.Env): ... ``` +**GPU-based simulators (e.g. MuJoCo with EGL rendering):** If your simulator allocates GPU/EGL contexts during `__init__`, defer that allocation to a `_ensure_env()` helper called on first `reset()`/`step()`. This avoids inheriting stale GPU handles when `AsyncVectorEnv` spawns worker processes. See `LiberoEnv._ensure_env()` for the pattern. + Also provide a factory function that returns the nested dict structure: ```python @@ -207,7 +209,7 @@ class MyBenchmarkEnvConfig(EnvConfig): def gym_kwargs(self) -> dict: return {"obs_type": self.obs_type, "render_mode": self.render_mode} - def create_envs(self, n_envs: int, use_async_envs: bool = False): + def create_envs(self, n_envs: int, use_async_envs: bool = True): """Override for multi-task benchmarks or custom env creation.""" from lerobot.envs. import create__envs return create__envs(task=self.task, n_envs=n_envs, ...)