World-Action-Verifier / src /envs /__init__.py
ffeng1017's picture
WAV interactive demo (ZeroGPU)
23a59ea verified
Raw
History Blame Contribute Delete
4.02 kB
import importlib
import warnings
warnings.filterwarnings('ignore')
import gymnasium as gym
from envs.wrappers.vectorized_multitask import make_vectorized_multitask_env
from envs.wrappers.render import Render
# Every domain used to be imported eagerly here, which means one missing
# dependency took down *all* tasks rather than just its own -- painful on any
# partial install, and fatal when deploying (a hosted demo cannot install a
# Vulkan ICD for ManiSkill, but should still serve the other nine domains).
# Each domain is now loaded behind a guard, generalising the pattern that was
# already used for Atari: on failure the name binds to a stub that raises the
# original error, but only if that domain's task is actually requested.
# `AVAILABLE_DOMAINS` lets a caller filter its task list up front instead.
#
# The guard catches Exception, not just ImportError, because these domains fail
# in more ways than a missing module: a native renderer with no GL/Vulkan
# context available typically raises RuntimeError or OSError at import time.
_IMPORT_ERRORS = {}
AVAILABLE_DOMAINS = set()
def _load_domain(module, domains, hint):
"""Return envs.<module>.make_env, or a stub explaining why it is unavailable."""
try:
fn = importlib.import_module(f'envs.{module}').make_env
except Exception as err:
_IMPORT_ERRORS[module] = err
def _unavailable(cfg, _m=module, _h=hint, _e=err):
raise ImportError(
f'The {_m} domain is not available in this installation ({_h}). '
f'Original import error: {type(_e).__name__}: {_e}'
)
return _unavailable
AVAILABLE_DOMAINS.update(domains)
return fn
make_dm_control_env = _load_domain(
'dmcontrol', ('dmcontrol', 'dmcontrol-ext'), 'needs dm-control and a headless MuJoCo GL backend, e.g. MUJOCO_GL=egl')
make_maniskill_env = _load_domain(
'maniskill', ('maniskill',), 'needs mani_skill, and SAPIEN requires a Vulkan ICD')
make_metaworld_env = _load_domain(
'metaworld', ('metaworld',), 'needs the metaworld fork and a headless MuJoCo GL backend')
make_mujoco_env = _load_domain(
'mujoco', ('mujoco',), 'needs mujoco and a headless GL backend')
make_box2d_env = _load_domain(
'box2d', ('box2d',), 'needs box2d-py (built with swig) and pygame')
make_robodesk_env = _load_domain(
'robodesk', ('robodesk',), 'needs robodesk and a headless MuJoCo GL backend')
make_ogbench_env = _load_domain(
'ogbench', ('ogbench',), 'needs ogbench and a headless MuJoCo GL backend')
make_pygame_env = _load_domain(
'pygame', ('pygame',), 'needs pygame; set SDL_VIDEODRIVER=dummy when headless')
make_atari_env = _load_domain(
'atari', ('atari',), 'needs ale_py>=0.10 for continuous-action Atari')
def unavailable_domains():
"""Map of domain module -> the exception that stopped it importing."""
return dict(_IMPORT_ERRORS)
def make_env(cfg):
"""
Make an environment for world-model experiments.
"""
gym.logger.set_level(40)
if not cfg.child_env:
env = make_vectorized_multitask_env(cfg, make_env)
else:
env = None
for fn in [
make_dm_control_env, make_maniskill_env, make_metaworld_env,
make_mujoco_env, make_box2d_env, make_robodesk_env,
make_ogbench_env, make_pygame_env, make_atari_env,
]:
try:
env = fn(cfg)
break
except ValueError as e:
if 'Unknown task' in str(e):
continue
else:
raise e
if env is None:
raise ValueError(f'Failed to make environment "{cfg.task}": please verify that dependencies are installed and that the task exists.')
assert cfg.num_envs == 1 or cfg.get('obs', 'state') == 'state', \
'Vectorized environments only support state observations.'
if cfg.save_video and cfg.get('num_demos', 0) > 0:
env = Render(env, cfg)
print(f'[Rank {cfg.rank}] Created env for task {cfg.task}')
try: # Dict
cfg.obs_shape = {k: v.shape for k, v in env.observation_space.spaces.items()}
except: # Box
cfg.obs_shape = {cfg.get('obs', 'state'): env.observation_space.shape}
cfg.action_dim = env.action_space.shape[0]
cfg.episode_length = env.max_episode_steps
return env