提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
本文主要对搭建自己的gym训练环境做一个详细介绍
gym主页
gym官方入门文档
环境中主要有六个模块,下面将主要以官方的MountainCarEnv为例对每个模块进行说明。
主要作用是初始化一些参数
如在MountainCarEnv中,对car的位置大小重量做了定义,对推力大小,动作空间,观测空间做了定义。
def __init__(self, goal_velocity=0):
self.min_position = -1.2
self.max_position = 0.6
self.max_speed = 0.07
self.goal_position = 0.5
self.goal_velocity = goal_velocity
self.force = 0.001
self.gravity = 0.0025
self.low = np.array([self.min_position, -self.max_speed], dtype=np.float32)
self.high = np.array([self.max_position, self.max_speed], dtype=np.float32)
self.viewer = None
self.action_space = spaces.Discrete(3)
self.observation_space = spaces.Box(self.low, self.high, dtype=np.float32)
self.seed()
self.action_space = spaces.Discrete(3)
这里的action_space是指动作空间,在此环境中有三个动作空间,向左,不动,向右。
self.observation_space = spaces.Box()
这里指观测空间,环境中所能观测到的范围。
设置随机种子列表
可以不设随机,但必须有这个模块。
def seed(self, seed=None):
self.np_random, seed = seeding.np_random(seed)
return [seed]
该函数在仿真器中扮演物理引擎的角色,利用智能体的运动学模型和动力学模型计算下一步的状态和立即回报,并判断是否达到终止状态。其输入是动作action,输出是:下一步状态,立即回报,是否终止,调试项。
以MountainCarEnv为例
def step(self, action):
assert self.action_space.contains(action), "%r (%s) invalid" % (
action,
type(action),
)
position, velocity = self.state
velocity += (action - 1) * self.force + math.cos(3 * position) * (-self.gravity)
velocity = np.clip(velocity, -self.max_speed, self.max_speed)
position += velocity
position = np.clip(position, self.min_position, self.max_position)
if position == self.min_position and velocity < 0:
velocity = 0
done = bool(position >= self.goal_position and velocity >= self.goal_velocity)
reward = -1.0
self.state = (position, velocity)
return np.array(self.state, dtype=np.float32), reward, done, {}
cartpole中step函数部分代码
done = bool(
x < -self.x_threshold
or x > self.x_threshold
or theta < -self.theta_threshold_radians
or theta > self.theta_threshold_radians
)
if not done:
reward = 1.0
elif self.steps_beyond_done is None:
# Pole just fell!
self.steps_beyond_done = 0
reward = 1.0
else:
if self.steps_beyond_done == 0:
logger.warn(
"You are calling 'step()' even though this "
"environment has already returned done = True. You "
"should always call 'reset()' once you receive 'done = "
"True' -- any further steps are undefined behavior."
)
self.steps_beyond_done += 1
reward = 0.0
首先是将position, velocity
从self.state
取出(这里的初始值将在下一个reset函数中对其进行初始化),然后根据运动学方程以及动力学方程对状态进行更新。
done
是用来判断智能体的状态是否符合所需,如MountainCar中的是判断是否到达终点以及是否到达指定速度;cartpole中判断cart是否超出左右界限,以及pole的摆动角度是否超过限制。
reward
奖励函数,这里仅对每步进行惩罚以求最快到达山顶,在cartpole中是对每步进行奖励以能使倒立摆保持平衡最长时间。
reward函数可以自己进行改进,如在MountainCar中加入对距离目标的奖励,距离目标越近,奖励越大,可以加快训练速度。
return np.array(self.state, dtype=np.float32), reward, done, {}
函数的返回值包括了智能体的下一个状态,奖励值,完成状态和一个调试接口。state包含智能体的运动学方程信息,在编写自己的智能体时可将所需的信息都加入其中,如无人机可加入俯仰角,xyz空间位置,速度,加速度等参数。
将系统状态随机初始化,返回observation:状态信息(不参与网络的计算)
注意: step中的state需要几个参数,这里就需要初始化几个参数。
def reset(self):
self.state = np.array([self.np_random.uniform(low=-0.6, high=-0.4), 0])
return np.array(self.state, dtype=np.float32)
绘图函数,可以为空,但必须存在
screen_width = 600
screen_height = 400
world_width = self.max_position - self.min_position
scale = screen_width / world_width
carwidth = 40
carheight = 20
if self.viewer is None:
from gym.envs.classic_control import rendering
self.viewer = rendering.Viewer(screen_width, screen_height)
xs = np.linspace(self.min_position, self.max_position, 100)
ys = self._height(xs)
xys = list(zip((xs - self.min_position) * scale, ys * scale))
self.track = rendering.make_polyline(xys)
self.track.set_linewidth(4)
self.viewer.add_geom(self.track)
clearance = 10
l, r, t, b = -carwidth / 2, carwidth / 2, carheight, 0
car = rendering.FilledPolygon([(l, b), (l, t), (r, t), (r, b)])
car.add_attr(rendering.Transform(translation=(0, clearance)))
self.cartrans = rendering.Transform()
car.add_attr(self.cartrans)
self.viewer.add_geom(car)
frontwheel = rendering.make_circle(carheight / 2.5)
frontwheel.set_color(0.5, 0.5, 0.5)
frontwheel.add_attr(
rendering.Transform(translation=(carwidth / 4, clearance))
)
frontwheel.add_attr(self.cartrans)
self.viewer.add_geom(frontwheel)
backwheel = rendering.make_circle(carheight / 2.5)
backwheel.add_attr(
rendering.Transform(translation=(-carwidth / 4, clearance))
)
backwheel.add_attr(self.cartrans)
backwheel.set_color(0.5, 0.5, 0.5)
self.viewer.add_geom(backwheel)
flagx = (self.goal_position - self.min_position) * scale
flagy1 = self._height(self.goal_position) * scale
flagy2 = flagy1 + 50
flagpole = rendering.Line((flagx, flagy1), (flagx, flagy2))
self.viewer.add_geom(flagpole)
flag = rendering.FilledPolygon(
[(flagx, flagy2), (flagx, flagy2 - 10), (flagx + 25, flagy2 - 5)]
)
flag.set_color(0.8, 0.8, 0)
self.viewer.add_geom(flag)
pos = self.state[0]
self.cartrans.set_translation(
(pos - self.min_position) * scale, self._height(pos) * scale
)
self.cartrans.set_rotation(math.cos(3 * pos))
return self.viewer.render(return_rgb_array=mode == "rgb_array")
一般开头是对画布的大小,以及智能体进行设定。可通过rendering.Line
画线, rendering.make_circle(10)
画圆, rendering.Transform()
添加旋转平移属性等。功能还是比较强大。
训练时不要每次都调用绘图,会极大减慢训练效率,可等训练奖励达到一定,然后开始调用绘图查看训练效果。
关闭图形界面
def close(self):
if self.viewer:
self.viewer.close()
self.viewer = None
打开.\Lib\site-packages\gym\envs\__init__.py
在其中加入如下代码段,对自定义的环境进行注册
这里的id以及point 的最后要改为自己的环境名称
# user
# ---------
register(
id='GridWorld-v1',
entry_point='gym.envs.user:GridEnv1',
max_episode_steps=200,
reward_threshold=100.0,
)
打开\Lib\site-packages\gym\envs
在这里新建user文件夹,并在user文件夹中新建__init__.py
文件
在init.py文件中加入如下代码
from gym.envs.user.grid_mdp_v1 import GridEnv1
将写好的env文件放入user文件夹中,命名为grid_mdp_v1
这里的grid都是自己来命名,注意更改。
在项目中新建main.py
import gym
import numpy as np
import time
import sys
env = gym.make('GridWorld-v1')
env.reset() # 初始化本场游戏的环境
env.render() # 更新并渲染游戏画面
time.sleep(10)
env.close()
sys.exit()
利用env = gym.make('GridWorld-v1')
将我们自己的环境导入。
运行可以看到所写的环境渲染出来。