# Copyright 2025 The HuggingFace Inc. team. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Isolated benchmark image for LIBERO-plus integration tests. # Installs only lerobot[libero_plus] (LIBERO-plus from GitHub, dm-control, mujoco). # # Build: docker build -f docker/Dockerfile.benchmark.libero_plus -t lerobot-benchmark-libero-plus . # Run: docker run --gpus all --rm lerobot-benchmark-libero-plus lerobot-eval ... ARG CUDA_VERSION=12.4.1 ARG OS_VERSION=22.04 FROM nvidia/cuda:${CUDA_VERSION}-base-ubuntu${OS_VERSION} ARG PYTHON_VERSION=3.12 ENV DEBIAN_FRONTEND=noninteractive \ MUJOCO_GL=egl \ PATH=/lerobot/.venv/bin:$PATH \ CUDA_VISIBLE_DEVICES=0 \ DEVICE=cuda # System deps — same set as Dockerfile.internal plus LIBERO-plus extras RUN apt-get update && apt-get install -y --no-install-recommends \ software-properties-common build-essential git curl \ libglib2.0-0 libgl1-mesa-glx libegl1-mesa ffmpeg \ libusb-1.0-0-dev speech-dispatcher libgeos-dev portaudio19-dev \ cmake pkg-config ninja-build \ libexpat1 libfontconfig1-dev libmagickwand-dev \ && add-apt-repository -y ppa:deadsnakes/ppa \ && apt-get update \ && apt-get install -y --no-install-recommends \ python${PYTHON_VERSION} \ python${PYTHON_VERSION}-venv \ python${PYTHON_VERSION}-dev \ && curl -LsSf https://astral.sh/uv/0.8.0/install.sh | sh \ && mv /root/.local/bin/uv /usr/local/bin/uv \ && useradd --create-home --shell /bin/bash user_lerobot \ && usermod -aG sudo user_lerobot \ && apt-get clean && rm -rf /var/lib/apt/lists/* WORKDIR /lerobot RUN chown -R user_lerobot:user_lerobot /lerobot USER user_lerobot ENV HOME=/home/user_lerobot \ HF_HOME=/home/user_lerobot/.cache/huggingface \ HF_LEROBOT_HOME=/home/user_lerobot/.cache/huggingface/lerobot \ TORCH_HOME=/home/user_lerobot/.cache/torch \ TRITON_CACHE_DIR=/home/user_lerobot/.cache/triton RUN uv venv --python python${PYTHON_VERSION} # Install only lerobot[libero_plus] — isolated from hf-libero and metaworld dep trees COPY --chown=user_lerobot:user_lerobot setup.py pyproject.toml uv.lock README.md MANIFEST.in ./ COPY --chown=user_lerobot:user_lerobot src/ src/ # Use uv pip install (not uv sync) — uv sync resolves all extras across all # Python versions, hitting cross-extra numpy conflicts. pip-style install # only resolves the requested extras for the current platform. # Install lerobot with libero_plus and smolvla extras. # The libero git dep sometimes gets silently skipped by uv pip install # when embedded in self-referential extras, so install it explicitly too. # Step 1: install lerobot with extras (libero git dep may be silently skipped) RUN uv pip install --no-cache -e ".[libero_plus,smolvla]" # Step 2: LIBERO-plus has a nested libero/libero/ structure that neither uv pip # install from git nor editable installs handle correctly (metadata-only install). # Clone and add to PYTHONPATH as the only reliable way to make it importable. RUN git clone --depth=1 https://github.com/sylvestf/LIBERO-plus.git /home/user_lerobot/libero-plus \ && mkdir -p /home/user_lerobot/.libero \ && echo 'assets: /tmp' > /home/user_lerobot/.libero/config.yaml # Install LIBERO-plus deps (robosuite, bddl, easydict, mujoco, etc.) from setup.py. # Pin robosuite==1.4.1 (fork uses single_arm_env removed in v1.5+), then install # the remaining deps from the clone. --no-build-isolation avoids rebuilding lerobot. RUN uv pip install --no-cache "robosuite==1.4.1" bddl easydict mujoco matplotlib wand scikit-image gym \ && cd /home/user_lerobot/libero-plus && uv pip install --no-cache --no-deps -e "." ENV PYTHONPATH="/home/user_lerobot/libero-plus:${PYTHONPATH}" # Pre-download libero assets so nothing is fetched at runtime (CI timeout risk). # libero/libero/__init__.py prompts with input() when ~/.libero/config.yaml is # missing; write the config first so any import is non-interactive. # 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 RUN mkdir -p /home/user_lerobot/.libero && \ python${PYTHON_VERSION} -c "\ from huggingface_hub import snapshot_download; \ snapshot_download(repo_id='lerobot/libero-assets', repo_type='dataset', \ local_dir='/home/user_lerobot/.libero/assets')" && \ printf "assets: /home/user_lerobot/.libero/assets\nbddl_files: ${LIBERO_PLUS_ROOT}/bddl_files\ndatasets: ${LIBERO_PLUS_ROOT}/../datasets\ninit_states: ${LIBERO_PLUS_ROOT}/init_files\n" \ > /home/user_lerobot/.libero/config.yaml RUN chmod +x /lerobot/.venv/lib/python${PYTHON_VERSION}/site-packages/triton/backends/nvidia/bin/ptxas COPY --chown=user_lerobot:user_lerobot . . CMD ["/bin/bash"]