Unify env random seeding using ManagerBasedRLEnv seed#777
Conversation
Greptile SummaryReplaces Arena's custom
Confidence Score: 5/5Safe to merge — the refactor correctly routes seeding through Isaac Lab's existing mechanism with no regressions in the non-distributed or distributed paths. All three call paths (single-process, distributed, batched eval) now receive the seed via No files require special attention. Important Files Changed
Sequence DiagramsequenceDiagram
participant CLI as CLI (--seed)
participant PR as policy_runner.py
participant AB as ArenaEnvBuilder
participant IL as Isaac Lab (ManagerBasedRLEnv)
CLI->>PR: args_cli.seed (default 42)
Note over PR: Distributed? seed += local_rank
PR->>AB: make_registered_and_return_cfg(args_cli)
AB->>AB: env_cfg_callback(env_cfg)
Note over AB: After callback:<br/>env_cfg.seed = args.seed
AB->>IL: gym.make(env_name, env_cfg)
Note over IL: Sets torch / cuda / numpy /<br/>random / replicator / warp seeds
IL-->>PR: env
Reviews (2): Last reviewed commit: "fix seed setting location in env builder" | Re-trigger Greptile |
There was a problem hiding this comment.
Review Summary
Clean refactoring that unifies environment seeding through Isaac Lab's built-in ManagerBasedRLEnv.seed mechanism, eliminating the inconsistent custom set_seed utility. The approach is sound — centralizing seed propagation in compose_manager_cfg ensures all code paths through ArenaEnvBuilder (including batched eval) get consistent seeding.
Findings
1. 🟡 Seed mutation of args_cli is a side effect that persists beyond its intended scope
File: isaaclab_arena/evaluation/policy_runner.py (line ~172)
if args_cli.seed is not None:
args_cli.seed += local_rankThis mutates args_cli.seed in-place before passing it to get_arena_builder_from_cli. Since args_cli is a namespace object shared throughout main(), any subsequent code that reads args_cli.seed will see the modified value (base_seed + local_rank) rather than the original user-supplied seed. While nothing currently reads it afterwards, this is fragile — future code (e.g., logging the user's requested seed, or a second env build) would silently get the wrong value.
Suggestion: Use a local variable instead:
env_seed = args_cli.seed
if env_seed is not None and is_distributed(args_cli):
env_seed += local_rank
args_cli.seed = env_seed # or pass env_seed explicitlyOr at minimum, add a comment noting the intentional mutation.
2. 🟡 env_cfg.seed is set before the env_cfg_callback, which could silently override it
File: isaaclab_arena/environments/arena_env_builder.py (line ~295-296)
# Set seed for Isaac Lab env.
env_cfg.seed = getattr(self.args, "seed", None)
# Apply the environment configuration callback if it is set
if self.arena_env.env_cfg_callback is not None:
env_cfg = self.arena_env.env_cfg_callback(env_cfg)The seed is set before the callback runs. If any env_cfg_callback also sets env_cfg.seed (e.g., for environment-specific reproducibility requirements), it will silently override the CLI-provided seed without warning. Conversely, if the intent is that CLI --seed should always be authoritative, consider moving the seed assignment after the callback (similar to how --presets is applied after the callback with the comment "the user's CLI choice is the final authority").
3. 🟢 Minor: The --seed CLI default is 42, so getattr(self.args, "seed", None) will never return None
File: isaaclab_arena/environments/arena_env_builder.py (line ~296)
The CLI defines --seed with default=42, meaning args.seed will always be an integer (never None) when invoked through standard CLI paths. The getattr(..., None) fallback only activates if self.args is a manually constructed namespace without a seed attribute. This isn't a bug, but the code reads as if None is a normal case. A brief comment clarifying the intent (e.g., "None when seed is explicitly disabled or args built programmatically") would improve readability.
4. 🟢 Dead code removal is incomplete — set_seed function body removed but not the function itself
File: isaaclab_arena/utils/random.py
The diff removes the set_seed function entirely, which is correct since no other module imports it (confirmed: only policy_runner.py imported it). The cleanup is complete. ✅ (No action needed — this is confirmation that the removal is safe.)
5. 🟡 No test coverage for the new seeding path
The PR removes the set_seed call but doesn't add tests verifying that env_cfg.seed is correctly propagated through compose_manager_cfg. Given that the PR description mentions this fixes non-deterministic results in batched eval, a regression test (even a simple unit test asserting compose_manager_cfg().seed == args.seed) would protect against future refactors accidentally breaking seed propagation.
Overall Assessment
This is a well-motivated simplification. Isaac Lab's native seeding is indeed more comprehensive (covers replicator + warp in addition to torch/numpy/random). The main concerns are:
- The in-place mutation pattern for distributed seeds (minor robustness issue)
- Ordering relative to
env_cfg_callback(design decision worth documenting) - Lack of test coverage for the new path
None of these are blocking. Nice cleanup! 👍
Update (commit f940f58): ✅ Finding #2 addressed — seed assignment moved after env_cfg_callback, ensuring CLI --seed is always authoritative (matching --presets pattern). No new issues in this commit. Remaining findings (#1 args mutation, #3 minor readability, #5 test coverage) are non-blocking and unchanged.
|
How about for the seed you modify here, we call it |
alexmillane
left a comment
There was a problem hiding this comment.
Looks good to me!!! Thanks for doing this!
We still have this variable placement_seed around. I wonder if we can also simplify by getting rid of that? But that's a question for another time.
| env_cfg = self.arena_env.env_cfg_callback(env_cfg) | ||
|
|
||
| # Set seed for Isaac Lab env. | ||
| env_cfg.seed = getattr(self.args, "seed", None) |
There was a problem hiding this comment.
We have a default seed of 42, so I think we can skip the getattr no?
claude likes to chuck these everywhere, but in my opinion that hurt the readablity.
Summary
Arena was previously setting the seed using a custom
set_seedfunction in Arena. The seeding was inconsistent and not always being set (for example it was not used for batched eval). This gave non-deterministic results.This PR removes the inconsistent env seeding and uses Isaac Lab's built in env random seeding mechanism. Any time a user provides a seed via CLI, it is passed to the arena environment builder which sets it in the env_cfg. Isaac Lab then handles setting all global seeds.
Note: Isaac Lab's seed mechanism sets all of the seeds that Arena was setting plus additional seeds for replicator and warp. It is more comprehensive than what Arena had.