Skip to content

Commit 7eda023

Browse files
committed
Address review: lean on base PolicyRunnerTask, align with pi0
- Slim Gr00tPolicyRunnerTask to just its policy args + gr00t-specific flags; rely on the base for the run script, outputs, task name, and image (drops the out-of-scope image override and the wait-for-server preamble for now). - Align Gr00tServerTask with pi0_server_task: inline task name, drop the wait-for-server helper, and fold model/embodiment/port into constants. - Centralize the policy-server port in workflow_constants (POLICY_SERVER_PORT = 8000) and use it for both the GR00T and pi0 remote tasks. - Reverse the workflow task order to match the pi0 workflow. Signed-off-by: alex <amillane@nvidia.com>
1 parent 2f63fa2 commit 7eda023

5 files changed

Lines changed: 28 additions & 125 deletions

File tree

osmo/tasks/gr00t_policy_runner_task.py

Lines changed: 13 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -3,114 +3,52 @@
33
#
44
# SPDX-License-Identifier: Apache-2.0
55

6-
"""GR00T policy-runner task for the Isaac Lab Arena OSMO workflow.
7-
8-
Runs ``policy_runner.py`` with the GR00T remote closed-loop policy against the
9-
GR00T server that shares its OSMO group. Mirrors the eval side of the
10-
``test_gr00t_closedloop_e2e`` CI job in ``.github/workflows/ci.yml``.
11-
"""
6+
"""GR00T policy-runner task for the Isaac Lab Arena OSMO workflow."""
127

138
import argparse
14-
from typing import Any
15-
16-
from tasks.gr00t_server_task import GR00T_SERVER_HOST_TOKEN, get_wait_for_server_script
17-
from tasks.policy_runner_task import POLICY_RUNNER_COMMAND, PolicyRunnerTask
18-
from workflows.workflow_constants import EVAL_OUTPUT_SWIFT_URL, OSMO_TASK_OUTPUT_DIR
199

20-
# Arena image name
21-
DEFAULT_IMAGE = "nvcr.io/nvstaging/isaac-amr/isaaclab_arena:latest"
10+
from tasks.policy_runner_task import PolicyRunnerTask
11+
from workflows.workflow_constants import POLICY_SERVER_PORT
2212

23-
# GR00T remote closed-loop policy and the policy closed-loop config.
24-
GR00T_POLICY_TYPE = "isaaclab_arena_gr00t.policy.gr00t_remote_closedloop_policy.Gr00tRemoteClosedloopPolicy"
2513
DEFAULT_POLICY_CONFIG = "isaaclab_arena_gr00t/policy/config/droid_manip_gr00t_closedloop_config.yaml"
2614

27-
DEFAULT_POLICY_RUNNER_ARGS = "--num_episodes 2 --headless --enable_cameras --num_envs 4 --record_camera_video"
28-
2915

3016
class Gr00tPolicyRunnerTask(PolicyRunnerTask):
3117
"""OSMO task that evaluates the GR00T remote policy via a connection to the GR00T server."""
3218

3319
def __init__(
3420
self,
35-
workflow_args: Any,
36-
task_args: Any,
37-
image: str = DEFAULT_IMAGE,
21+
workflow_args: argparse.Namespace,
22+
task_args: argparse.Namespace,
3823
lead: bool | None = None,
3924
) -> None:
40-
super().__init__(workflow_args, task_args, image=image, lead=lead)
41-
self.image = getattr(task_args, "arena_image", image)
25+
super().__init__(workflow_args=workflow_args, task_args=task_args, lead=lead)
4226
self.policy_config_yaml_path = task_args.policy_config_yaml_path
43-
44-
# Tasks in an OSMO group each get their own IP (no shared loopback), so the server is reached
45-
# via the {{host:<task-name>}} token, which OSMO resolves to the server task's IP at runtime.
4627
self.remote_host = task_args.remote_host
47-
self.remote_port = task_args.server_port
4828

4929
@staticmethod
5030
def add_task_arguments(parser: argparse.ArgumentParser) -> None:
31+
PolicyRunnerTask.add_task_arguments(parser)
5132
group = parser.add_argument_group("gr00t policy runner")
52-
group.add_argument("--arena_image", default=DEFAULT_IMAGE, help="Override the Arena dev image")
5333
group.add_argument(
5434
"--policy_config_yaml_path", default=DEFAULT_POLICY_CONFIG, help="GR00T closed-loop config YAML"
5535
)
56-
group.add_argument(
57-
"--arena_env_args",
58-
required=True,
59-
help=(
60-
"Arena example-environment name plus its env-related arguments, "
61-
"e.g. 'kitchen_pick_and_place --object cracker_box'"
62-
),
63-
)
36+
# Tasks in an OSMO group each get their own IP, so the server is reached via the
37+
# {{host:<task-name>}} token, which OSMO resolves to the server task's IP at runtime.
6438
group.add_argument(
6539
"--remote_host",
66-
default=GR00T_SERVER_HOST_TOKEN,
67-
help="GR00T server host (defaults to the {{host:gr00t_server}}) name",
40+
default="{{host:gr00t_server}}",
41+
help="GR00T server host (defaults to {{host:gr00t_server}})",
6842
)
69-
group.add_argument(
70-
"--policy_runner_args",
71-
default=DEFAULT_POLICY_RUNNER_ARGS,
72-
help=(
73-
"Policy-runner related arguments, e.g. '--num_episodes, --headless, --enable_cameras, --num_envs,"
74-
" --record_camera_video'"
75-
),
76-
)
77-
78-
@staticmethod
79-
def get_task_name() -> str:
80-
return "gr00t_policy_runner"
81-
82-
def _get_outputs(self) -> list[dict[str, Any]]:
83-
# Evaluation outputs (videos, per-episode results, report) are uploaded per run.
84-
return [{"url": EVAL_OUTPUT_SWIFT_URL}]
8543

8644
def _get_policy_args(self) -> list[str]:
8745
return [
8846
"--policy_type",
89-
GR00T_POLICY_TYPE,
47+
"isaaclab_arena_gr00t.policy.gr00t_remote_closedloop_policy.Gr00tRemoteClosedloopPolicy",
9048
"--policy_config_yaml_path",
9149
self.policy_config_yaml_path,
9250
"--remote_host",
9351
self.remote_host,
9452
"--remote_port",
95-
str(self.remote_port),
53+
str(POLICY_SERVER_PORT),
9654
]
97-
98-
def _get_run_script(self) -> str:
99-
# Override the base runner: block on the GR00T server coming up before launching the eval.
100-
policy_args_str = " ".join(self._get_policy_args())
101-
return (
102-
"set -euxo pipefail\n"
103-
"ldconfig\n"
104-
"nvidia-smi\n"
105-
"cd /workspaces/isaaclab_arena\n"
106-
"[ -e submodules/IsaacLab/_isaac_sim ] || ln -s /isaac-sim/ submodules/IsaacLab/_isaac_sim\n"
107-
"\n"
108-
f"{get_wait_for_server_script(self.remote_host, self.remote_port)}"
109-
"\n"
110-
f"{POLICY_RUNNER_COMMAND} "
111-
f"{policy_args_str} "
112-
# Write evaluation outputs to the OSMO task output mount (uploaded to EVAL_OUTPUT_SWIFT_URL).
113-
f"--output_base_dir {OSMO_TASK_OUTPUT_DIR} "
114-
f"{self.policy_runner_args} "
115-
f"{self.arena_env_args}\n"
116-
)

osmo/tasks/gr00t_server_task.py

Lines changed: 9 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -5,39 +5,17 @@
55

66
"""GR00T inference-server task for OSMO eval workflows, used by the GR00T policy-runner task."""
77

8-
import argparse
98
from typing import Any
109

1110
from tasks.base_task import BaseTask
11+
from workflows.workflow_constants import POLICY_SERVER_PORT
1212

1313
# GR00T server image (containing the droid checkpoints).
1414
DEFAULT_IMAGE = "nvcr.io/nvstaging/isaac-amr/gr00t_1_6_droid"
1515
# Droid checkpoint baked into the GR00T server image.
16-
DEFAULT_MODEL_PATH = "/workspace/pretrained_ckpts/GR00T-N1.6-DROID"
16+
MODEL_PATH = "/workspace/pretrained_ckpts/GR00T-N1.6-DROID"
1717
# Embodiment tag for the droid manipulation config (see droid_manip_gr00t_closedloop_config.yaml).
18-
DEFAULT_EMBODIMENT_TAG = "OXE_DROID"
19-
DEFAULT_SERVER_PORT = 5555
20-
21-
# OSMO task name for the server. The eval runner reaches it via the {{host:<name>}} token,
22-
# which OSMO resolves to the runtime IP.
23-
GR00T_SERVER_TASK_NAME = "gr00t_server"
24-
GR00T_SERVER_HOST_TOKEN = "{{host:" + GR00T_SERVER_TASK_NAME + "}}"
25-
26-
# Run in the Arena eval image (not the server image): polls the server until it accepts requests.
27-
WAIT_FOR_SERVER_COMMAND = "/isaac-sim/python.sh -u -m isaaclab_arena_gr00t.utils.wait_for_gr00t_server"
28-
29-
30-
def get_wait_for_server_script(host: str, port: int) -> str:
31-
"""Return the bash snippet that blocks until the GR00T server accepts requests."""
32-
return (
33-
"# Wait for the GR00T server task to come up before starting the eval.\n"
34-
f"{WAIT_FOR_SERVER_COMMAND} \\\n"
35-
f" --host {host} \\\n"
36-
f" --port {port} \\\n"
37-
" --timeout-sec 1200 \\\n"
38-
" --poll-interval-sec 15 \\\n"
39-
" --request-timeout-ms 5000\n"
40-
)
18+
EMBODIMENT_TAG = "OXE_DROID"
4119

4220

4321
class Gr00tServerTask(BaseTask):
@@ -51,27 +29,14 @@ def __init__(
5129
lead: bool | None = None,
5230
) -> None:
5331
super().__init__(workflow_args=workflow_args, task_args=task_args, lead=lead)
54-
self.docker_image = getattr(task_args, "gr00t_server_image", image)
55-
self.model_path = task_args.gr00t_model_path
56-
self.embodiment_tag = task_args.gr00t_embodiment_tag
57-
self.server_port = task_args.server_port
58-
59-
@staticmethod
60-
def add_task_arguments(parser: argparse.ArgumentParser) -> None:
61-
group = parser.add_argument_group("gr00t server")
62-
group.add_argument("--gr00t_server_image", default=DEFAULT_IMAGE, help="Override the GR00T server image")
63-
group.add_argument("--gr00t_model_path", default=DEFAULT_MODEL_PATH, help="Model path for the GR00T policy")
64-
group.add_argument(
65-
"--gr00t_embodiment_tag", default=DEFAULT_EMBODIMENT_TAG, help="Embodiment tag for the GR00T policy"
66-
)
67-
group.add_argument("--server_port", type=int, default=DEFAULT_SERVER_PORT, help="GR00T server port")
32+
self.image = image
6833

6934
@staticmethod
7035
def get_task_name() -> str:
71-
return GR00T_SERVER_TASK_NAME
36+
return "gr00t_server"
7237

7338
def _get_image(self) -> str:
74-
return self.docker_image
39+
return self.image
7540

7641
def _get_inputs(self) -> list[dict[str, Any]]:
7742
return []
@@ -85,8 +50,8 @@ def _get_run_script(self) -> str:
8550
"nvidia-smi\n"
8651
"cd /workspace\n"
8752
"exec uv run python gr00t/eval/run_gr00t_server.py \\\n"
88-
f" --model_path={self.model_path} \\\n"
89-
f" --embodiment_tag={self.embodiment_tag} \\\n"
53+
f" --model_path={MODEL_PATH} \\\n"
54+
f" --embodiment_tag={EMBODIMENT_TAG} \\\n"
9055
" --host=0.0.0.0 \\\n"
91-
f" --port={self.server_port}\n"
56+
f" --port={POLICY_SERVER_PORT}\n"
9257
)

osmo/tasks/pi0_remote_policy_runner_task.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"""Remote pi0 policy-runner task for the Isaac Lab Arena OSMO workflow."""
77

88
from tasks.policy_runner_task import PolicyRunnerTask
9+
from workflows.workflow_constants import POLICY_SERVER_PORT
910

1011

1112
class Pi0RemotePolicyRunnerTask(PolicyRunnerTask):
@@ -18,7 +19,7 @@ def _get_policy_args(self) -> list[str]:
1819
"--remote_host",
1920
"{{host:policy_server}}",
2021
"--remote_port",
21-
"8000",
22+
str(POLICY_SERVER_PORT),
2223
# Raised from the default: on OSMO the first inference timed out while the
2324
# server was still compiling kernels, which dropped the connection.
2425
"--ping_timeout",

osmo/workflows/gr00t_policy_runner_workflow.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,6 @@
2020
class Gr00tPolicyRunnerWorkflow(Workflow):
2121
"""Two-task workflow: a GR00T server plus the lead policy-runner eval task."""
2222

23-
task_cls_list = [Gr00tServerTask, Gr00tPolicyRunnerTask]
2423
# The policy runner is the lead: it drives completion and the server runs until the lead finishes.
25-
lead_list = [False, True]
24+
task_cls_list = [Gr00tPolicyRunnerTask, Gr00tServerTask]
25+
lead_list = [True, False]

osmo/workflows/workflow_constants.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,5 @@
2020
DATASET_HTTPS_URL = f"{HTTPS_URL_PREFIX}/{DATASETS_PATH}/{{{{workflow_id}}}}"
2121
DATASET_SWIFT_URL = f"{SWIFT_URL_PREFIX}/{DATASETS_PATH}/{{{{workflow_id}}}}"
2222

23-
# Evaluation output dataset, written per run under the existing isaaclab_arena container.
24-
EVAL_OUTPUT_PATH = "AUTH_team-isaac/isaaclab_arena/datasets"
25-
EVAL_OUTPUT_SWIFT_URL = f"{SWIFT_URL_PREFIX}/{EVAL_OUTPUT_PATH}/{{{{workflow_id}}}}"
23+
# Port a policy server binds to and its remote policy-runner client connects to.
24+
POLICY_SERVER_PORT = 8000

0 commit comments

Comments
 (0)