文章目录

  • 前言
  • 一、构建自己的gym训练环境
    • 1. __init __
    • 2. seed
    • 3. step
    • 4. reset
    • 5. render
    • 6. closer
  • 二、将训练环境添加到库中
    • 1.注册
    • 2.放入库中
    • 3. 测试

前言

本文主要对搭建自己的gym训练环境做一个详细介绍
gym主页
gym官方入门文档


一、构建自己的gym训练环境

环境中主要有六个模块,下面将主要以官方的MountainCarEnv为例对每个模块进行说明。

1. __init __

主要作用是初始化一些参数

如在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()这里指观测空间,环境中所能观测到的范围。

2. seed

设置随机种子列表
可以不设随机,但必须有这个模块。

    def seed(self, seed=None):        self.np_random, seed = seeding.np_random(seed)        return [seed]

3. step

该函数在仿真器中扮演物理引擎的角色,利用智能体的运动学模型和动力学模型计算下一步的状态和立即回报,并判断是否达到终止状态。其输入是动作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, velocityself.state取出(这里的初始值将在下一个reset函数中对其进行初始化),然后根据运动学方程以及动力学方程对状态进行更新。
done是用来判断智能体的状态是否符合所需,如MountainCar中的是判断是否到达终点以及是否到达指定速度;cartpole中判断cart是否超出左右界限,以及pole的摆动角度是否超过限制。
reward奖励函数,这里仅对每步进行惩罚以求最快到达山顶,在cartpole中是对每步进行奖励以能使倒立摆保持平衡最长时间。
reward函数可以自己进行改进,如在MountainCar中加入对距离目标的奖励,距离目标越近,奖励越大,可以加快训练速度。
return np.array(self.state, dtype=np.float32), reward, done, {}函数的返回值包括了智能体的下一个状态,奖励值,完成状态和一个调试接口。state包含智能体的运动学方程信息,在编写自己的智能体时可将所需的信息都加入其中,如无人机可加入俯仰角,xyz空间位置,速度,加速度等参数。

4. reset

将系统状态随机初始化,返回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)

5. render

绘图函数,可以为空,但必须存在

        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()添加旋转平移属性等。功能还是比较强大。

训练时不要每次都调用绘图,会极大减慢训练效率,可等训练奖励达到一定,然后开始调用绘图查看训练效果。

6. closer

关闭图形界面

    def close(self):        if self.viewer:            self.viewer.close()            self.viewer = None

二、将训练环境添加到库中

1.注册

打开.\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,    )

2.放入库中

打开\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都是自己来命名,注意更改。

3. 测试

在项目中新建main.py

import gymimport numpy as npimport timeimport sysenv = gym.make('GridWorld-v1')env.reset()   # 初始化本场游戏的环境env.render()    # 更新并渲染游戏画面time.sleep(10)env.close()sys.exit()

利用env = gym.make('GridWorld-v1')将我们自己的环境导入。
运行可以看到所写的环境渲染出来。