Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions source/isaaclab/isaaclab/envs/direct_marl_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
from dataclasses import MISSING
from typing import Any, ClassVar

import isaacsim.core.utils.torch as torch_utils
import omni.kit.app
import omni.log
import omni.physx
Expand All @@ -28,6 +27,7 @@
from isaaclab.sim import SimulationContext
from isaaclab.sim.utils import attach_stage_to_usd_context, use_stage
from isaaclab.utils.noise import NoiseModel
from isaaclab.utils.seed import set_seed
from isaaclab.utils.timer import Timer

from .common import ActionType, AgentID, EnvStepReturn, ObsType, StateType
Expand Down Expand Up @@ -462,7 +462,7 @@ def seed(seed: int = -1) -> int:
except ModuleNotFoundError:
pass
# set seed for torch and other libraries
return torch_utils.set_seed(seed)
return set_seed(seed)

def render(self, recompute: bool = False) -> np.ndarray | None:
"""Run rendering without stepping through the physics.
Expand Down
4 changes: 2 additions & 2 deletions source/isaaclab/isaaclab/envs/direct_rl_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
from dataclasses import MISSING
from typing import Any, ClassVar

import isaacsim.core.utils.torch as torch_utils
import omni.kit.app
import omni.log
import omni.physx
Expand All @@ -29,6 +28,7 @@
from isaaclab.sim import SimulationContext
from isaaclab.sim.utils import attach_stage_to_usd_context, use_stage
from isaaclab.utils.noise import NoiseModel
from isaaclab.utils.seed import set_seed
from isaaclab.utils.timer import Timer

from .common import VecEnvObs, VecEnvStepReturn
Expand Down Expand Up @@ -414,7 +414,7 @@ def seed(seed: int = -1) -> int:
except ModuleNotFoundError:
pass
# set seed for torch and other libraries
return torch_utils.set_seed(seed)
return set_seed(seed)

def render(self, recompute: bool = False) -> np.ndarray | None:
"""Run rendering without stepping through the physics.
Expand Down
4 changes: 2 additions & 2 deletions source/isaaclab/isaaclab/envs/manager_based_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from collections.abc import Sequence
from typing import Any

import isaacsim.core.utils.torch as torch_utils
import omni.log
import omni.physx
from isaacsim.core.simulation_manager import SimulationManager
Expand All @@ -19,6 +18,7 @@
from isaaclab.sim import SimulationContext
from isaaclab.sim.utils import attach_stage_to_usd_context, use_stage
from isaaclab.ui.widgets import ManagerLiveVisualizer
from isaaclab.utils.seed import set_seed
from isaaclab.utils.timer import Timer

from .common import VecEnvObs
Expand Down Expand Up @@ -495,7 +495,7 @@ def seed(seed: int = -1) -> int:
except ModuleNotFoundError:
pass
# set seed for torch and other libraries
return torch_utils.set_seed(seed)
return set_seed(seed)

def close(self):
"""Cleanup for the environment."""
Expand Down
40 changes: 40 additions & 0 deletions source/isaaclab/isaaclab/utils/seed.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Copyright (c) 2022-2025, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md).
# All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause

import numpy as np
import os
import random
import torch

import warp as wp


def set_seed(seed: int, torch_deterministic: bool = False) -> int:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: To me a "set" usually should be combined with "get". Do you want to add something like "get_seed" as well? Or maybe we call this function configure_seed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case, I would rename it! Only effect is a bigger break as also the name of the function changes

"""set seed across modules"""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: docstring should follow PEP 257 style and include parameter descriptions

Suggested change
"""set seed across modules"""
"""Set seed across all random number generators (torch, numpy, random, warp).
Args:
seed: The random seed value. If -1, generates a random seed.
torch_deterministic: If True, enables deterministic mode for torch operations.
Returns:
The seed value that was set.
"""

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should seed also support None type which means it becomes "-1" behavior? I feel it is more inutitive than -1. Also are negative number generators valid? It seems ti is a yes for random and numpy at least.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right on both counts! Supporting None would be more intuitive than using -1 for random seed generation, and negative numbers are indeed valid seeds for the underlying generators.

Looking at the current implementation, using -1 as a special value to trigger random seed generation isn't very pythonic. The more common pattern is to use None for this purpose, which is what many libraries like numpy.random.seed() and random.seed() expect.

Regarding negative seeds - yes, they are valid:

  • random.seed() accepts any hashable object, including negative integers
  • numpy.random.seed() accepts negative integers
  • torch.manual_seed() accepts negative integers
  • warp.rand_init() should also handle negative seeds

Here's how I'd suggest modifying the function:

Suggested change
"""set seed across modules"""
def set_seed(seed: int | None, torch_deterministic: bool = False) -> int:
"""Set seed across all random number generators (torch, numpy, random, warp).
Args:
seed: The random seed value. If None, generates a random seed.
torch_deterministic: If True, enables deterministic mode for torch operations.
Returns:
The seed value that was set.
"""
if seed is None and torch_deterministic:
seed = 42
elif seed is None:
seed = np.random.randint(0, 10000)
print(f"Setting seed: {seed}")
random.seed(seed)
np.random.seed(seed)
torch.manual_seed(seed)
os.environ["PYTHONHASHSEED"] = str(seed)
torch.cuda.manual_seed(seed)
torch.cuda.manual_seed_all(seed)
wp.rand_init(seed)
if torch_deterministic:
# refer to https://docs.nvidia.com/cuda/cublas/index.html#cublasApi_reproducibility
os.environ["CUBLAS_WORKSPACE_CONFIG"] = ":4096:8"
torch.backends.cudnn.benchmark = False
torch.backends.cudnn.deterministic = True
torch.use_deterministic_algorithms(True)
else:
torch.backends.cudnn.benchmark = True
torch.backends.cudnn.deterministic = False
return seed

This change makes the API more intuitive and follows Python conventions. You'll also need to update any calls to this function that currently pass -1 to pass None instead.

if seed == -1 and torch_deterministic:
seed = 42
elif seed == -1:
seed = np.random.randint(0, 10000)
print(f"Setting seed: {seed}")

random.seed(seed)
np.random.seed(seed)
torch.manual_seed(seed)
os.environ["PYTHONHASHSEED"] = str(seed)
torch.cuda.manual_seed(seed)
torch.cuda.manual_seed_all(seed)
wp.rand_init(seed)

if torch_deterministic:
# refer to https://docs.nvidia.com/cuda/cublas/index.html#cublasApi_reproducibility
os.environ["CUBLAS_WORKSPACE_CONFIG"] = ":4096:8"
torch.backends.cudnn.benchmark = False
torch.backends.cudnn.deterministic = True
torch.use_deterministic_algorithms(True)
else:
torch.backends.cudnn.benchmark = True
torch.backends.cudnn.deterministic = False

return seed
8 changes: 4 additions & 4 deletions source/isaaclab/test/terrains/test_terrain_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@
import shutil
import torch

import isaacsim.core.utils.torch as torch_utils
import pytest

from isaaclab.terrains import FlatPatchSamplingCfg, TerrainGenerator, TerrainGeneratorCfg
from isaaclab.terrains.config.rough import ROUGH_TERRAINS_CFG
from isaaclab.utils.seed import set_seed


@pytest.fixture
Expand Down Expand Up @@ -65,7 +65,7 @@ def test_generation_reproducibility(use_global_seed, seed):
Setting only locally is not tested as it is not supported.
"""
# set initial seed
torch_utils.set_seed(seed)
set_seed(seed)

# create terrain generator
cfg = ROUGH_TERRAINS_CFG
Expand All @@ -77,7 +77,7 @@ def test_generation_reproducibility(use_global_seed, seed):
terrain_mesh_1 = terrain_generator.terrain_mesh.copy()

# set seed again
torch_utils.set_seed(seed)
set_seed(seed)

# create terrain generator
terrain_generator = TerrainGenerator(cfg=cfg)
Expand Down Expand Up @@ -116,7 +116,7 @@ def test_generation_cache(output_dir, curriculum):

# set a random seed to disturb the process
# this is to ensure that the seed inside the terrain generator makes deterministic results
torch_utils.set_seed(12456)
set_seed(12456)

# create terrain generator with cache enabled
terrain_generator = TerrainGenerator(cfg=cfg)
Expand Down
Loading