RL - 云端 Jupyter / Colab 环境中运行 OpenAI Gym

本文介绍如何解决云端运行 Gym 环境时遇到的找不到显示器(NoSuchDisplayException)问题。

OpenAI Gym

OpenAI Gym 是一个用于开发强化学习算法的环境/任务的工具包,里面包括了多个小游戏环境,非常适合做强化学习实验。

OpenAI Gym 环境列表

本地执行 Gym

我们先在本地环境安装 Gym,然后启动赛车环境 CarRacing-v0 让它随机跑。

注意:运行 CarRacing-v0 换需要安装 box2d,可以使用 pip install 'gym[box2d]' 方式安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import gym
env = gym.make('CarRacing-v0')
env.reset()

for i in range(100):
# 从 action_space 随机采样一个动作
action = env.action_space.sample()
# 执行动作
observation, reward, done, info = env.step(action)
# 渲染画面
env.render()
print(f'Action: {action} Reward: {reward}')
if done:
break

env.close()

运行后会弹出一个窗口,并且开始渲染赛车环境。赛车会最多执行 100 步,每一步都是随机运动。

CarRacing-v0 随机 Action

云端运行 Gym

接下来我们尝试在 Colab 执行以上代码。执行会有以下的错误提示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Track generation: 1113..1395 -> 282-tiles track
---------------------------------------------------------------------------
NoSuchDisplayException Traceback (most recent call last)
<ipython-input-2-1149edd96f39> in <module>()
1 import gym
2 env = gym.make('CarRacing-v0')
----> 3 env.reset()
4
5 for i in range(1000):

....

/usr/local/lib/python3.6/dist-packages/pyglet/canvas/xlib.py in __init__(self, name, x_screen)
84 self._display = xlib.XOpenDisplay(name)
85 if not self._display:
---> 86 raise NoSuchDisplayException('Cannot connect to "%s"' % name)
87
88 screen_count = xlib.XScreenCount(self._display)

NoSuchDisplayException: Cannot connect to "None"

错误是没有显示器,但是当我们在服务器/云端训练模型时没办法配备显示器。此时我们可以用 pyvirtualdisplay 框架虚拟一个显示器来运行 Gym 环境。

首先安装 pyvirtualdisplay 和需要的依赖。

1
2
3
!apt-get install xvfb
!pip install pyvirtualdisplay
!pip install Pillow

安装完成后,先启动虚拟显示器。

1
2
3
from pyvirtualdisplay import Display
display = Display(visible=0, size=(1400, 900))
display.start()

接下来再执行上面代码就可以正常运行,可以看到 Action 和 Reward 输出,但是没有画面。因为网页是没办法弹出渲染弹窗。我们可以通过以下方式在 Jupyter 内可视化 Gym 环境。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import gym
import time
from IPython import display
from PIL import Image

env = gym.make('CarRacing-v0')
env.reset()

for i in range(100):
# 从 action_space 随机采样一个动作
action = env.action_space.sample()
# 执行动作
observation, reward, done, info = env.step(action)
# 清除当前 Cell 的输出
display.clear_output(wait=True)
# 渲染画面,得到画面的像素数组
rgb_array = env.render(mode='rgb_array')
# 使用像素数组生成图片
img = Image.fromarray(rgb_array)
# 当前 Cell 中展示图片
display.display(img)
# 防止刷新过快
time.sleep(0.01)
print(f'Action {action} Reward {reward}')
if done:
break

env.close()

执行后可以在 Jupyter 中看到图像输出,结果如下图。
Jupyter 中渲染结果