Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue #216: Add envpool to openrl #278

Merged
merged 6 commits into from
Dec 20, 2023
Merged
Show file tree
Hide file tree
Changes from 4 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
85 changes: 85 additions & 0 deletions examples/envpool/train_ppo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright 2023 The OpenRL Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

""""""
import numpy as np

from openrl.configs.config import create_config_parser
from openrl.envs.common import make
from openrl.envs.wrappers.envpool_wrappers import VecAdapter, VecMonitor
from openrl.modules.common import PPONet as Net
from openrl.modules.common.ppo_net import PPONet as Net
from openrl.runners.common import PPOAgent as Agent


def train():
# create the neural network
cfg_parser = create_config_parser()
cfg = cfg_parser.parse_args()

# create environment, set environment parallelism to 9
env = make(
"envpool:CartPole-v1",
render_mode=None,
env_num=9,
asynchronous=False,
env_wrappers=[VecAdapter, VecMonitor],
env_type="gym",
)

net = Net(
env,
cfg=cfg,
)
# initialize the trainer
agent = Agent(net, use_wandb=False, project_name="envpool:CartPole-v1")
# start training, set total number of training steps to 20000
agent.train(total_time_steps=20000)

env.close()
return agent


def evaluation(agent):
# begin to test
# Create an environment for testing and set the number of environments to interact with to 9. Set rendering mode to group_human.
render_mode = "group_human"
render_mode = None
env = make("CartPole-v1", render_mode=render_mode, env_num=9, asynchronous=True)
# The trained agent sets up the interactive environment it needs.
agent.set_env(env)
# Initialize the environment and get initial observations and environmental information.
obs, info = env.reset()
done = False
step = 0
total_step, total_reward = 0, 0
while not np.any(done):
# Based on environmental observation input, predict next action.
action, _ = agent.act(obs, deterministic=True)
obs, r, done, info = env.step(action)
step += 1
total_step += 1
total_reward += np.mean(r)
if step % 50 == 0:
print(f"{step}: reward:{np.mean(r)}")
env.close()
print("total step:", total_step)
print("total reward:", total_reward)


if __name__ == "__main__":
agent = train()
evaluation(agent)
23 changes: 16 additions & 7 deletions openrl/envs/common/build_envs.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,22 @@
new_kwargs["env_num"] = env_num
if id.startswith("ALE/") or id in gym.envs.registry.keys():
new_kwargs.pop("cfg", None)
Copy link
Member

Choose a reason for hiding this comment

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

Envpool can not be installed on many platforms (such as Windows), so you should use the envpool as an external env which is out of OpenRL. Moreover, with the envpool as an external env, you don't need to write test code for codecov, because we only track the code in the openrl folder.

Examples:


env = make(
id,
render_mode=env_render_mode,
disable_env_checker=_disable_env_checker,
**new_kwargs,
)
if "envpool" in new_kwargs:
# for now envpool doesnt support any render mode
# envpool also doesnt stores the id anywhere
Copy link
Member

Choose a reason for hiding this comment

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

Envpool can not be installed on many platforms (such as Windows), so you should use the envpool as an external env which is out of OpenRL. Moreover, with the envpool as an external env, you don't need to write test code for codecov, because we only track the code in the openrl folder.

Examples:

new_kwargs.pop("envpool")
env = make(

Check warning on line 43 in openrl/envs/common/build_envs.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/common/build_envs.py#L42-L43

Added lines #L42 - L43 were not covered by tests
id,
**new_kwargs,
)
env.unwrapped.spec.id = id

Check warning on line 47 in openrl/envs/common/build_envs.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/common/build_envs.py#L47

Added line #L47 was not covered by tests
else:
env = make(
id,
render_mode=env_render_mode,
disable_env_checker=_disable_env_checker,
**new_kwargs,
)

if wrappers is not None:
if callable(wrappers):
Expand Down
14 changes: 13 additions & 1 deletion openrl/envs/common/registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
""""""
from typing import Callable, Optional

import envpool
Copy link
Member

Choose a reason for hiding this comment

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

Envpool can not be installed on many platforms (such as Windows), so you should use the envpool as an external env which is out of OpenRL. Moreover, with the envpool as an external env, you don't need to write test code for codecov, because we only track the code in the openrl folder.

Examples:

import gymnasium as gym

import openrl
Expand Down Expand Up @@ -72,7 +73,6 @@
env_fns = make_single_agent_drone_envs(
id=id, env_num=env_num, render_mode=convert_render_mode, **kwargs
)

elif id.startswith("snakes_"):
from openrl.envs.snake import make_snake_envs

Expand Down Expand Up @@ -155,6 +155,18 @@
env_fns = make_PettingZoo_envs(
id=id, env_num=env_num, render_mode=convert_render_mode, **kwargs
)
elif (

Check warning on line 158 in openrl/envs/common/registration.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/common/registration.py#L158

Added line #L158 was not covered by tests
"envpool:" in id
Copy link
Member

Choose a reason for hiding this comment

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

Envpool can not be installed on many platforms (such as Windows), so you should use the envpool as an external env which is out of OpenRL. Moreover, with the envpool as an external env, you don't need to write test code for codecov, because we only track the code in the openrl folder.

Examples:

and id.split(":")[-1] in envpool.registration.list_all_envs()
):
from openrl.envs.envpool import make_envpool_envs

Check warning on line 162 in openrl/envs/common/registration.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/common/registration.py#L162

Added line #L162 was not covered by tests

env_fns = make_envpool_envs(

Check warning on line 164 in openrl/envs/common/registration.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/common/registration.py#L164

Added line #L164 was not covered by tests
Copy link
Member

Choose a reason for hiding this comment

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

Envpool can not be installed on many platforms (such as Windows), so you should use the envpool as an external env which is out of OpenRL. Moreover, with the envpool as an external env, you don't need to write test code for codecov, because we only track the code in the openrl folder.

Examples:

id=id.split(":")[-1],
env_num=env_num,
render_mode=convert_render_mode,
**kwargs,
)
else:
raise NotImplementedError(f"env {id} is not supported.")

Expand Down
47 changes: 47 additions & 0 deletions openrl/envs/envpool/__init__.py
Copy link
Member

Choose a reason for hiding this comment

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

should move to examples/envpool

Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright 2023 The OpenRL Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

""""""
from typing import List, Optional, Union

Check warning on line 18 in openrl/envs/envpool/__init__.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/envpool/__init__.py#L17-L18

Added lines #L17 - L18 were not covered by tests

import envpool

Check warning on line 20 in openrl/envs/envpool/__init__.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/envpool/__init__.py#L20

Added line #L20 was not covered by tests

from openrl.envs.common import build_envs

Check warning on line 22 in openrl/envs/envpool/__init__.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/envpool/__init__.py#L22

Added line #L22 was not covered by tests


def make_envpool_envs(

Check warning on line 25 in openrl/envs/envpool/__init__.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/envpool/__init__.py#L25

Added line #L25 was not covered by tests
id: str,
env_num: int = 1,
render_mode: Optional[Union[str, List[str]]] = None,
**kwargs,
):
assert "env_type" in kwargs
assert kwargs.get("env_type") in ["gym", "dm", "gymnasium"]

Check warning on line 32 in openrl/envs/envpool/__init__.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/envpool/__init__.py#L31-L32

Added lines #L31 - L32 were not covered by tests
# Since render_mode is not supported, we set envpool to True
# so that we can remove render_mode keyword argument from build_envs
assert render_mode is None, "envpool does not support render_mode yet"
kwargs["envpool"] = True

Check warning on line 36 in openrl/envs/envpool/__init__.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/envpool/__init__.py#L35-L36

Added lines #L35 - L36 were not covered by tests

env_wrappers = kwargs.pop("env_wrappers")
env_fns = build_envs(

Check warning on line 39 in openrl/envs/envpool/__init__.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/envpool/__init__.py#L38-L39

Added lines #L38 - L39 were not covered by tests
make=envpool.make,
id=id,
env_num=env_num,
render_mode=render_mode,
wrappers=env_wrappers,
**kwargs,
)
return env_fns

Check warning on line 47 in openrl/envs/envpool/__init__.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/envpool/__init__.py#L47

Added line #L47 was not covered by tests
182 changes: 182 additions & 0 deletions openrl/envs/wrappers/envpool_wrappers.py
Copy link
Member

Choose a reason for hiding this comment

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

should move to examples/envpool

Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
import time
import warnings
from typing import Optional

Check warning on line 3 in openrl/envs/wrappers/envpool_wrappers.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/wrappers/envpool_wrappers.py#L1-L3

Added lines #L1 - L3 were not covered by tests

import gym
import gymnasium
import numpy as np
from envpool.python.protocol import EnvPool
from packaging import version
from stable_baselines3.common.vec_env import VecEnvWrapper as BaseWrapper
from stable_baselines3.common.vec_env import VecMonitor
from stable_baselines3.common.vec_env.base_vec_env import (VecEnvObs,

Check warning on line 12 in openrl/envs/wrappers/envpool_wrappers.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/wrappers/envpool_wrappers.py#L5-L12

Added lines #L5 - L12 were not covered by tests
VecEnvStepReturn)

is_legacy_gym = version.parse(gym.__version__) < version.parse("0.26.0")

Check warning on line 15 in openrl/envs/wrappers/envpool_wrappers.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/wrappers/envpool_wrappers.py#L15

Added line #L15 was not covered by tests


class VecEnvWrapper(BaseWrapper):
@property
def agent_num(self):
if self.is_original_envpool_env():
return 1

Check warning on line 22 in openrl/envs/wrappers/envpool_wrappers.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/wrappers/envpool_wrappers.py#L18-L22

Added lines #L18 - L22 were not covered by tests
else:
return self.env.agent_num

Check warning on line 24 in openrl/envs/wrappers/envpool_wrappers.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/wrappers/envpool_wrappers.py#L24

Added line #L24 was not covered by tests

def is_original_envpool_env(self):
return not hasattr(self.venv, "agent_num`")

Check warning on line 27 in openrl/envs/wrappers/envpool_wrappers.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/wrappers/envpool_wrappers.py#L26-L27

Added lines #L26 - L27 were not covered by tests


class VecAdapter(VecEnvWrapper):

Check warning on line 30 in openrl/envs/wrappers/envpool_wrappers.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/wrappers/envpool_wrappers.py#L30

Added line #L30 was not covered by tests
"""
Convert EnvPool object to a Stable-Baselines3 (SB3) VecEnv.

:param venv: The envpool object.
"""

def __init__(self, venv: EnvPool):
venv.num_envs = venv.spec.config.num_envs
observation_space = venv.observation_space
new_observation_space = gymnasium.spaces.Box(

Check warning on line 40 in openrl/envs/wrappers/envpool_wrappers.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/wrappers/envpool_wrappers.py#L37-L40

Added lines #L37 - L40 were not covered by tests
low=observation_space.low,
high=observation_space.high,
dtype=observation_space.dtype,
)
action_space = venv.action_space
if isinstance(action_space, gym.spaces.Discrete):
new_action_space = gymnasium.spaces.Discrete(action_space.n)
elif isinstance(action_space, gym.spaces.MultiDiscrete):
new_action_space = gymnasium.spaces.MultiDiscrete(action_space.nvec)
elif isinstance(action_space, gym.spaces.MultiBinary):
new_action_space = gymnasium.spaces.MultiBinary(action_space.n)
elif isinstance(action_space, gym.spaces.Box):
new_action_space = gymnasium.spaces.Box(

Check warning on line 53 in openrl/envs/wrappers/envpool_wrappers.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/wrappers/envpool_wrappers.py#L45-L53

Added lines #L45 - L53 were not covered by tests
low=action_space.low,
high=action_space.high,
dtype=action_space.dtype,
)
else:
raise NotImplementedError(f"Action space {action_space} is not supported")
super().__init__(

Check warning on line 60 in openrl/envs/wrappers/envpool_wrappers.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/wrappers/envpool_wrappers.py#L59-L60

Added lines #L59 - L60 were not covered by tests
venv=venv,
observation_space=new_observation_space,
action_space=new_action_space,
)

def step_async(self, actions: np.ndarray) -> None:
self.actions = actions

Check warning on line 67 in openrl/envs/wrappers/envpool_wrappers.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/wrappers/envpool_wrappers.py#L66-L67

Added lines #L66 - L67 were not covered by tests

def reset(self) -> VecEnvObs:
if is_legacy_gym:
return self.venv.reset(), {}

Check warning on line 71 in openrl/envs/wrappers/envpool_wrappers.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/wrappers/envpool_wrappers.py#L69-L71

Added lines #L69 - L71 were not covered by tests
else:
return self.venv.reset()

Check warning on line 73 in openrl/envs/wrappers/envpool_wrappers.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/wrappers/envpool_wrappers.py#L73

Added line #L73 was not covered by tests

def step_wait(self) -> VecEnvStepReturn:
if is_legacy_gym:
obs, rewards, dones, info_dict = self.venv.step(self.actions)

Check warning on line 77 in openrl/envs/wrappers/envpool_wrappers.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/wrappers/envpool_wrappers.py#L75-L77

Added lines #L75 - L77 were not covered by tests
else:
obs, rewards, terms, truncs, info_dict = self.venv.step(self.actions)
dones = terms + truncs
rewards = rewards
infos = []
for i in range(self.num_envs):
infos.append(

Check warning on line 84 in openrl/envs/wrappers/envpool_wrappers.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/wrappers/envpool_wrappers.py#L79-L84

Added lines #L79 - L84 were not covered by tests
{
key: info_dict[key][i]
for key in info_dict.keys()
if isinstance(info_dict[key], np.ndarray)
}
)
if dones[i]:
infos[i]["terminal_observation"] = obs[i]
if is_legacy_gym:
obs[i] = self.venv.reset(np.array([i]))

Check warning on line 94 in openrl/envs/wrappers/envpool_wrappers.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/wrappers/envpool_wrappers.py#L91-L94

Added lines #L91 - L94 were not covered by tests
else:
obs[i] = self.venv.reset(np.array([i]))[0]
return obs, rewards, dones, infos

Check warning on line 97 in openrl/envs/wrappers/envpool_wrappers.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/wrappers/envpool_wrappers.py#L96-L97

Added lines #L96 - L97 were not covered by tests


class VecMonitor(VecEnvWrapper):
def __init__(

Check warning on line 101 in openrl/envs/wrappers/envpool_wrappers.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/wrappers/envpool_wrappers.py#L100-L101

Added lines #L100 - L101 were not covered by tests
self,
venv,
filename: Optional[str] = None,
info_keywords=(),
):
# Avoid circular import
from stable_baselines3.common.monitor import Monitor, ResultsWriter

Check warning on line 108 in openrl/envs/wrappers/envpool_wrappers.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/wrappers/envpool_wrappers.py#L108

Added line #L108 was not covered by tests

try:
is_wrapped_with_monitor = venv.env_is_wrapped(Monitor)[0]
except AttributeError:
is_wrapped_with_monitor = False

Check warning on line 113 in openrl/envs/wrappers/envpool_wrappers.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/wrappers/envpool_wrappers.py#L110-L113

Added lines #L110 - L113 were not covered by tests

if is_wrapped_with_monitor:
warnings.warn(

Check warning on line 116 in openrl/envs/wrappers/envpool_wrappers.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/wrappers/envpool_wrappers.py#L115-L116

Added lines #L115 - L116 were not covered by tests
"The environment is already wrapped with a `Monitor` wrapper"
"but you are wrapping it with a `VecMonitor` wrapper, the `Monitor` statistics will be"
"overwritten by the `VecMonitor` ones.",
UserWarning,
)

VecEnvWrapper.__init__(self, venv)
self.episode_count = 0
self.t_start = time.time()

Check warning on line 125 in openrl/envs/wrappers/envpool_wrappers.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/wrappers/envpool_wrappers.py#L123-L125

Added lines #L123 - L125 were not covered by tests

env_id = None
if hasattr(venv, "spec") and venv.spec is not None:
env_id = venv.spec.id

Check warning on line 129 in openrl/envs/wrappers/envpool_wrappers.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/wrappers/envpool_wrappers.py#L127-L129

Added lines #L127 - L129 were not covered by tests

self.results_writer: Optional[ResultsWriter] = None
if filename:
self.results_writer = ResultsWriter(

Check warning on line 133 in openrl/envs/wrappers/envpool_wrappers.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/wrappers/envpool_wrappers.py#L131-L133

Added lines #L131 - L133 were not covered by tests
filename,
header={"t_start": self.t_start, "env_id": str(env_id)},
extra_keys=info_keywords,
)

self.info_keywords = info_keywords
self.episode_returns = np.zeros(self.num_envs, dtype=np.float32)
self.episode_lengths = np.zeros(self.num_envs, dtype=np.int32)

Check warning on line 141 in openrl/envs/wrappers/envpool_wrappers.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/wrappers/envpool_wrappers.py#L139-L141

Added lines #L139 - L141 were not covered by tests

def reset(self, **kwargs) -> VecEnvObs:
obs, info = self.venv.reset()
self.episode_returns = np.zeros(self.num_envs, dtype=np.float32)
self.episode_lengths = np.zeros(self.num_envs, dtype=np.int32)
return obs, info

Check warning on line 147 in openrl/envs/wrappers/envpool_wrappers.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/wrappers/envpool_wrappers.py#L143-L147

Added lines #L143 - L147 were not covered by tests

def step_wait(self) -> VecEnvStepReturn:
obs, rewards, dones, infos = self.venv.step_wait()
self.episode_returns += rewards
self.episode_lengths += 1
new_infos = list(infos[:])
for i in range(len(dones)):
if dones[i]:
info = infos[i].copy()
episode_return = self.episode_returns[i]
episode_length = self.episode_lengths[i]
episode_info = {

Check warning on line 159 in openrl/envs/wrappers/envpool_wrappers.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/wrappers/envpool_wrappers.py#L149-L159

Added lines #L149 - L159 were not covered by tests
"r": episode_return,
"l": episode_length,
"t": round(time.time() - self.t_start, 6),
}
for key in self.info_keywords:
episode_info[key] = info[key]
info["episode"] = episode_info
self.episode_count += 1
self.episode_returns[i] = 0
self.episode_lengths[i] = 0
if self.results_writer:
self.results_writer.write_row(episode_info)
new_infos[i] = info
rewards = np.expand_dims(rewards, 1)
return obs, rewards, dones, new_infos

Check warning on line 174 in openrl/envs/wrappers/envpool_wrappers.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/wrappers/envpool_wrappers.py#L164-L174

Added lines #L164 - L174 were not covered by tests

def close(self) -> None:
if self.results_writer:
self.results_writer.close()
return self.venv.close()

Check warning on line 179 in openrl/envs/wrappers/envpool_wrappers.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/wrappers/envpool_wrappers.py#L176-L179

Added lines #L176 - L179 were not covered by tests


__all__ = ["VecAdapter", "VecMonitor"]

Check warning on line 182 in openrl/envs/wrappers/envpool_wrappers.py

View check run for this annotation

Codecov / codecov/patch

openrl/envs/wrappers/envpool_wrappers.py#L182

Added line #L182 was not covered by tests
2 changes: 2 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ def get_extra_requires() -> dict:
"async_timeout",
"pettingzoo[classic]",
"trueskill",
"envpool",
Copy link
Member

Choose a reason for hiding this comment

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

delete this. Add a README.md in examples/envpool. And show how to install dependencies in the markdown.

],
"selfplay_test": [
"ray[default]>=2.7",
Expand All @@ -84,6 +85,7 @@ def get_extra_requires() -> dict:
"fastapi",
"pettingzoo[mpe]",
"pettingzoo[butterfly]",
"envpool",
Copy link
Member

Choose a reason for hiding this comment

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

delete this. Add a README.md in examples/envpool. And show how to install dependencies in the markdown.

],
"retro": ["gym-retro"],
"super_mario": ["gym-super-mario-bros"],
Expand Down