构建自己的gym训练环境 巨详细

提示:文章写完后,可以自动生成目录。生成方法请参考右侧帮助文档

前言

本文主要对搭建自己的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()添加旋转和平移属性。功能还是比较强大的。

训练时不要每次都调用drawing,这样会大大降低训练效率。可以等待训练奖励达到一定等级,然后开始调用抽签查看训练效果。

6. closer

关闭图形用户界面

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

2. 将训练环境添加到库中

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 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')导入我们自己的环境。
运行它以查看呈现的书面环境。

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
青葱年少的头像青葱年少普通用户
上一篇 2022年3月16日 上午10:53
下一篇 2022年3月16日 上午11:14

相关推荐