From b61f39d69ff1ce9b2ef2254bc1b6dade36e538e1 Mon Sep 17 00:00:00 2001 From: Pepijn Date: Tue, 14 Apr 2026 16:57:39 +0200 Subject: [PATCH] fix(libero): use suite's perturbation-aware init_states loader MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LIBERO-plus's Benchmark class exposes a `get_task_init_states(i)` method that strips perturbation suffixes (`_table_N`, `_tb_N`, `_view_`, `_language_`, `_light_`, `_add_`, `_level`) and loads the underlying base `.pruned_init` file — the on-disk name for a perturbation variant doesn't exist as a file, only the base does. lerobot's loader was bypassing that logic and trying to read the suffix-bearing filename directly, which failed for every non-zero task id and killed the eval before any rollout video could be written. Delegate to the suite's method when it exists; fall back to the path-based loader for vanilla LIBERO (which does not provide the method). Also drop the hf-libero install + init_files copy from the LIBERO-plus Dockerfile — the LIBERO-plus clone already ships both `bddl_files/` and `init_files/` for all five suites, so the copy was unnecessary and the `cp -r` into an existing dir produced a confusing nested layout. Co-Authored-By: Claude Opus 4.6 (1M context) --- docker/Dockerfile.benchmark.libero_plus | 16 ++++------------ src/lerobot/envs/libero.py | 6 ++++++ 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/docker/Dockerfile.benchmark.libero_plus b/docker/Dockerfile.benchmark.libero_plus index 12af9a7bc..a3bad9e35 100644 --- a/docker/Dockerfile.benchmark.libero_plus +++ b/docker/Dockerfile.benchmark.libero_plus @@ -92,18 +92,10 @@ ENV PYTHONPATH="/home/user_lerobot/libero-plus:${PYTHONPATH}" # LIBERO-plus installs with a nested package structure, so find_spec('libero') # may return a namespace package without .origin. Use glob to locate bddl_files. ENV LIBERO_PLUS_ROOT=/home/user_lerobot/libero-plus/libero/libero -# Find hf-libero's init_files in site-packages (shallow clone doesn't have them). -# Copy them into the PYTHONPATH clone so both bddl_files (from clone) and -# init_files (from pip) are in the same tree. -RUN uv pip install --no-cache --no-deps "hf-libero>=0.1.3,<0.2.0" -RUN HF_LIBERO=$(uv pip show hf-libero 2>/dev/null | grep Location | awk '{print $2}') && \ - if [ -d "${HF_LIBERO}/libero/libero/init_files" ]; then \ - cp -r "${HF_LIBERO}/libero/libero/init_files" ${LIBERO_PLUS_ROOT}/init_files; \ - fi && \ - # Uninstall hf-libero so that Python imports LIBERO-plus (from PYTHONPATH) - # instead of vanilla hf-libero — LIBERO-plus has 2400+ perturbation tasks per - # suite, vanilla has only 10. - uv pip uninstall hf-libero 2>/dev/null || true +# LIBERO-plus's clone already ships both bddl_files/ and init_files/ with base +# `.pruned_init` files for all 5 suites. Its Benchmark.get_task_init_states() +# strips perturbation suffixes (_table_N, _tb_N, _view_, _language_, _light_) +# back to the base filename, so no extra init files are needed. RUN mkdir -p /home/user_lerobot/.libero && \ python${PYTHON_VERSION} -c "\ from huggingface_hub import snapshot_download; \ diff --git a/src/lerobot/envs/libero.py b/src/lerobot/envs/libero.py index ec90d0ffd..bdc9c3760 100644 --- a/src/lerobot/envs/libero.py +++ b/src/lerobot/envs/libero.py @@ -70,6 +70,12 @@ def _select_task_ids(total_tasks: int, task_ids: Iterable[int] | None) -> list[i def get_task_init_states(task_suite: Any, i: int) -> np.ndarray: + # LIBERO-plus's Benchmark exposes a suffix-aware loader that maps perturbation + # variants (_table_N, _tb_N, _view_, _language_, _light_, _add_, _level) back to + # the base init_states file. Vanilla LIBERO has no such method — fall through. + suite_loader = getattr(task_suite, "get_task_init_states", None) + if callable(suite_loader): + return suite_loader(i) init_states_path = ( Path(get_libero_path("init_states")) / task_suite.tasks[i].problem_folder