【五】gym搭建自己的环境之寻宝游戏,详细定义自己myenv.py文件以及算法实现
相关文章:
相关文章:
【四】gym搭建自己的环境,全网最详细版本,3分钟你就学会了!
【五】gym搭建自己的环境____详细定义自己myenv.py文件
【六】gym搭建自己环境升级版设计,动态障碍------强化学习
环境文件下载地址:丨汀/MyEnv {目前暂未更新}
gym搭建自己的环境之详细定义自己myenv.py文件
1.模板化环境编程(统一环境代码框架)
通过上篇文章我们已经可以注册搭建自己环境了,下面开始详细构建自己的myenv.py文件,还有疑问请看文章【四】。
- 首先需要定义自己的环境myenv.py,其代码框架如下:
import gym
"""
gym.Env是gym的环境基类,自定义的环境就是根据自己的需要重写其中的方法;
必须要重写的方法有:
__init__():构造函数
reset():初始化环境
step():环境动作,即环境对agent的反馈
render():如果要进行可视化则实现
"""
class MyEnv(gym.Env):
- 函数reset()作用:智能体需要一次次地尝试累积经验,然后从经验中学到好的动作。一次尝试称之为一条轨迹或一个episode. 每次尝试都要到达终止状态. 一次尝试结束后,智能体需要从头开始,这就需要智能体具有重新初始化的功能。
- 一个仿真环境必不可少的两部分是物理引擎和图像引擎。物理引擎模拟环境中物体的运动规律;图像引擎用来显示环境中的物体图像
· render()函数作用:起到图像引擎作用,对于强化学习算法渲染函数可以没有,但是加入图像引擎可以方便调试代码时直观显示当前环境中物体的状态。
·step()函数作用:起到物理引擎,其输入是动作a,输出是:下一步状态,立即回报,是否终止,调试项;该函数中,一般利用智能体的运动学模型和动力学模型计算下一步的状态和立即回报,并判断是否达到终止状态。
from gym import spaces, core
# core.Env是gym的环境基类,自定义的环境就是根据自己的需要重写其中的方法;
#同上 class MyEnv(core.Env):
def __init__(self):
self.action_space = spaces.Box(low=-1, high=1, shape=(1, )) # 动作空间
self.observation_space = spaces.Box(low=-1, high=1, shape=(1, )) # 状态空间
# 其他成员 def reset(self):
...
obs = self.get_observation()
return obs def step(self, action):
...
reward = self._get_reward()
done = self._get_done()
obs = self._get_observation(action)
info = {} # 用于记录训练过程中的环境信息,便于观察训练状态
return obs, reward, done, info
# 根据需要设计相关辅助函数
def _get_observation(self, action):
...
return obs def _get_reward(self):
...
return reward def _get_done(self):
...
return done
2.项目环境搭建
- 背景介绍:机器人在一个二维迷宫中走动寻找电池,迷宫中有障碍物、大山、电池。大山机器人是无法走的,游戏终止条件是:机器人设计障碍物里或者找到电池;如何最佳的策略,让机器人尽快地找到电池获得奖励呢。下面将进行解答:
2.1 状态空间代码:
self.states = range(0,16) #状态空间 self.terminate_states = dict() #终止状态为字典格式
self.terminate_states[11] = 1
self.terminate_states[12] = 1
self.terminate_states[15] = 1 self.actions = ['n','e','s','w'] self.rewards = dict(); #回报的数据结构为字典
self.rewards['8_s'] = -1.0
self.rewards['13_w'] = -1.0
self.rewards['7_s'] = -1.0
self.rewards['10_e'] = -1.0
self.rewards['14_e'] = 1.0 self.t = dict(); #状态转移的数据格式为字典
self.t['1_s'] = 5
self.t['1_e'] = 2
self.t['2_w'] = 1
self.t['2_e'] = 3
self.t['3_s'] = 6
self.t['3_w'] = 2
self.t['3_e'] = 4
self.t['4_w'] = 3
self.t['4_s'] = 7
self.t['5_s'] = 8
self.t['5_n'] = 1
self.t['6_n'] = 3
self.t['6_s'] = 10
self.t['6_e'] = 7
self.t['7_w'] = 6
self.t['7_n'] = 4
self.t['7_s'] = 11
self.t['8_n'] = 5
self.t['8_e'] = 9
self.t['8_s'] = 12
self.t['9_w'] = 8
self.t['9_e'] = 10
self.t['9_s'] = 13
self.t['10_w'] = 9
self.t['10_n'] = 6
self.t['10_e'] = 11
self.t['10_s'] = 14
self.t['10_w'] = 9
self.t['13_n'] = 9
self.t['13_e'] = 14
self.t['13_w'] = 12
self.t['14_n'] = 10
self.t['14_e'] = 15
self.t['14_w'] = 13
2.2 step函数创建:
动作空间:需要注意的是输出的顺序不要弄错了,对于调试信息,可以为空,但不能缺少,否则会报错,常用{}来代替。
简单阐释:状态转移根据当前状态和动作得到下一步状态,然后判断是否达到终止条件is_terminal决定游戏进程。reward只有到达目的或者障碍是才有其余情况为
def step(self, action):
#系统当前状态
state = self.state
if state in self.terminate_states:
return state, 0, True, {}
key = "%d_%s"%(state, action) #将状态和动作组成字典的键值 #状态转移
if key in self.t:
next_state = self.t[key]
else:
next_state = state
self.state = next_state is_terminal = False if next_state in self.terminate_states:
is_terminal = True if key not in self.rewards:
r = 0.0
else:
r = self.rewards[key] return next_state, r, is_terminal,{}
2.3 render函数的建立:
def render(self, mode='human'): #可视化画图
from gym.envs.classic_control import rendering
screen_width = 600
screen_height = 600 if self.viewer is None: self.viewer = rendering.Viewer(screen_width, screen_height)#调用rendering中的画图函数,#创建600*600的窗口
# 创建网格世界,一共包括10条直线,事先算好每条直线的起点和终点坐标,然后绘制这些直线,代码如下:
#创建网格世界
self.line1 = rendering.Line((100,100),(500,100))
self.line2 = rendering.Line((100, 200), (500, 200))
self.line3 = rendering.Line((100, 300), (500, 300))
self.line4 = rendering.Line((100, 400), (500, 400))
self.line5 = rendering.Line((100, 500), (500, 500))
self.line6 = rendering.Line((100, 100), (100, 500))
self.line7 = rendering.Line((200, 100), (200, 500))
self.line8 = rendering.Line((300, 100), (300, 500))
self.line9 = rendering.Line((400, 100), (400, 500))
self.line10 = rendering.Line((500, 100), (500, 500)) #创建大山
self.mountain = rendering.make_circle(40)
self.circletrans = rendering.Transform(translation=(250,350))
self.mountain.add_attr(self.circletrans)
self.mountain.set_color(0,1,1) #创建第一个障碍物
self.obstacle_1 = rendering.make_circle(35)
self.circletrans = rendering.Transform(translation=(450, 250))
self.obstacle_1.add_attr(self.circletrans)
self.obstacle_1.set_color(0, 0, 0) #创建第二个障碍物
self.obstacle_2 = rendering.make_circle(35)
self.circletrans = rendering.Transform(translation=(150, 150))
self.obstacle_2.add_attr(self.circletrans)
self.obstacle_2.set_color(0, 0, 0) #创建电池
self.Battery = rendering.make_circle(35)
self.circletrans = rendering.Transform(translation=(450, 150))
self.Battery.add_attr(self.circletrans)
self.Battery.set_color(0, 1, 0.5) #创建机器人
self.robot= rendering.make_circle(30)
self.robotrans = rendering.Transform()
self.robot.add_attr(self.robotrans)
self.robot.set_color(1, 0.8, 0)
# 创建完之后,给11条直线设置颜色,并将这些创建的对象添加到几何中代码如下:
self.line1.set_color(0, 0, 0)
self.line2.set_color(0, 0, 0)
self.line3.set_color(0, 0, 0)
self.line4.set_color(0, 0, 0)
self.line5.set_color(0, 0, 0)
self.line6.set_color(0, 0, 0)
self.line7.set_color(0, 0, 0)
self.line8.set_color(0, 0, 0)
self.line9.set_color(0, 0, 0)
self.line10.set_color(0, 0, 0)
# 添加组件到Viewer中
self.viewer.add_geom(self.line1)
self.viewer.add_geom(self.line2)
self.viewer.add_geom(self.line3)
self.viewer.add_geom(self.line4)
self.viewer.add_geom(self.line5)
self.viewer.add_geom(self.line6)
self.viewer.add_geom(self.line7)
self.viewer.add_geom(self.line8)
self.viewer.add_geom(self.line9)
self.viewer.add_geom(self.line10)
self.viewer.add_geom(self.mountain)
self.viewer.add_geom(self.obstacle_1)
self.viewer.add_geom(self.obstacle_2)
self.viewer.add_geom(self.Battery)
self.viewer.add_geom(self.robot)
# 接下来,开始设置机器人的位置。机器人的位置根据其当前所处的状态不同,所在的位置不同。我们事先计算出每个状态处机器人位置的中心坐标,并存储到两个向量中,并在类初始化中给出
self.x=[150,250,350,450] * 4
self.y=[450] * 4 + [350] * 4 + [250] * 4 + [150] * 4
"""为了让结果可视化,我们需要自己渲染结果,比如我打算设置一个600×600的窗口,
那么,每一格的中心的横坐标为[150, 250, 350, 450]重复4次(因为是一个1×16的list,每4个为环境的一行),
相应地,纵坐标为150,250,350,450分别重复4次。""" # 根据这两个向量和机器人当前的状态,我们就可以设置机器人当前的圆心坐标了即:
if self.state is None:
return None self.robotrans.set_translation(self.x[self.state-1], self.y[self.state- 1]) return self.viewer.render(return_rgb_array=mode == 'rgb_array')
2.4 reset()函数的建立:
reset()函数常常用随机的方法初始化机器人的状态,即:
def reset(self):
self.state = self.states[int(random.random() * len(self.states))] #随机初始化机器人状态在[1-16之间随便选]
return self.state关闭窗口:
def close(self):
if self.viewer:
self.viewer.close()下面对创建网格世界进行详细阐释:比如需要创建下面的往网格,则需要10条线,3行4列(本来需要7条),但是有空缺,则8,9,10,需要每个创建从开始到结束的坐标
2.5 环境生成效果图:
2.6 完整代码和文件创建位置:
通过上篇文章我们已经可以注册搭建自己环境了,下面开始详细构建自己的myenv.py文件,还有疑问请看文章【四】。
- 路径H:\Anaconda3-2020.02\envs\tf2\Lib\site-packages\gym\envs\classic_control下的__init__.py文件
- 拷贝在这个文件夹中因为要使用rendering模块
from gym.envs.classic_control.cartpole import CartPoleEnv
from gym.envs.classic_control.mountain_car import MountainCarEnv
from gym.envs.classic_control.continuous_mountain_car import Continuous_MountainCarEnv
from gym.envs.classic_control.pendulum import PendulumEnv
from gym.envs.classic_control.acrobot import AcrobotEnv #MyEnv_1:
from gym.envs.classic_control.myenv_1.myenv_1 import MyEnv_1
- 路径H:\Anaconda3-2020.02\envs\tf2\Lib\site-packages\gym\envs下的__init__.py文件
register(
id='MyEnv_1-v0',
entry_point='gym.envs.classic_control:MyEnv_1',
max_episode_steps=200,
reward_threshold=195.0,
- 测试程序
import gym
import time
env = gym.make('MyEnv_1-v0')
env.reset()
env.render()
time.sleep(10)
env.close()
sys.exit()
- 完整的环境py文件
3.基于Q-learning和Epsilon-greedy训练
理论知识见:【五】强化学习之Sarsa、Qlearing详细讲解----PaddlePaddlle【PARL】框架{飞桨}_丨汀、的博客-CSDN博客
这份代码没有考虑大山的存在。具体代码见码云:丨汀/MyEnv - Gitee.com
import gym
import numpy as np
import time
import sys
num_episodes = 5000# 共进行5000场游戏
max_number_of_steps = 10# 每场游戏最大步数
# 以栈的方式记录成绩
goal_average_steps = 100 # 平均分
num_consecutive_iterations = 100 # 栈的容量
last_time_steps = np.zeros(num_consecutive_iterations) # 只存储最近100场的得分(可以理解为是一个容量为100的栈)
env = gym.make('GridWorld-v0')
# q_table是一个256*2的二维数组
# 离散化后的状态共有4^4=256中可能的取值,每种状态会对应一个行动
# q_table[s][a]就是当状态为s时作出行动a的有利程度评价值
# 我们的AI模型要训练学习的就是这个映射关系表
# 这里的4*4=16是棋盘上棋子的位置数量,第二个参数的4为每个位置对应的4个方向的可能操作。
# q_table的纵坐标是state可能出现的情况之和,横坐标为对应每种state可以做出的action
# 而取值是每种action对于每种state有利程度的评价值
# q_table = np.loadtxt("q_table.txt", delimiter=",")
q_table = np.random.uniform(low=-1, high=1, size=(4 * 4, 4))
#在这之间随机取值
# 根据本次的行动及其反馈(下一个时间步的状态),返回下一次的最佳行动
# epsilon_coefficient为贪心策略中的ε,取值范围[0,1],取值越大,行为越随机
# 当epsilon_coefficient取值为0时,将完全按照q_table行动。故可作为训练模型与运用模型的开关值。
def get_action(state, action, observation, reward, episode, epsilon_coefficient=0.0):
# print(observation)
next_state = observation
epsilon = epsilon_coefficient * (0.99 ** episode) # ε-贪心策略中的ε
if epsilon <= np.random.uniform(0, 1):
next_action = np.argmax(q_table[next_state])
else:
next_action = np.random.choice([0, 1, 2, 3])
# -------------------------------------训练学习,更新q_table----------------------------------
alpha = 0.2 # 学习系数α
gamma = 0.99 # 报酬衰减系数γ
q_table[state, action] = (1 - alpha) * q_table[state, action] + alpha * (
reward + gamma * q_table[next_state, next_action])
# -------------------------------------------------------------------------------------------
return next_action, next_state
timer = time.time()#返回时间单位是秒
for episode in range(num_episodes):
env.reset() # 初始化本场游戏的环境
episode_reward = 0 # 初始化本场游戏的得分
q_table_cache = q_table # 创建q_table还原点,如若训练次数超次,则不作本次训练记录。
for t in range(max_number_of_steps):
env.render() # 更新并渲染游戏画面
state = env.state
action = np.argmax(q_table[state])
observation, reward, done, info = env.step(action) # 进行活动,#并获取本次行动的反馈结果
action, state = get_action(state, action, observation, reward, episode, 0.5) # 作出下一次行动的决策
episode_reward += reward
if done:
np.savetxt("q_table.txt", q_table, delimiter=",")
print('已完成 %d 次训练,本次训练共进行 %d 步数。episode_reward:%d,平均分: %f' % (episode, t + 1, reward, last_time_steps.mean()))
last_time_steps = np.hstack((last_time_steps[1:], [reward])) # 更新最近100场游戏的得分stack
break
q_table = q_table_cache # 超次还原q_table
print('已完成 %d 次训练,本次训练共进行 %d 步数。episode_reward:%d,平均分: %f' % (episode, t + 1, reward, last_time_steps.mean()))
last_time_steps = np.hstack((last_time_steps[1:], [reward])) # 更新最近100场游戏的得分stack;np.hstack():在水平方向上平铺
if (last_time_steps.mean() >= goal_average_steps):
np.savetxt("q_table.txt", q_table, delimiter=",")
print('用时 %d s,训练 %d 次后,模型到达测试标准!' % (time.time() - timer, episode))
env.close()
sys.exit()
env.close()
sys.exit()
结果如下:
......
已完成 113 次训练,本次训练共进行 4 步数。episode_reward:100,平均分: 96.000000
已完成 113 次训练,本次训练共进行 4 步数。episode_reward:100,平均分: 96.000000
已完成 114 次训练,本次训练共进行 2 步数。episode_reward:100,平均分: 96.000000
已完成 114 次训练,本次训练共进行 2 步数。episode_reward:100,平均分: 96.000000
已完成 115 次训练,本次训练共进行 5 步数。episode_reward:100,平均分: 96.000000
已完成 115 次训练,本次训练共进行 5 步数。episode_reward:100,平均分: 98.000000
【五】gym搭建自己的环境之寻宝游戏,详细定义自己myenv.py文件以及算法实现的更多相关文章
- 一文教你如何在ubuntu上快速搭建STM32 CubeIDE环境(图文超详细+文末有附件)
在快速ubuntu上安装cubeide你值得拥有:适合对linux系统还不是很熟悉的同学: 文章目录 1 下载 cubeide 2 找到软件 3 安装 4 附件 5 总结 1 下载 cubeide 登 ...
- 十分钟上手-搭建vue开发环境(新手教程)
想写一些关于vue的文章已经很久了,因为这个框架已经火了很久,在公司里用的框架都比较老旧,但怎么也得跟上前端发展变化的潮流,这不,开始使用vue开发项目了,一遍开发一边踩坑中,今天要记录的是五分钟搭建 ...
- docker 搭建 web 服务环境
docker容器虽然早就听说过,但是本人还真的没去用过,刚好看到相关的文章,就分享了下,有机会可以实践下...... 做过开发的人对开发环境的安装.配置应该都不会太陌生,不管你做什么开发,对开发环境都 ...
- Sublime Text3搭建完美开发环境(Python+PHP+Javascript+nodejs+C++)
一.Sublime配置(如已安装Package Control可跳过) sublime下载地址:http://www.sublimetext.com/3 安装Package Control插件: 直接 ...
- 一文带你趟过mac搭建appium测试环境的遇到的坑
做UI自动化,最难的一步就是在环境搭建上,怎么去搭建一个UI自动化测试的环境,会难住很多人,在Mac上搭建appium如何搭建呢,本文带着大家去领略如何在mac上搭建appium测试环境.下面就是详细 ...
- 单机搭建Android开发环境(五)
前文介绍了Android系统开发环境的搭建,本文将简单介绍Android应用开发环境的搭建. 基于Android Studio搭建应用开发环境,相比使用Eclipse简单得多.Android Stud ...
- 五分钟用Docker快速搭建Go开发环境
挺早以前在我写过一篇用 `Docker`搭建LNMP开发环境的文章:[用Docker搭建Laravel开发环境](http://mp.weixin.qq.com/s?__biz=MzUzNTY5MzU ...
- 自定义搭建PHP开发环境
学习了一段时间php了,因为之前是刚接触php,所以用的是集成安装包(wamp).现在想进一步了解apache.mysql.php之间的关系以及提升自己所以进行自定义搭建PHP开发环境.废话不多说,请 ...
- [BI项目记]-搭建代码管理环境之客户端
前面已经介绍了如何搭建代码管理环境的服务器端安装和配置,这里介绍对于客户端的几个场景. 首先对于开发人员来说,可以直接使用Visual Studio来连接,这里主要演示Visual Studio 20 ...
- 第二章 搭建Android开发环境--读书笔记
俗话说,工欲善其事,必先利其器,对于Android驱动开发来说,首先我们要做的就是搭建Android开发环境,我们首先要配置Linux驱动的开发环境,接着还得配置开发Android应用程序以及Andr ...
随机推荐
- Lambda 表达式各种用法,你都会了吗
公众号「架构成长指南」,专注于生产实践.云原生.分布式系统.大数据技术分享. 前言 Lambda表达式是 Java 8 中引入的最有影响力的功能之一.它们通过允许简洁而优雅地创建匿名函数来实现 Jav ...
- 用ChatGPT,入门机器学习,太强了
入门机器学习,对大部分人来说很简单,一本书.一份课件.一套视频足矣,但是我大胆猜测很多人大概率都没有完整看完过. 所以前些天在朋友圈抱怨了一波: 我感觉所谓牛人,大佬,刨除背景机遇,其成长路上可能也仅 ...
- 手把手教你配置JupyterLab 环境
Python 代码编辑器怎么选?PyCharm.VS Code.Jupyter Notebook 都各有特色. 对于大型代码库,最好还是用传统的 IDE 比较靠谱,但是数据分析等需要可视化操作的场景下 ...
- 0x02 基本算法-枚举、模拟、递推
递归实现指数型枚举 int _, n, m, k, x, y; vector<int> vec; void calc(int x) { if (x == n + 1) { for (int ...
- Java 多线程上下文传递在复杂场景下的实践
一.引言 海外商城从印度做起,慢慢的会有一些其他国家的诉求,这个时候需要我们针对当前的商城做一个改造,可以支撑多个国家的商城,这里会涉及多个问题,多语言,多国家,多时区,本地化等等.在多国家的情况下如 ...
- 七、mycat-ER分片
系列导航 一.Mycat实战---为什么要用mycat 二.Mycat安装 三.mycat实验数据 四.mycat垂直分库 五.mycat水平分库 六.mycat全局自增 七.mycat-ER分片 一 ...
- 深度学习(六)——神经网络的基本骨架:nn.Module的使用
一.torch.nn简介 官网地址: torch.nn - PyTorch 2.0 documentation 1. torch.nn中的函数简介 Containers:神经网络的骨架 Convolu ...
- 解决ssh远程登录Too many authentication failures报错
远程登录失败,报错,造成无法登录的情况,原因为:多次输入密码失败导致登录异常. 解决方案: 1.登录主机:vi /etc/ssh/sshd_config 2.找到MaxAuthTries,修改数值变大 ...
- Kubernetes APIServer 最佳实践
1. kubernetes 整体架构 kubernetes 由 master 节点和工作节点组成.其中,master 节点的组件有 APIServer,scheduler 和 controller-m ...
- 万字血书Vue-Vue进阶
Vue进阶 生命周期 组件运行的过程 组件的生命周期是:组件从创建->运行(渲染)->销毁的整个过程,是一个时间段 如何监听组件的不同时刻 vue框架为组件内置了不同时刻的生命周期函数,是 ...