“他山之石,可以攻玉”,站在巨人的肩膀才能看得更高,走得更远。在科研的道路上,更需借助东风才能更快前行。为此,我们特别搜集整理了一些实用的代码链接,数据集,软件,编程技巧等,开辟“他山之石”专栏,助你乘风破浪,一路奋勇向前,敬请关注。
转自:https://www.meltycriss.com/2018/03/26/tech-gym/
01
# main.py
import gym
def choose_action(o):
...
env = gym.make('CartPole-v0')
o = env.reset()
while True:
a = choose_action(o)
o_, r, done, info = env.step(a)
o = o_
if done:
break
env = gym.make('CartPole-v0')
env.reset()
env.step(a)
# gym/core.py
class Env(object):
...
# Override in ALL subclasses
def _step(self, action): raise NotImplementedError
def _reset(self): raise NotImplementedError
...
def step(self, action):
return self._step(action)
def reset(self):
return self._reset()
...
# gym/envs/classic_control/CartPole.py
class CartPoleEnv(gym.Env):
...
def _step(self, action):
...
def _reset(self):
...
...
# gym/envs/registration.py
# Have a global registry
registry = EnvRegistry()
...
def make(id):
return registry.make(id)
# gym/envs/registration.py
class EnvRegistry(object):
def __init__(self):
# 注册表
# key: 环境名称(e.g., 'CartPole-v0')
# value:类型为EnvSpec,可以暂时理解为环境
self.env_specs = {}
def make(self, id):
...
# 根据环境名称,通过成员函数找到对应的环境
spec = self.spec(id)
# 实例化环境
env = spec.make()
...
return env
...
def spec(self, id):
...
...
# gym/envs/registration.py
def load(name):
...
# EnvSpec与Env之间的关系类似于说明商品规格的订单与商品之间的关系,
# 下面用一个例子来说明:
# 假设你网购看中了一款衣服,那么你会挑选该款衣服的颜色、码数,然后再下单。
# 在这个例子里面,那款衣服就是Env,而说明该款衣服颜色、码数的订单就是EnvSpec。
# 这就是为什么EnvRegistry.make(self, id)中,在得到spec之后还要再spec.make(),
# 因为EnvSpec并不是Env,正如订单不是衣服。
class EnvSpec(object):
def __init__(self, id, entry_point=None, ...):
self.id = id
...
self._entry_point = entry_point
...
def make(self):
...
# 动态加载环境类
# 相当于以下代码
# from self._entry_point import classA
# cls = classA
cls = load(self._entry_point)
# 实例化环境
env = cls(**self._kwargs)
...
return env
...
gym.make(id):通过EnvRegistry中的注册表找到对应的EnvSpec,EnvSpec根据entry_point动态import对应的Env,并将其实例化; env.reset()和env.step(a):子类的_reset(self)和_step(self, action)。
02
第一个是搭建自己的Env子类FooEnv; 第二个是注册FooEnv(i.e., 将FooEnv添加到registry.env_specs中),使得gym.make(id)可以找到FooEnv。
gym-foo/
README.md
setup.py #将gym_foo这个package加到系统环境变量中
gym_foo/ #核心部分
__init__.py #注册FooEnv
envs/
__init__.py
foo_env.py #实现FooEnv
# gym-foo/gym_foo/__init__.py
from gym.envs.registration import register
register(
id='foo-v0', # 环境名
entry_point='gym_foo.envs:FooEnv', # 环境类,之后就根据这个路径动态import环境
)
# gym/envs/registration.py
# Have a global registry
registry = EnvRegistry()
# Gym的注册环境API
def register(id, **kwargs):
return registry.register(id, **kwargs)
def make(id):
return registry.make(id)
# gym/envs/registration.py
class EnvRegistry(object):
...
def register(self, id, **kwargs):
...
# 将FooEnv对应的“订单”写到“注册表”上
self.env_specs[id] = EnvSpec(id, **kwargs)
03
3.1 server render
# main.py
import gym
from gym import wrappers
env = gym.make('CartPole-v0')
env = wrappers.Monitor(env, 'video')
for i_episode in range(20):
observation = env.reset()
for t in range(100):
env.render()
action = env.action_space.sample()
observation, reward, done, info = env.step(action)
if done:
break
3.2 保存每一段episode的录像
env = wrappers.Monitor(env, 'video', video_callable=lambda episode_id: True)
3.3 动态修改episode的最大step
3.4 关于wrapper
相同的两个wrapper不能叠加(e.g., Monitor不可以和Monitor叠加,但是Monitor可以和TimeLimit叠加),否则会报double wrapper的错。 在注册FooEnv时,加不加max_episode_steps=xxx会影响返回的Env的类型。假如加了,返回的是TimeLimit类型的wrapper;假如不加,返回的就是裸的FooEnv。 Monitor里面有两个recorder,一个是stat_recorder,用于保存数据(reward之类的);另一个是video_recorder,用于录像。Monitor会在每一次调用env.reset和env.step之后调用render
3.5 屏蔽log信息
# main.py
import logging
# suppress INFO level logging 'Making new env: ...'
logging.getLogger('gym.envs.registration').setLevel(logging.WARNING)
# suppress INFO level logging 'Starting new video recorder writing to ...'
logging.getLogger('gym.monitoring.video_recorder').setLevel(logging.WARNING)
# suppress INFO level logging 'Creating monitor directory ...'
logging.getLogger('gym.wrappers.monitoring').setLevel(logging.WARNING)
“他山之石”历史文章
更多他山之石专栏文章,
请点击文章底部“阅读原文”查看
分享、点赞、在看,给个三连击呗!