| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| """ |
| Standalone inference smoke tests. |
| |
| Loads Gr00tPolicy and LeRobotEpisodeLoader once per embodiment variant (module-scoped |
| fixture), then calls the internal Python functions directly — no subprocess overhead. |
| |
| Variants exercised: LIBERO, DROID, SimplerEnv-Fractal, SimplerEnv-Bridge. |
| |
| Environment variables (optional, per-embodiment): |
| INFERENCE_TEST_LIBERO_MODEL_PATH – LIBERO checkpoint path override |
| INFERENCE_TEST_LIBERO_DATASET_PATH – LIBERO dataset path override |
| INFERENCE_TEST_DROID_MODEL_PATH – DROID checkpoint path override |
| INFERENCE_TEST_DROID_DATASET_PATH – DROID dataset path override |
| INFERENCE_TEST_SIMPLERENV_FRACTAL_MODEL_PATH – SimplerEnv-Fractal model override |
| INFERENCE_TEST_SIMPLERENV_FRACTAL_DATASET_PATH – SimplerEnv-Fractal dataset override |
| INFERENCE_TEST_SIMPLERENV_BRIDGE_MODEL_PATH – SimplerEnv-Bridge model override |
| INFERENCE_TEST_SIMPLERENV_BRIDGE_DATASET_PATH – SimplerEnv-Bridge dataset override |
| """ |
|
|
| from __future__ import annotations |
|
|
| from dataclasses import dataclass |
| import sys |
|
|
| from gr00t.data.dataset.lerobot_episode_loader import LeRobotEpisodeLoader |
| from gr00t.data.embodiment_tags import EmbodimentTag |
| from gr00t.eval.open_loop_eval import evaluate_single_trajectory |
| from gr00t.policy.gr00t_policy import Gr00tPolicy |
| import pytest |
| from test_support.runtime import get_root, resolve_demo_dataset, resolve_model_checkpoint_path |
| import torch |
|
|
|
|
| ROOT = get_root() |
|
|
| |
| |
| _DEPLOY_DIR = str(ROOT / "scripts" / "deployment") |
| if _DEPLOY_DIR not in sys.path: |
| sys.path.insert(0, _DEPLOY_DIR) |
|
|
| from standalone_inference_script import run_single_trajectory |
|
|
|
|
| @dataclass(frozen=True) |
| class InferenceVariant: |
| """Configuration for one embodiment variant of the inference smoke tests.""" |
|
|
| id: str |
| embodiment_tag: str |
| hf_repo_id: str |
| hf_subdir: str | None |
| dataset_name: str |
| model_env_var: str = "" |
| dataset_env_var: str = "" |
|
|
| def __str__(self) -> str: |
| return self.id |
|
|
|
|
| LIBERO = InferenceVariant( |
| id="libero", |
| embodiment_tag="LIBERO_PANDA", |
| hf_repo_id="nvidia/GR00T-N1.7-LIBERO", |
| hf_subdir="libero_10", |
| dataset_name="libero_demo", |
| model_env_var="INFERENCE_TEST_LIBERO_MODEL_PATH", |
| dataset_env_var="INFERENCE_TEST_LIBERO_DATASET_PATH", |
| ) |
|
|
| DROID = InferenceVariant( |
| id="droid", |
| embodiment_tag="OXE_DROID_RELATIVE_EEF_RELATIVE_JOINT", |
| hf_repo_id="nvidia/GR00T-N1.7-DROID", |
| hf_subdir=None, |
| dataset_name="droid_sample", |
| model_env_var="INFERENCE_TEST_DROID_MODEL_PATH", |
| dataset_env_var="INFERENCE_TEST_DROID_DATASET_PATH", |
| ) |
|
|
| SIMPLERENV_FRACTAL = InferenceVariant( |
| id="simplerenv_fractal", |
| embodiment_tag="SIMPLER_ENV_GOOGLE", |
| hf_repo_id="nvidia/GR00T-N1.7-SimplerEnv-Fractal", |
| hf_subdir=None, |
| dataset_name="simplerenv_fractal_sample", |
| model_env_var="INFERENCE_TEST_SIMPLERENV_FRACTAL_MODEL_PATH", |
| dataset_env_var="INFERENCE_TEST_SIMPLERENV_FRACTAL_DATASET_PATH", |
| ) |
|
|
| SIMPLERENV_BRIDGE = InferenceVariant( |
| id="simplerenv_bridge", |
| embodiment_tag="SIMPLER_ENV_WIDOWX", |
| hf_repo_id="nvidia/GR00T-N1.7-SimplerEnv-Bridge", |
| hf_subdir=None, |
| dataset_name="simplerenv_bridge_sample", |
| model_env_var="INFERENCE_TEST_SIMPLERENV_BRIDGE_MODEL_PATH", |
| dataset_env_var="INFERENCE_TEST_SIMPLERENV_BRIDGE_DATASET_PATH", |
| ) |
|
|
| VARIANTS = [LIBERO, DROID, SIMPLERENV_FRACTAL, SIMPLERENV_BRIDGE] |
|
|
|
|
| def _model_path(variant: InferenceVariant) -> str: |
| return str( |
| resolve_model_checkpoint_path( |
| hf_repo_id=variant.hf_repo_id, |
| hf_subdir=variant.hf_subdir, |
| path_override_env=variant.model_env_var, |
| repo_root=ROOT, |
| ) |
| ) |
|
|
|
|
| def _dataset_path(variant: InferenceVariant) -> str: |
| return str( |
| resolve_demo_dataset( |
| dataset_name=variant.dataset_name, |
| path_override_env=variant.dataset_env_var, |
| repo_root=ROOT, |
| ) |
| ) |
|
|
|
|
| @dataclass |
| class LoadedVariant: |
| """Holds the pre-loaded policy and dataset loader for one variant.""" |
|
|
| variant: InferenceVariant |
| policy: Gr00tPolicy |
| loader: LeRobotEpisodeLoader |
| embodiment_tag: EmbodimentTag |
| model_path: str |
| dataset_path: str |
|
|
|
|
| @pytest.fixture(scope="module", params=VARIANTS, ids=str) |
| def loaded_variant(request): |
| """Load Gr00tPolicy + LeRobotEpisodeLoader once per variant for the whole module.""" |
| variant: InferenceVariant = request.param |
| model_path = _model_path(variant) |
| dataset_path = _dataset_path(variant) |
| embodiment_tag = EmbodimentTag.resolve(variant.embodiment_tag) |
| device = "cuda" if torch.cuda.is_available() else "cpu" |
|
|
| policy = Gr00tPolicy( |
| embodiment_tag=embodiment_tag, |
| model_path=model_path, |
| device=device, |
| ) |
|
|
| modality = policy.get_modality_config() |
|
|
| loader = LeRobotEpisodeLoader( |
| dataset_path=dataset_path, |
| modality_configs=modality, |
| video_backend="torchcodec", |
| video_backend_kwargs=None, |
| ) |
|
|
| yield LoadedVariant( |
| variant=variant, |
| policy=policy, |
| loader=loader, |
| embodiment_tag=embodiment_tag, |
| model_path=model_path, |
| dataset_path=dataset_path, |
| ) |
|
|
|
|
| |
| |
| |
|
|
|
|
| @pytest.mark.gpu |
| @pytest.mark.timeout(600) |
| def test_standalone_inference_pytorch(loaded_variant: LoadedVariant) -> None: |
| """Run standalone inference in PyTorch mode for a few steps on trajectory 0.""" |
| v = loaded_variant |
| run_single_trajectory( |
| policy=v.policy, |
| loader=v.loader, |
| traj_id=0, |
| embodiment_tag=v.embodiment_tag, |
| steps=20, |
| action_horizon=8, |
| ) |
|
|
|
|
| @pytest.mark.gpu |
| @pytest.mark.timeout(600) |
| def test_standalone_inference_invalid_traj_id(loaded_variant: LoadedVariant) -> None: |
| """Out-of-range traj_id should raise an index error, not UnboundLocalError.""" |
| v = loaded_variant |
| n = len(v.loader) |
| assert n < 999, f"Expected dataset to have fewer than 999 trajectories, got {n}" |
| with pytest.raises((IndexError, KeyError)): |
| v.loader[999] |
|
|
|
|
| @pytest.mark.gpu |
| @pytest.mark.timeout(600) |
| def test_open_loop_eval_with_checkpoint(loaded_variant: LoadedVariant) -> None: |
| """Run evaluate_single_trajectory from open_loop_eval directly.""" |
| v = loaded_variant |
| evaluate_single_trajectory( |
| policy=v.policy, |
| loader=v.loader, |
| traj_id=0, |
| embodiment_tag=v.embodiment_tag, |
| steps=5, |
| action_horizon=8, |
| ) |
|
|