def __init__( self, env, directory, video_callable=None, force=False, resume=False, write_upon_reset=False, uid=None, mode=None, ): super().__init__(env) logger.deprecation( "The Monitor wrapper is being deprecated in favor of gym.wrappers.RecordVideo and gym.wrappers.RecordEpisodeStatistics (see https://github.com/openai/gym/issues/2297)" ) self.videos = [] self.stats_recorder = None self.video_recorder = None self.enabled = False self.episode_id = 0 self._monitor_id = None self.env_semantics_autoreset = env.metadata.get("semantics.autoreset") self._start(directory, video_callable, force, resume, write_upon_reset, uid, mode)
def seed(self, seed=None): """:deprecated: function that sets the seed for the environment's random number generator(s). Use `env.reset(seed=seed)` as the new API for setting the seed of the environment. Note: Some environments use multiple pseudorandom number generators. We want to capture all such seeds used in order to ensure that there aren't accidental correlations between multiple generators. Args: seed(Optional int): The seed value for the random number geneartor Returns: seeds (List[int]): Returns the list of seeds used in this environment's random number generators. The first value in the list should be the "main" seed, or the value which a reproducer should pass to 'seed'. Often, the main seed equals the provided 'seed', but this won't be true `if seed=None`, for example. """ deprecation( "Function `env.seed(seed)` is marked as deprecated and will be removed in the future. " "Please use `env.reset(seed=seed)` instead.") self._np_random, seed = seeding.np_random(seed) return [seed]
def create_seed(a: Optional[Union[int, str]] = None, max_bytes: int = 8) -> int: """Create a strong random seed. Otherwise, Python 2 would seed using the system time, which might be non-robust especially in the presence of concurrency. Args: a: None seeds from an operating system specific randomness source. max_bytes: Maximum number of bytes to use in the seed. """ deprecation( "Function `create_seed(a, max_bytes)` is marked as deprecated and will be removed in the future. " ) # Adapted from https://svn.python.org/projects/python/tags/r32/Lib/random.py if a is None: a = _bigint_from_bytes(os.urandom(max_bytes)) elif isinstance(a, str): bt = a.encode("utf8") bt += hashlib.sha512(bt).digest() a = _bigint_from_bytes(bt[:max_bytes]) elif isinstance(a, int): a = int(a % 2**(8 * max_bytes)) else: raise error.Error(f"Invalid type for seed: {type(a)} ({a})") return a
def randint(self, low, high=None, size=None, dtype=int): deprecation( "Function `rng.randint(low, [high, size, dtype])` is marked as deprecated " "and will be removed in the future. " "Please use `rng.integers(low, [high, size, dtype])` instead.") return self.integers(low=low, high=high, size=size, dtype=dtype)
def set_state(self, state): """Deprecated set rng state function use bit_generator.state = state.""" deprecation("Function `rng.set_state(state)` is marked as deprecated " "and will be removed in the future. " "Please use `rng.bit_generator.state = state` instead.") self.bit_generator.state = state
def get_state(self): """Deprecated get rng state use bit_generator.state.""" deprecation("Function `rng.get_state()` is marked as deprecated " "and will be removed in the future. " "Please use `rng.bit_generator.state` instead.") return self.bit_generator.state
def randn(self, *size): """Deprecated random standard normal function use standard_normal.""" deprecation("Function `rng.randn(*size)` is marked as deprecated " "and will be removed in the future. " "Please use `rng.standard_normal(size)` instead.") return self.standard_normal(size)
def rand(self, *size): """Deprecated rand function using random.""" deprecation("Function `rng.rand(*size)` is marked as deprecated " "and will be removed in the future. " "Please use `Generator.random(size)` instead.") return self.random(size)
def seed(self, seed=None): deprecation( "Function `rng.seed(seed)` is marked as deprecated " "and will be removed in the future. " "Please use `rng, seed = gym.utils.seeding.np_random(seed)` to create a separate generator instead." ) self.bit_generator.state = type(self.bit_generator)(seed).state
def __init__( self, env: gym.Env, video_folder: str, episode_trigger: Callable[[int], bool] = None, step_trigger: Callable[[int], bool] = None, video_length: int = 0, name_prefix: str = "rl-video", ): """Wrapper records videos of rollouts. Args: env: The environment that will be wrapped video_folder (str): The folder where the recordings will be stored episode_trigger: Function that accepts an integer and returns ``True`` iff a recording should be started at this episode step_trigger: Function that accepts an integer and returns ``True`` iff a recording should be started at this step video_length (int): The length of recorded episodes. If 0, entire episodes are recorded. Otherwise, snippets of the specified length are captured name_prefix (str): Will be prepended to the filename of the recordings """ super().__init__(env) logger.deprecation( "RecordVideo is deprecated.\n" "Collect the frames with render_mode='rgb_array' and use an external library like MoviePy: " "https://zulko.github.io/moviepy/getting_started/videoclips.html#videoclip" ) if episode_trigger is None and step_trigger is None: episode_trigger = capped_cubic_video_schedule trigger_count = sum(x is not None for x in [episode_trigger, step_trigger]) assert trigger_count == 1, "Must specify exactly one trigger" self.episode_trigger = episode_trigger self.step_trigger = step_trigger self.video_recorder = None self.video_folder = os.path.abspath(video_folder) # Create output folder if needed if os.path.isdir(self.video_folder): logger.warn( f"Overwriting existing videos at {self.video_folder} folder " f"(try specifying a different `video_folder` for the `RecordVideo` wrapper if this is not desired)" ) os.makedirs(self.video_folder, exist_ok=True) self.name_prefix = name_prefix self.step_id = 0 self.video_length = video_length self.recording = False self.recorded_frames = 0 self.is_vector_env = getattr(env, "is_vector_env", False) self.episode_id = 0
def seed(self, seed=None): """Set the random seed in all parallel environments. Args: seed: Random seed for each parallel environment. If ``seed`` is a list of length ``num_envs``, then the items of the list are chosen as random seeds. If ``seed`` is an int, then each parallel environment uses the random seed ``seed + n``, where ``n`` is the index of the parallel environment (between ``0`` and ``num_envs - 1``). """ deprecation( "Function `env.seed(seed)` is marked as deprecated and will be removed in the future. " "Please use `env.reset(seed=seed) instead in VectorEnvs.")
def _bigint_from_bytes(bt: bytes) -> int: deprecation( "Function `_bigint_from_bytes(bytes)` is marked as deprecated and will be removed in the future. " ) sizeof_int = 4 padding = sizeof_int - len(bt) % sizeof_int bt += b"\0" * padding int_count = int(len(bt) / sizeof_int) unpacked = struct.unpack(f"{int_count}I", bt) accum = 0 for i, val in enumerate(unpacked): accum += 2**(sizeof_int * 8 * i) * val return accum
def _int_list_from_bigint(bigint: int) -> List[int]: deprecation( "Function `_int_list_from_bigint` is marked as deprecated and will be removed in the future. " ) # Special case 0 if bigint < 0: raise error.Error(f"Seed must be non-negative, not {bigint}") elif bigint == 0: return [0] ints: List[int] = [] while bigint > 0: bigint, mod = divmod(bigint, 2**32) ints.append(mod) return ints
def render(self: object, *args: Tuple[Any], **kwargs: Dict[str, Any]) -> render_return: if "mode" in kwargs.keys(): deprecation( "The argument mode in render method is deprecated; " "use render_mode during environment initialization instead.\n" "See here for more information: https://www.gymlibrary.ml/content/api/" ) elif self.spec is not None and "render_mode" not in self.spec.kwargs.keys( ): # type: ignore deprecation( "You are calling render method, " "but you didn't specified the argument render_mode at environment initialization. " "To maintain backward compatibility, the environment will render in human mode.\n" "If you want to render in human mode, initialize the environment in this way: " "gym.make('EnvName', render_mode='human') and don't call the render method.\n" "See here for more information: https://www.gymlibrary.ml/content/api/" ) return render_func(self, *args, **kwargs)
def seed(self, seed=None): """Sets the seed for this env's random number generator(s). Note: Some environments use multiple pseudorandom number generators. We want to capture all such seeds used in order to ensure that there aren't accidental correlations between multiple generators. Returns: list<bigint>: Returns the list of seeds used in this env's random number generators. The first value in the list should be the "main" seed, or the value which a reproducer should pass to 'seed'. Often, the main seed equals the provided 'seed', but this won't be true if seed=None, for example. """ deprecation( "Function `env.seed(seed)` is marked as deprecated and will be removed in the future. " "Please use `env.reset(seed=seed) instead.") self._np_random, seed = seeding.np_random(seed) return [seed]
def hash_seed(seed: Optional[int] = None, max_bytes: int = 8) -> int: """Any given evaluation is likely to have many PRNG's active at once. (Most commonly, because the environment is running in multiple processes.) There's literature indicating that having linear correlations between seeds of multiple PRNG's can correlate the outputs: http://blogs.unity3d.com/2015/01/07/a-primer-on-repeatable-random-numbers/ http://stackoverflow.com/questions/1554958/how-different-do-random-seeds-need-to-be http://dl.acm.org/citation.cfm?id=1276928 Thus, for sanity we hash the seeds before using them. (This scheme is likely not crypto-strength, but it should be good enough to get rid of simple correlations.) Args: seed: None seeds from an operating system specific randomness source. max_bytes: Maximum number of bytes to use in the hashed seed. """ deprecation( "Function `hash_seed(seed, max_bytes)` is marked as deprecated and will be removed in the future. " ) if seed is None: seed = create_seed(max_bytes=max_bytes) hash = hashlib.sha512(str(seed).encode("utf8")).digest() return _bigint_from_bytes(hash[:max_bytes])
def __init__( self, callback: callable, horizon_timesteps: int, plot_names: List[str] ): """Constructor of :class:`PlayPlot`. The function ``callback`` that is passed to this constructor should return a list of metrics that is of length ``len(plot_names)``. Args: callback: Function that computes metrics from environment transitions horizon_timesteps: The time horizon used for the live plots plot_names: List of plot titles Raises: DependencyNotInstalled: If matplotlib is not installed """ deprecation( "`PlayPlot` is marked as deprecated and will be removed in the near future." ) self.data_callback = callback self.horizon_timesteps = horizon_timesteps self.plot_names = plot_names if plt is None: raise DependencyNotInstalled( "matplotlib is not installed, run `pip install gym[other]`" ) num_plots = len(self.plot_names) self.fig, self.ax = plt.subplots(num_plots) if num_plots == 1: self.ax = [self.ax] for axis, name in zip(self.ax, plot_names): axis.set_title(name) self.t = 0 self.cur_plot = [None for _ in range(num_plots)] self.data = [deque(maxlen=horizon_timesteps) for _ in range(num_plots)]
def __init__( self, env, path: Optional[str] = None, metadata: Optional[dict] = None, enabled: bool = True, base_path: Optional[str] = None, ): """Video recorder renders a nice movie of a rollout, frame by frame. Args: env (Env): Environment to take video of. path (Optional[str]): Path to the video file; will be randomly chosen if omitted. metadata (Optional[dict]): Contents to save to the metadata file. enabled (bool): Whether to actually record video, or just no-op (for convenience) base_path (Optional[str]): Alternatively, path to the video file without extension, which will be added. """ modes = env.metadata.get("render_modes", []) # backward-compatibility mode: backward_compatible_mode = env.metadata.get("render.modes", []) if len(modes) == 0 and len(backward_compatible_mode) > 0: logger.deprecation( '`env.metadata["render.modes"] is marked as deprecated and will be replaced ' 'with `env.metadata["render_modes"]` see https://github.com/openai/gym/pull/2654 for more details' ) modes = backward_compatible_mode self._async = env.metadata.get("semantics.async") self.enabled = enabled self._closed = False # Don't bother setting anything else if not enabled if not self.enabled: return self.ansi_mode = False if "rgb_array" not in modes: if "ansi" in modes: self.ansi_mode = True else: logger.info( f'Disabling video recorder because {env} neither supports video mode "rgb_array" nor "ansi".' ) # Whoops, turns out we shouldn't be enabled after all self.enabled = False return if path is not None and base_path is not None: raise error.Error( "You can pass at most one of `path` or `base_path`.") self.last_frame = None self.env = env required_ext = ".json" if self.ansi_mode else ".mp4" if path is None: if base_path is not None: # Base path given, append ext path = base_path + required_ext else: # Otherwise, just generate a unique filename with tempfile.NamedTemporaryFile(suffix=required_ext, delete=False) as f: path = f.name self.path = path path_base, actual_ext = os.path.splitext(self.path) if actual_ext != required_ext: if self.ansi_mode: hint = ( " HINT: The environment is text-only, " "therefore we're recording its text output in a structured JSON format." ) else: hint = "" raise error.Error( f"Invalid path given: {self.path} -- must have file extension {required_ext}.{hint}" ) # Touch the file in any case, so we know it's present. This corrects for platform platform differences. # Using ffmpeg on OS X, the file is precreated, but not on Linux. touch(path) self.frames_per_sec = env.metadata.get("render_fps", 30) self.output_frames_per_sec = env.metadata.get("render_fps", self.frames_per_sec) # backward-compatibility mode: self.backward_compatible_frames_per_sec = env.metadata.get( "video.frames_per_second", self.frames_per_sec) self.backward_compatible_output_frames_per_sec = env.metadata.get( "video.output_frames_per_second", self.output_frames_per_sec) if self.frames_per_sec != self.backward_compatible_frames_per_sec: logger.deprecation( '`env.metadata["video.frames_per_second"] is marked as deprecated and will be replaced ' 'with `env.metadata["render_fps"]` see https://github.com/openai/gym/pull/2654 for more details' ) self.frames_per_sec = self.backward_compatible_frames_per_sec if self.output_frames_per_sec != self.backward_compatible_output_frames_per_sec: logger.deprecation( '`env.metadata["video.output_frames_per_second"] is marked as deprecated and will be replaced ' 'with `env.metadata["render_fps"]` see https://github.com/openai/gym/pull/2654 for more details' ) self.output_frames_per_sec = self.backward_compatible_output_frames_per_sec self.encoder = None # lazily start the process self.broken = False # Dump metadata self.metadata = metadata or {} self.metadata["content_type"] = ("video/vnd.openai.ansivid" if self.ansi_mode else "video/mp4") self.metadata_path = f"{path_base}.meta.json" self.write_metadata() logger.info(f"Starting new video recorder writing to {self.path}") self.empty = True
def __init__(self, env, path=None, metadata=None, enabled=True, base_path=None): modes = env.metadata.get("render_modes", []) # backward-compatibility mode: backward_compatible_mode = env.metadata.get("render.modes", []) if len(modes) == 0 and len(backward_compatible_mode) > 0: logger.deprecation( '`env.metadata["render.modes"] is marked as deprecated and will be replaced with `env.metadata["render_modes"]` ' "see https://github.com/openai/gym/pull/2654 for more details") modes = backward_compatible_mode self._async = env.metadata.get("semantics.async") self.enabled = enabled self._closed = False # Don't bother setting anything else if not enabled if not self.enabled: return self.ansi_mode = False if "rgb_array" not in modes: if "ansi" in modes: self.ansi_mode = True else: logger.info( f'Disabling video recorder because {env} neither supports video mode "rgb_array" nor "ansi".' ) # Whoops, turns out we shouldn't be enabled after all self.enabled = False return if path is not None and base_path is not None: raise error.Error( "You can pass at most one of `path` or `base_path`.") self.last_frame = None self.env = env required_ext = ".json" if self.ansi_mode else ".mp4" if path is None: if base_path is not None: # Base path given, append ext path = base_path + required_ext else: # Otherwise, just generate a unique filename with tempfile.NamedTemporaryFile(suffix=required_ext, delete=False) as f: path = f.name self.path = path path_base, actual_ext = os.path.splitext(self.path) if actual_ext != required_ext: hint = ( " HINT: The environment is text-only, therefore we're recording its text output in a structured JSON format." if self.ansi_mode else "") raise error.Error( f"Invalid path given: {self.path} -- must have file extension {required_ext}.{hint}" ) # Touch the file in any case, so we know it's present. (This # corrects for platform platform differences. Using ffmpeg on # OS X, the file is precreated, but not on Linux. touch(path) self.frames_per_sec = env.metadata.get("render_fps", 30) self.output_frames_per_sec = env.metadata.get("render_fps", self.frames_per_sec) # backward-compatibility mode: self.backward_compatible_frames_per_sec = env.metadata.get( "video.frames_per_second", 30) self.backward_compatible_output_frames_per_sec = env.metadata.get( "video.output_frames_per_second", self.frames_per_sec) if self.frames_per_sec != self.backward_compatible_frames_per_sec: logger.deprecation( '`env.metadata["video.frames_per_second"] is marked as deprecated and will be replaced with `env.metadata["render_fps"]` ' "see https://github.com/openai/gym/pull/2654 for more details") self.frames_per_sec = self.backward_compatible_frames_per_sec if self.output_frames_per_sec != self.backward_compatible_output_frames_per_sec: logger.deprecation( '`env.metadata["video.output_frames_per_second"] is marked as deprecated and will be replaced with `env.metadata["render_fps"]` ' "see https://github.com/openai/gym/pull/2654 for more details") self.output_frames_per_sec = self.backward_compatible_output_frames_per_sec self.encoder = None # lazily start the process self.broken = False # Dump metadata self.metadata = metadata or {} self.metadata["content_type"] = ("video/vnd.openai.ansivid" if self.ansi_mode else "video/mp4") self.metadata_path = f"{path_base}.meta.json" self.write_metadata() logger.info("Starting new video recorder writing to %s", self.path) self.empty = True