Skip to content

Commit 15de4dd

Browse files
committed
[Feature] mujoco_playground wrapper review fixes
- CI: install `playground` (PyPI name) instead of import name `mujoco_playground`; the previous `pip install mujoco_playground` was the root cause of the current `unittests-mujoco-playground` CI failure. - CI: drop the broken try/except JAX-init fallback in run_test.sh — it ran in a subprocess that exited immediately, so `JAX_PLATFORM_NAME` never reached pytest and any real "GPU not visible" error was hidden. - Wrapper: docstrings no longer advertise a `state` field that the env never emits; the JAX state is intentionally kept on `self._current_state` rather than round-tripped through TensorDict (this is now documented as a `.. note::` block). - Wrapper: freeze `MujocoPlaygroundAgentSpec` / `MujocoPlaygroundAgentMapping` dataclasses and deep-copy `KNOWN_MARL_MAPPINGS` entries on string lookup so users cannot mutate the module-level mapping by accident. - Wrapper: emit a `UserWarning` when resolving a string against `KNOWN_MARL_MAPPINGS`, since those indices target Brax's observation layout and may not be semantically equivalent for mujoco_playground envs. - Wrapper: document the policy contract for `homogenization_mode='max'` and `'concat'` (which action/obs entries are real vs padding/discarded). - Wrapper: align `_MujocoPlaygroundMeta` num_workers handling with `_BraxMeta`; make `agent_mapping` and `config`/`config_overrides` keyword-only; accept `seed=None` in `_set_seed` (defaults to 0, matching the `_reset` fallback) instead of raising bare `Exception`; document `_listerize`'s inclusive-range semantics; drop unused `pixels_only`/`camera_id`/`render_kwargs` from `_build_env`. - Example: rewrite `save_visualization` in `profile_mujoco_playground_collector.py` to snapshot `env._current_state` during a manual rollout, removing dependencies on non-existent `env._state_example` and `td["state"]`. - Config: drop stale `categorical_action_encoding` field on `MujocoPlaygroundEnvConfig`; add `agent_mapping` and `num_workers` so the MARL and parallel-process knobs are reachable from the config system. - Tests: replace three duplicated `_setup_jax` fixtures with a single module-level autouse fixture; introduce a session-scoped `marl_env_sizes` fixture to avoid constructing a throwaway env in every MARL test; expect the new MABrax warning on string lookups; add a new `TestMujocoPlaygroundDictObs` class covering reset / `check_env_specs` and a negative test that `homogenization_mode != 'none'` raises `NotImplementedError` for dict-obs envs; make `test_no_mapping_regression` actually exercise the MARL env it constructs. - Docs: keep the `MOGymEnv` / `MOGymWrapper` pair adjacent in `envs_libraries.rst`; `__repr__` now uses `env_name=` to match the constructor kwarg.
1 parent 39e43d7 commit 15de4dd

7 files changed

Lines changed: 400 additions & 306 deletions

File tree

.github/unittest/linux_libs/scripts_mujoco_playground/environment.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,6 @@ dependencies:
2121
- scipy
2222
- hydra-core
2323
- jax[cuda12]>=0.7.0
24-
- mujoco_playground
24+
# NOTE: import name is `mujoco_playground` but the PyPI distribution is `playground`.
25+
- playground
2526
- psutil

.github/unittest/linux_libs/scripts_mujoco_playground/run_test.sh

Lines changed: 5 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -30,31 +30,11 @@ export MAGNUM_LOG=verbose MAGNUM_GPU_VALIDATION=ON
3030
python -c "import mujoco_playground"
3131
python -c "from mujoco_playground import dm_control_suite, locomotion, manipulation, registry"
3232

33-
# Initialize JAX with proper GPU configuration
34-
python -c "
35-
import jax
36-
import jax.numpy as jnp
37-
import os
38-
39-
# Configure JAX for GPU
40-
os.environ['XLA_PYTHON_CLIENT_PREALLOCATE'] = 'false'
41-
os.environ['XLA_PYTHON_CLIENT_ALLOCATOR'] = 'platform'
42-
43-
# Test JAX GPU availability
44-
try:
45-
devices = jax.devices()
46-
print(f'JAX devices: {devices}')
47-
if len(devices) > 1:
48-
print('JAX GPU is available')
49-
else:
50-
print('JAX CPU only')
51-
except Exception as e:
52-
print(f'JAX initialization error: {e}')
53-
# Fallback to CPU
54-
os.environ['JAX_PLATFORM_NAME'] = 'cpu'
55-
jax.config.update('jax_platform_name', 'cpu')
56-
print('Falling back to JAX CPU')
57-
"
33+
# Report JAX devices. We deliberately avoid try/except + JAX_PLATFORM_NAME
34+
# fallback here: it runs in a subprocess that exits immediately, so it has no
35+
# effect on the pytest invocation below, and it would hide a real "GPU not
36+
# visible" failure from CI.
37+
python -c "import jax; print(f'JAX devices: {jax.devices()}')"
5838

5939
python -c 'import torch;t = torch.ones([2,2], device="cuda:0");print(t);print("tensor device:" + str(t.device))'
6040

docs/source/reference/envs_libraries.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,9 @@ Available wrappers
9797
MeltingpotEnv
9898
MeltingpotWrapper
9999
MOGymEnv
100+
MOGymWrapper
100101
MujocoPlaygroundEnv
101102
MujocoPlaygroundWrapper
102-
MOGymWrapper
103103
MultiThreadedEnv
104104
MultiThreadedEnvWrapper
105105
OpenMLEnv

examples/collectors/profile_mujoco_playground_collector.py

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
from torchrl._utils import logger as torchrl_logger
4242
from torchrl.collectors import Collector
4343
from torchrl.envs import MujocoPlaygroundEnv
44-
from torchrl.envs.libs.jax_utils import _tensordict_to_object
44+
from torchrl.envs.utils import step_mdp
4545

4646
os.environ.setdefault("TORCHRL_PROFILING", "1")
4747

@@ -262,43 +262,44 @@ def make_policy(
262262
raise ValueError(f"Unknown policy mode {policy_mode!r}.")
263263

264264

265-
def save_visualization(env: MujocoPlaygroundEnv, args: argparse.Namespace) -> None:
265+
def save_visualization(
266+
env: MujocoPlaygroundEnv,
267+
policy: typing.Callable[[TensorDictBase], TensorDictBase],
268+
args: argparse.Namespace,
269+
) -> None:
266270
"""Collect a short rollout and save a rendered visualization.
267271
268-
Converts TensorDict states back to JAX State objects, calls the
269-
underlying environment's ``render`` method, then writes the frames
270-
to an MP4 file (via ``imageio``) or to individual PNG files.
272+
Snapshots the env's JAX state (``env._current_state``) after each step,
273+
optionally indexing into the leading batch dim, and feeds the resulting
274+
list of states to the underlying env's ``render`` method.
271275
272276
Args:
273277
env (MujocoPlaygroundEnv): the environment to render.
278+
policy (callable): a policy that fills the action in a TensorDict.
274279
args (argparse.Namespace): parsed command-line arguments.
275280
"""
276281
import jax
277282

283+
batched = len(env.batch_size) > 0
284+
285+
def _snapshot(state):
286+
# For batched envs, pick the first sub-environment so the renderer
287+
# receives un-batched JAX State objects.
288+
if batched:
289+
return jax.tree_util.tree_map(lambda x: x[0], state)
290+
return state
291+
278292
torchrl_logger.info(
279293
f"Collecting {args.render_steps} steps for visualization rollout."
280294
)
295+
td = env.reset()
296+
states = [_snapshot(env._current_state)]
281297
with torch.no_grad():
282-
td = env.rollout(args.render_steps)
283-
284-
batched = len(env.batch_size) > 0
285-
286-
# Build a single-element state example so _tensordict_to_object can
287-
# infer field structure without a batch dimension.
288-
if batched:
289-
single_example = jax.tree_util.tree_map(lambda x: x[0], env._state_example)
290-
else:
291-
single_example = env._state_example
292-
293-
torchrl_logger.info("Converting TensorDict states to JAX State objects.")
294-
states = []
295-
for t in range(args.render_steps):
296-
if batched:
297-
step_td = td[0, t].get("state")
298-
else:
299-
step_td = td[t].get("state")
300-
jax_state = _tensordict_to_object(step_td, single_example)
301-
states.append(jax_state)
298+
for _ in range(args.render_steps):
299+
td = policy(td)
300+
td = env.step(td)
301+
states.append(_snapshot(env._current_state))
302+
td = step_mdp(td)
302303

303304
torchrl_logger.info(
304305
f"Rendering {len(states)} frames "
@@ -402,7 +403,7 @@ def main() -> None:
402403
torchrl_logger.info(f"Trace written to {worker_0_trace_path}.")
403404

404405
if args_cli.render:
405-
save_visualization(env, args_cli)
406+
save_visualization(env, policy, args_cli)
406407

407408
env.close()
408409

0 commit comments

Comments
 (0)