OpenAI Gym 环境介绍及使用
前面的强化学习介绍实验中,我们给出了如下所示的强化学习流程图。可以很清楚看到,环境是强化学习的基础,智能体在强化学习的过程中始终和环境发生着交互,并从环境中获得奖励。这也是强化学习区别于监督学习或非监督学习的重要特点。
正是因为强化学习需要环境这个先决条件,当我们想要调试或对比强化学习算法时都需要先搭建环境(比如先设计并建造迷宫,确定奖励等),而这往往是一个复杂的过程,且需要掌握更多的技术才能得以实现。所以,Q-Learning 学习时只能使用文字迷宫游戏。
如今,有了 OpenAI 的 Gym 环境,这将不再是一件麻烦的事情,尤其是对于初学者而言,可以很快地上手强化学习算法,并在有趣的游戏环境中实验。
Gym 环境安装
首先,我们来说一下 Gym 环境的安装。受限于 Notebook 的限制,蓝桥云课在线实验只能使用 Gym 中的部分环境。如果想要尝试全部的环境,则最好是在桌面环境中使用。
目前,Gym 官方仅支持 Linux 或使用 UNIX 内核的操作系统,也就是 Ubuntu 或者 macOS 都可以使用。官方并不支持 Windows,但有一些博客文章也给出了解决方案。下面,我们以在 Ubuntu 中安装 Gym 举例。
Gym 的安装大致分为 3 步,首先是更新 apt 包管理工具:
sudo apt-get update
然后,安装相应的依赖包:
sudo apt-get install -y python-numpy python-dev cmake zlib1g-dev libjpeg-dev xvfb libav-tools xorg-dev python-opengl libboost-all-dev libsdl2-dev swig
最后通过 pip 安装 gym 模块:
sudo pip install gym
你可以使用 gym[all]
安装 Gym 提供的全部环境,这需要你单独安装 MuJoCo 模块,具体请参考 官方文档。
目前,我们的线上环境已经安装了完整的 Gym 环境。
Gym 环境使用
Gym 提供的全部环境中主要包含下面几大类:
Atari:几十种小游戏,例如打方块、乒乓球等。
Box2D:二维环境下的连续任务,例如开小车、机器人行走等。
Classic control:经典的控制任务,例如简单机械臂控制或者小车爬坡任务。
MuJoCo:三维环境中的连续任务,例如小人在地板上行走等。【需要单独付费安装】
Robotics:机械臂模拟任务。
Toy text:非常简单的文字游戏。
关于这些环境的详细信息,可以通过 此链接查看。
冰面飞盘游戏示例
接下来,我们通过一个叫 FrozenLake-v0 的文字游戏入门 Gym 的使用。FrozenLake-v0 是一个在冰面上捡飞盘的游戏,默认为 4x4 的网格。例如:
[ SFFF FHFH FFFH HFFG]
其中,S 表示起点,G 表示分盘所在的目标点,F 表示安全的冰冻表面,H 表示冰窟窿。Agent 每次从 S 出发,掉入冰窟窿游戏结束,成功捡到飞盘将收获奖励 1。另外,冰面很滑,所以不一定会按照预想的方向移动。
首先,我们需要加载环境,方法非常简单:
import gym
import warnings
warnings.filterwarnings('ignore')
env = gym.make('FrozenLake-v0') # 加载相应环境
env.action_space # 查看该环境中可用 action 数量
上面输出的 Discrete(4),即代表可以有 4 个动作,你可以想到是上、下、左、右。现在可以启动环境了。
env.reset() # 运行前一般需要先重置环境
env.render() # 启动渲染环境
此时如果 Agent 采取一个随机行动,环境就会反馈奖励并进入下一个状态。
action = env.action_space.sample() # 使用 sample 表示随机行动
env.step(action) # 采取随机行动
上面的代码中,action_space.sample()
是环境默认方法代表随机选择动作。实际上,你也可以手动指定 action_space.contains(0\1\2\3)
实现左下右上。由于 Gym 环境文档普遍不全,可能需要通过 查看源码 发现。
通过输出结果可以看到,env.step() 行动发生之后,环境返回 4 个值,这 4 个值依次对应:
observation (object):冰面的状态,即 Agent 的观测结果。
reward (float):奖励,即先前行为获得的所有回报之和。
done (boolean):判断是否要重新设定(reset)环境,例如此时掉进冰窟窿或拿到飞盘表示游戏终止,即重新设定环境。
info (dict): 调试诊断信息。
observation = env.reset() # 重置环境
for t in range(20):
env.render() # 渲染环境
action = env.action_space.sample() # 设定随机行动
observation, reward, done, info = env.step(action) # 采取随机行动
print(observation, reward, done) # 输出观测结果,奖励以及游戏是否终止的状态
if done: # 如果游戏中止
print("Episode finished after {} timesteps".format(t+1)) # 输出连续行动的时间步长
break
其实,我们还可以使用 IPython.display 模块让过程在 Notebook 中动态化:
from IPython import display
import time
observation = env.reset() # 重置环境
for t in range(20):
env.render() # 渲染环境
action = env.action_space.sample()
observation, reward, done, info = env.step(action) # 采取随机行动
print(observation, reward, done)
display.clear_output(wait=True) # 清除单元格输出
time.sleep(1) # 延时 1s 执行
print("step:", t)
if done:
print("Episode finished after {} timesteps".format(t+1))
break
上面的例子中,你可能会发现每一个 step 都会显示执行的方向(Up,Down,Left,Right),但是智能体并不是每次都向相应方向移动。这是因为环境默认设置了冰面很滑,所以有 1/3 的概率溜走。
不过,我们可以通过重新注册环境参数来取消掉随机性,变成确定性问题。
from gym.envs.registration import register
# 重新注册环境
register(
id='FrozenLakeNotSlippery-v0', # 新环境 id
entry_point='gym.envs.toy_text:FrozenLakeEnv', # 继承环境
kwargs={'map_name': '4x4', 'is_slippery': False}, # 参数
max_episode_steps=100, # 最大迭代次数
)
上方,我们继承了 FrozenLakeEnv 环境,并重新注册了新环境 FrozenLakeNotSlippery-v0。其中设置 'is_slippery': False 使得环境变成确定性问题。
from IPython import display
import time
env = gym.make('FrozenLakeNotSlippery-v0') # 加载新环境
observation = env.reset() # 重置环境
for t in range(20):
env.render() # 渲染环境
action = env.action_space.sample()
observation, reward, done, info = env.step(action) # 采取随机行动
print(observation, reward, done)
display.clear_output(wait=True) # 清除单元格输出
time.sleep(1) # 延时 1s 执行
print("step:", t)
if done:
print("Episode finished after {} timesteps".format(t+1))
break
这一次,你应该能看到智能体是沿着状态显示的方向准确移动了。
Gym 玩 Atari 打砖块游戏
一般情况下,OpenAI Gym 需要运行在有显卡的环境中,因为大部分环境需要有窗口显示。所以,线上 Jupyter Notebook 使用 Gym 的限制就非常多了。
上一个实验中,我们使用 FrozenLake-v0
文字游戏进行了示例。本次挑战中,你需要参考前面介绍过的 Gym 环境常用 API 来练习另一个打砖块小游戏环境的调用和渲染。这块游戏也是 Atari 雅达利 非常经典的游戏之一。
挑战:加载打砖块小游戏环境 Breakout-v0。
import gym
env = gym.make("Breakout-v0")
env
接下来,我们初步查看环境的样子,你需要渲染环境界面。由于该环境与文字游戏不同,我们需要对其进行简单处理以在 Jupyter Notebook 中显示。
挑战:渲染并可视化环境 Breakout-v0。
规定:需要向 render 方法中添加参数 mode='rgb_array',其可以使环境变成 RGB 数组。最后使用 Matplotlib 提供的 imshow 方法显示图像。
from matplotlib import pyplot as plt
%matplotlib inline
env.reset() # 运行前一般需要先重置环境
rgb_array = env.render(mode='rgb_array') # 渲染为数组
plt.imshow(rgb_array) # 绘图
接下来,我们查看 Breakout-v0 环境提供的动作空间。
env.action_space
Discrete(4) 表示底部滑块(智能体)有 4 个动作,实际上就是向左,向右,快速向左和快速向右。
下面,我们随机选择动作,并迭代 100 次,查看环境的变化。
挑战:随机选择智能体动作迭代 100 次,并打印出每次执行的动作、奖励以及是否重置环境的状态。
from IPython import display
env.reset()
for t in range(100): # 最长时间步长为 100
display.display(plt.gcf())
plt.imshow(env.render(mode='rgb_array'))
action = env.action_space.sample()
observation, reward, done, info = env.step(action) # 采取随机行动
print(action, reward, done)
display.clear_output(wait=True) # 清空每次迭代的静态输出使之可以动态显示