gym里内置了许多好玩经典的环境用于训练一个更加智能的个体,不过这些环境类绝大多数不能用来实践前五讲的视频内容,主要是由于这些环境类的观测空间的某个维度是连续变量而不是离散变量,这是前五讲内容还未涉及到的知识。为了配合解释David Silver视频公开课提到的一些示例,参考了gym的思想设计了一个通用的格子世界环境类,该环境类的观测空间是一维离散变量,可以很好地模拟其公开课中提到的:简单格子、有风格子、随机行走、悬崖行走、随机策略(骷髅和钱袋子)等问题。在此基础上理解、实践强化学习的基础算法就相对简单而且直观了。
先贴上格子世界环境类的源文件:gridworld.py,只把该文件下载到您自己的文件夹内,导入其中的类或方法就可以了。已经内置的一些环境类UI界面类似下面这些:
简单或有风10*7格子世界
悬崖行走示例
随机行走示例
模仿Gridworld with Dynamic Programming 的一个格子世界
用户可以自定义格子的大小、水平和垂直格子数目、内部障碍分布、以及每一个格子的即时奖励值。在通用的格子世界环境类的UI界面中,我使用不同的颜色设置表示不同的意义,其中:
通用的格子世界环境类接受如下参数:
def __init__(self, n_width:int=10,
n_height:int = 7,
u_size = 40,
default_reward:float = 0,
default_type = 0,
windy=False):
分别是水平方向上格子数量,竖直方向上格子数量,每一个单位格子的绘制边长(单位为像素值),默认每一个格子的即时奖励值以及默认格子的类型。定义格子类型值为0时为个体可进入格子,类型为1表示为障碍,个体不能进入格子。有兴趣您可以修改代码支持更多的类型。
下面以一个悬崖行走格子世界环境为例,讲解如何使用通用的格子世界环境类来得到自己想要的格子世界环境对象。悬崖行走的例子出现在David Silver强化学习公开课的 第五讲 ,环境如下:
# 导入GridWorldEnv前确保当前代码文件与gridworld.py文件同在一个包内
from gridworld import GridWorldEnv
env = GridWorldEnv(n_width=12, # 水平方向格子数量
n_height = 4, # 垂直方向格子数量
u_size = 60, # 可以根据喜好调整大小
default_reward = -1, # 默认格子的即时奖励值
default_type = 0) # 默认的格子都是可以进入的
from gym import spaces # 导入spaces
env.action_space = spaces.Discrete(4) # 设置行为空间支持的行为数量
# 格子世界环境类默认使用0表示左,1:右,2:上,3:下,4,5,6,7为斜向行走
# 具体可参考_step内的定义
# 格子世界的观测空间不需要额外设置,会自动根据传入的格子数量计算得到
env.start = (0,0)
env.ends = [(11,0)]
对一些特殊格子的类型和即时奖励值进行修改,这里要把组成悬崖的格子的即时奖励设为-100,这个例子中没有不可进入的格子,所以不需要对格子类型进行修改。示例中悬崖格子是终止状态,因此有:
for i in range(10):
env.rewards.append((i+1,0,-100))
env.ends.append((i+1,0))
env.types = [(5,1,1),(5,2,1)]
env.refresh_setting()
至此,我们自定义的格子世界环境就设置好了,调用其render()方法查看一下吧:
env.render()
input("press any key to continue...")
效果如下:
两块障碍已经顺利生成了,可是发现个体的位置不在起始位置,为此我们需要重置下个体的位置,只需要调用env的reset()方法就可以了:
env.reset()
再看效果符合预期:
生成这个环境完整的代码如下:
from gridworld import GridWorldEnv
from gym import spaces
env = GridWorldEnv(n_width=12, # 水平方向格子数量
n_height = 4, # 垂直方向格子数量
u_size = 60, # 可以根据喜好调整大小
default_reward = -1, # 默认格子的即时奖励值
default_type = 0) # 默认的格子都是可以进入的
env.action_space = spaces.Discrete(4) # 设置行为空间数量
# 格子世界环境类默认使用0表示左,1:右,2:上,3:下,4,5,6,7为斜向行走
# 具体可参考_step内的定义
# 格子世界的观测空间不需要额外设置,会自动根据传输的格子数量计算得到
env.start = (0,0)
env.ends = [(11,0)]
for i in range(10):
env.rewards.append((i+1,0,-100))
env.ends.append((i+1,0))
env.types = [(5,1,1),(5,2,1)]
env.refresh_setting()
env.reset()
env.render()
input("press any key to continue...")
有了格子世界通用环境类,我们就可以比较方便定制自己的格子世界环境。为了方便使用,我也写好了几个内置的格子世界环境,大家只要调用相应的方法就可以得到它:
env = LargeGridWorld() # 10*10的大格子
env = SimpleGridWorld() # 10*7简单无风格子
env = WindyGridWorld() # 10*7有风格子
env = RandomWalk() # 随机行走
env = CliffWalk() # 悬崖行走
env = SkullAndTreasure() # 骷髅和钱袋子示例
如果您希望让您的个体支持斜向行走,请将相应的行为空间参数设为8,同时请留意环境类的_step方法关于斜向行走状态的改变是否如您所愿的那样设置,您可以在此基础上定制自己的行为规则。
要使用格子世界环境类提供的功能,您必须已经实现安装了gym库以及其依赖库。关于如何安装gym库、如何向gym注册自定义的环境类可以参考相关教程。通过gym库提供的相关功能,你还可以把个体经历Episode的过程录制成视频。
下次实践编写与个体相关的代码来巩固我们对强化学习相关基础算法的理解。敬请期待。