此时,可以出现模型的图示:
其输入是动作a,输出是:下一步状态,立即回报,是否终止,调试项。该函数描述了智能体与环境交互的所有信息,是环境文件中最重要的函数。在该函数中,一般利用智能体的运动学模型和动力学模型计算下一步的状态和立即回报,并判断是否达到终止状态。
def _step(self, action): assert self.action_space.contains(action), "%r (%s) invalid"%(action, type(action)) state = self.state x, x_dot, theta, theta_dot = state #系统的当前状态 force = self.force_mag if action==1 else -self.force_mag #输入动作,即作用到车上的力 costheta = math.cos(theta) #余弦函数 sintheta = math.sin(theta) #正弦函数 #以下是车摆的动力学方程式,即加速度与动作之间的关系。 temp = (force + self.polemass_length * theta_dot * theta_dot * sintheta) / self.total_mass thetaacc = (self.gravity * sintheta - costheta* temp) / (self.length * (4.0/3.0 - self.masspole * costheta * costheta / self.total_mass)) #摆的角加速度 xacc = temp - self.polemass_length * thetaacc * costheta / self.total_mass #小车的平移加速 x = x + self.tau * x_dot x_dot = x_dot + self.tau * xacc theta = theta + self.tau * theta_dot theta_dot = theta_dot + self.tau * thetaacc #积分求下一步的状态 self.state = (x,x_dot,theta,theta_dot)参考gym中经典的CartPole环境代码CartPole.py,我们逐步构建自定义环境。
将要创建的是一个在二维水平面上移动的小车。该二维区域长宽各20单位。区域中心为坐标原点,也是小车要到达的目的地。
动作:小车每次只能选择不动或向四周移动一个单位。 状态:小车的横纵坐标。 奖励:小车到达目的地周围有+10的奖励;每移动一个单位有-0.1的奖励,这表示我们希望小车尽量以较少的时间(移动次数)到达终点;小车移动到区域外的奖励为-50。
首先新建一个Car2D.py的文件,需要import的包如下:
import gym from gym import spaces import numpy as np声明一个Car2DEnv的类,它是gym.Env的子类。它一般包括的内容如下: The minimal required interface for an environment is composed of the __init__, reset, step, render and close routines.
class Car2DEnv(gym.Env): metadata = { 'render.modes': ['human', 'rgb_array'], 'video.frames_per_second': 2 } def __init__(self): self.action_space = None self.observation_space = None pass def step(self, action): return self.state, reward, done, {} def reset(self): return self.state def render(self, mode='human'): return None def close(self): return None必须实现的内容: __init__():将会初始化动作空间与状态空间,便于强化学习算法在给定的状态空间中搜索合适的动作。gym提供了spaces方法,详细内容可以help查看;
step():用于编写智能体与环境交互的逻辑,它接受action的输入,给出下一时刻的状态、当前动作的回报、是否结束当前episode及调试信息。输入action由__init__()函数中的动作空间给定。我们规定当action为0表示小车不动,当action为1,2,3,4时分别是向上、下、左、右各移动一个单位。据此可以写出小车坐标的更新逻辑;
reset():用于在每轮开始之前重置智能体的状态。
不是必须实现的但有助于调试算法的内容: metadata、render()、close()是与图像显示有关的,我们不涉及这一部分。
完整的Car2D.py代码如下
# -*- coding: utf-8 -*- import gym from gym import spaces import numpy as np class Car2DEnv(gym.Env): metadata = { 'render.modes': ['human', 'rgb_array'], 'video.frames_per_second': 2 } def __init__(self): self.xth = 0 self.target_x = 0 self.target_y = 0 self.L = 10 self.action_space = spaces.Discrete(5) # 0, 1, 2,3,4: 不动,上下左右 self.observation_space = spaces.Box(np.array([self.L, self.L]), np.array([self.L, self.L])) self.state = None def step(self, action): assert self.action_space.contains(action), "%r (%s) invalid"%(action, type(action)) x, y = self.state if action == 0: x = x y = y if action == 1: x = x y = y + 1 if action == 2: x = x y = y - 1 if action == 3: x = x - 1 y = y if action == 4: x = x + 1 y = y self.state = np.array([x, y]) self.counts += 1 done = (np.abs(x)+np.abs(y) <= 1) or (np.abs(x)+np.abs(y) >= 2*self.L+1) done = bool(done) if not done: reward = -0.1 else: if np.abs(x)+np.abs(y) <= 1: reward = 10 else: reward = -50 return self.state, reward, done, {} def reset(self): self.state = np.ceil(np.random.rand(2)*2*self.L)-self.L self.counts = 0 return self.state def render(self, mode='human'): return None def close(self): return None if __name__ == '__main__': env = Car2DEnv() env.reset() env.step(env.action_space.sample()) print(env.state) env.step(env.action_space.sample()) print(env.state) 参考:https://www.zhihu.com/collection/581976137 https://www.zhihu.com/question/58126239
