在强化学习中环境(environment)是与agent进行交互的重要部分,虽然OpenAI gym中有提供多种的环境,但是有时我们需要自己创建训练用的环境。这个文章主要用于介绍和记录我作为一个初学者对如何用gym创建训练环境的学习过程。其中会包含如何使用OpenAI gym提供的Function和Class以及创建环境的格式。
例子:
from gym import spaces
# 规定action space最小值,最大值以及维度
action_space1 = spaces.Box(low=-1, high=1, shape=(1, ))
# 也可以输入向量,这样space输出的值会与输入向量具有相同维度,不需要另外规定维度(low和high要具有相同维度)
low = np.float32(np.zeros(3))
high = np.float32(np.ones(3))
action_space2 = spaces.Box(low=low,high=high)
# 随机进行采样,观察输出结果
print(action_space1.sample())
print(action_space2.sample())
输出结果:
[0.17719302]
[0.09906013 0.6137293 0.5404117 ]
注意: 如果输入的上下限为np.float64,那么会出现warning:UserWarning: WARN: Box bound precision lowered by casting to float32
,因此可以将输入改为np.float32
例子:
# 规定action space中总共有几个动作
# 例如在有名的例子“cartpole”中小车只有两个action选项:向左或向右,因此将数值设为2,则输出会为0或1
action_space = spaces.Discrete(2)
# 测试输出结果
for i in range(5):
print(action_space.sample())
输出结果:
0
1
1
1
1
例子:
low = np.float32(np.zeros(3))
high = np.float32(np.ones(3))
# 创建有两个不同action的action space
action_space = spaces.Dict({
"action1": spaces.Discrete(10),
"action2": spaces.Box(low=low,high=high)
})
print(action_space.sample())
输出结果:
OrderedDict([('action1', 6), ('action2', array([0.23961447, 0.6493422 , 0.267231 ], dtype=float32))])
可以看到action space中有 action1 和 action2 两个action
import gym
from gym.utils import seeding
# gym.Env是主要的OpenAI Gym class,其中含有多个API,若要构建自己的环境,需要重写这些API
# Main API: step, reset, render, close, seed,每个部分的作用会写在下面
class MyEnv(gym.Env):
# 根据需要自己定义环境的名字
def __init__(self):
# 这个部分用于定义MyEnv的各种属性,包括action space, observation space, gravity(cartpole)
...
self.action_space = spaces.Discrete(2)
self.observation_space = spaces.Box(low=np.float32(np.zeros(3)),high=np.float32(np.ones(3)))
def reset(self):
# 重置环境,用于新的episode,需要返回observation (initial state)
...
obs = self.get_obs()
return obs
def render(self):
# 如果要进行可视化,可以实现
def seed(self, seed=None):
# 设置此环境随机数生成器seed
self.np_random, seed = seeding.np_random(seed)
return [seed]
def step(self):
# 描述环境根据agent的动作发生什么样的改变,即环境对agents' action的反馈
# 需要返回observation, reward (one step),
# done (True/False), training information (用于记录训练过程中的环境信息)
...
obs = self.get_obs()
reward = self.get_reward()
done = self.get_done()
info = {}
return obs, reward, done, info
# 根据训练需要自定义函数
def get_obs(self):
...
return obs
def get_reward(self):
...
return reward
def get_done(self):
...
return done
这部分用于记录我在看别人构建的环境中学到的小tips
scipy.linalg.block_diag()
将多个矩阵合并为一个单独的对角矩阵,方便在step()中进行计算。我原本的方法是将每个对象保存的list中,list[i]对应第i个对象,这样容易造成step()中的代码过于冗长且要话费更多的计算时间,因为每次要调用多个对象时都需要写一个循环。scipy.linalg.block_diag()
介绍:https://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.block_diag.htmlnumpy.ndarray.flatten
介绍:https://numpy.org/doc/stable/reference/generated/numpy.ndarray.flatten.html