diff --git a/docs/source/g05.mdx b/docs/source/g05.mdx index acb97036e..5be58aaf3 100644 --- a/docs/source/g05.mdx +++ b/docs/source/g05.mdx @@ -126,3 +126,33 @@ This command still requires licensed checkpoint access and suitable CUDA hardwar A 50-episode LIBERO/RoboTwin success-rate comparison additionally requires the matching simulator, task assets, reset seeds, and author evaluator; no task-level benchmark number is claimed until that separate gate runs. + +Once the pinned LIBERO simulator and assets are installed, run the matching +LeRobot rollout with the author camera names and relative control: + +```bash +lerobot-eval \ + --policy.path=outputs/g05-libero-lerobot \ + --policy.device=cuda \ + --env.type=libero \ + --env.task=libero_goal \ + --env.control_mode=relative \ + --env.observation_height=512 \ + --env.observation_width=512 \ + '--env.camera_name_mapping={"agentview_image": "image", "robot0_eye_in_hand_image": "wrist_image"}' \ + --eval.batch_size=1 \ + --eval.n_episodes=50 \ + --seed=0 \ + --output_dir=outputs/g05-libero-lerobot-eval +``` + +The author-oracle command for the same 50-trial gate is: + +```bash +LIBERO_CONFIG_PATH=$(pwd)/experiments/libero \ +bash scripts/run/eval_libero.sh checkpoints/g05-libero/model.pt \ + --suites "libero_goal" \ + --num_trials 50 \ + --num_parallel 1 \ + --output_dir outputs/g05-libero-author-eval +``` diff --git a/src/lerobot/policies/g05/processor_g05.py b/src/lerobot/policies/g05/processor_g05.py index f6d1158d1..afca04f0e 100644 --- a/src/lerobot/policies/g05/processor_g05.py +++ b/src/lerobot/policies/g05/processor_g05.py @@ -153,6 +153,10 @@ class G05EmbodimentProjectionStep(ProcessorStep): ) if OBS_STATE in observation: raw_state = observation[OBS_STATE] + if self.embodiment == "libero" and raw_state.shape[-1] == 8: + # LeRobot's generic LIBERO env exposes both parallel-jaw qpos + # values. The author evaluator consumes only qpos[0]. + raw_state = torch.cat((raw_state[..., :6], raw_state[..., 6:7]), dim=-1) observation[OBS_STATE] = self._project(raw_state, self.mapping["state"], self.policy_state_dim) state_mask = torch.ones( *raw_state.shape[:-1], diff --git a/tests/policies/g05/test_g05.py b/tests/policies/g05/test_g05.py index 113bfe126..c8028f471 100644 --- a/tests/policies/g05/test_g05.py +++ b/tests/policies/g05/test_g05.py @@ -181,6 +181,24 @@ def test_inference_without_ground_truth_action_still_emits_action_dimension_mask assert processed["action_dim_is_pad"].sum() == 13 +def test_lerobot_libero_two_finger_state_matches_author_first_qpos_contract(): + config = _config() + preprocessor, _ = make_pre_post_processors(config) + env_state = torch.arange(8, dtype=torch.float32) + + processed = preprocessor( + { + OBS_STATE: env_state, + "observation.images.image": torch.zeros(3, 8, 8), + "observation.images.wrist_image": torch.zeros(3, 8, 8), + "task": "libero env", + } + ) + + checkpoint_slots = G05_EMBODIMENT_MAPPINGS["libero"]["state"] + assert torch.equal(processed[OBS_STATE][0, list(checkpoint_slots)], env_state[:7]) + + def test_atomic4_projection_has_mobile_base_control_mode_and_exact_inverse(): config = G05Config( checkpoint_profile="custom",