如何在服务器上运行OpenAI Gym .render()


77

我正在通过Jupyter(Ubuntu 14.04)在p2.xlarge AWS服务器上运行python 2.7脚本。我希望能够渲染我的模拟。

最小的工作实例

import gym
env = gym.make('CartPole-v0')
env.reset()
env.render()

env.render() 导致(除其他事项外)以下错误:

...
HINT: make sure you have OpenGL install. On Ubuntu, you can run 
'apt-get install python-opengl'. If you're running on a server, 
you may need a virtual frame buffer; something like this should work: 
'xvfb-run -s \"-screen 0 1400x900x24\" python <your_script.py>'")
...
NoSuchDisplayException: Cannot connect to "None"

我想一些如何能够看到模拟。如果可以内联,那将是理想的选择,但是任何显示方法都将是不错的选择。

编辑:这只是某些环境下的问题,例如经典控件。


更新我

灵感来自这个我尝试以下,而不是xvfb-run -s \"-screen 0 1400x900x24\" python <your_script.py>(我不能去工作)。

xvfb-run -a jupyter notebook

运行我现在得到的原始脚本

GLXInfoException: pyglet requires an X server with GLX

更新二

问题#154似乎相关。我尝试禁用弹出窗口,然后直接创建RGB颜色

import gym
env = gym.make('CartPole-v0')
env.reset()

img = env.render(mode='rgb_array', close=True)  
print(type(img)) # <--- <type 'NoneType'>

img = env.render(mode='rgb_array', close=False) # <--- ERROR
print(type(img)) 

我懂了ImportError: cannot import name gl_info


更新三

从@ Torxed的灵感中,我尝试创建一个视频文件,然后进行渲染(一个完全令人满意的解决方案)。

使用“记录和上传结果”中的代码

import gym

env = gym.make('CartPole-v0')
env.monitor.start('/tmp/cartpole-experiment-1', force=True)
observation = env.reset()
for t in range(100):
#    env.render()
    print(observation)
    action = env.action_space.sample()
    observation, reward, done, info = env.step(action)
    if done:
        print("Episode finished after {} timesteps".format(t+1))
        break

env.monitor.close()

我尝试遵循您的建议,但是ImportError: cannot import name gl_info从运行时获得了建议env.monitor.start(...

根据我的理解,问题是OpenAI使用pyglet,并且pyglet“需要”一个屏幕,以便计算要渲染的图像的RGB颜色。因此,有必要欺骗python以使其认为已连接监视器


更新四

仅供参考,有一些在线解决方案可以使用大黄蜂。如果您可以控制服务器,那么这应该可以工作,但是由于AWS在VM中运行,所以我认为您不能使用它。


更新V

即使您遇到此问题,并且不知道要做什么(就像我一样),大多数环境的状态也很简单,您可以创建自己的渲染机制。不是很令人满意,但是..你知道的。


您是否尝试过制作非常有用的错误消息所要求的虚拟屏幕缓冲区?
Selali Adob​​or '16

1
就是这样,我不知道该怎么做。在我看过的指南中,我不明白如何使它在服务器上工作。
Toke Faurby

2
我已经尝试更新了该帖子
Toke Faurby

1
我也被
困在这里

请注意,@ TokeFaurby,您的解决方案自2016年12月23日起已过时。您需要使用稍微不同的API和differentnet方法才能使此工作正常进行。我认为您的方法将不再起作用,因为作为VideoRecorder类一部分的类env.wrapper.Monitor现在正在env.render直接调用。
mpacer

Answers:


35

得到了一个简单的解决方案:

购物车杆

如果在Linux服务器上,请使用以下命令打开jupyter:
$ xvfb-run -s "-screen 0 1400x900x24" jupyter notebook
在朱皮特
import matplotlib.pyplot as plt
%matplotlib inline
from IPython import display
每一步之后
def show_state(env, step=0, info=""):
    plt.figure(3)
    plt.clf()
    plt.imshow(env.render(mode='rgb_array'))
    plt.title("%s | Step: %d %s" % (env._spec.id,step, info))
    plt.axis('off')

    display.clear_output(wait=True)
    display.display(plt.gcf())

注意:如果您的环境不是unwrapped,请传递env.envshow_state


1
很好,谢谢,但是环境仍然在外部窗口中打开(我在本地运行,而不是在远程服务器中运行)。关于如何防止这种情况的任何想法?
卢卡斯

我正在/bin/xvfb-run: line 181: 0: command not found/bin/xvfb-run: line 186: kill: (31449) - No such process错误。任何想法?
Afshin Oroojlooy

241400x900x24是什么意思?我猜1400是显示器宽度和900显示器高度
内森(Nathan)

24指定虚拟监视器的位深度-参见此处
-BrandonHoughton

我的问题发生在渲染阶段:env = gym.make('CartPole-v0'); env.render(mode ='rgb_array'); 给我ValueError:数组长度必须> = 0,而不是-48424951659315200
John Jiang

16

这个GitHub问题给了我一个很好的答案。很好,因为它不需要服务器的任何其他依赖项(我假设您已经拥有matplotlib)或配置。

只需运行,例如:

import gym
import matplotlib.pyplot as plt
%matplotlib inline

env = gym.make('Breakout-v0') # insert your favorite environment
render = lambda : plt.imshow(env.render(mode='rgb_array'))
env.reset()
render()

使用mode='rgb_array'为您numpy.ndarray提供每个位置的RGB值,并且matplotlibimshow(或其他方法)可以很好地显示这些值。

请注意,如果您需要将多个在同一细胞时,这种解决方案将每次绘制一个单独的图像。这可能不是您想要的。如果我想出一个好的解决方法,我将尝试对其进行更新。

更新以在一个单元格中多次渲染

根据这个StackOverflow答案,这是一个有效的代码段(请注意,使用交互式绘图可以有更有效的方法;在我的机器上,这种方法似乎有些滞后):

import gym
from IPython import display
import matplotlib.pyplot as plt
%matplotlib inline

env = gym.make('Breakout-v0')
env.reset()
for _ in range(100):
    plt.imshow(env.render(mode='rgb_array'))
    display.display(plt.gcf())
    display.clear_output(wait=True)
    action = env.action_space.sample()
    env.step(action)

更新以提高效率

在我的机器上,这大约快了3倍。不同之处在于imshow,我们无需在每次渲染时都调用它,而是仅更改原始图上的RGB数据。

import gym
from IPython import display
import matplotlib
import matplotlib.pyplot as plt
%matplotlib inline

env = gym.make('Breakout-v0')
env.reset()
img = plt.imshow(env.render(mode='rgb_array')) # only call this once
for _ in range(100):
    img.set_data(env.render(mode='rgb_array')) # just update the data
    display.display(plt.gcf())
    display.clear_output(wait=True)
    action = env.action_space.sample()
    env.step(action)

您是否真的尝试过在服务器上运行它?还是只在本地计算机上进行了测试?您所建议的基本上与Update II中的相同。问题在于即使窗口没有打开,env.render()导入gl_info也会在后台进行。mode=rgb_array不会改变这一点
Toke Faurby

啊,我没有在AWS服务器上尝试过;我使用的那个必须配置不同,以便不会出现相同的错误。抱歉,该操作无济于事
Nathan

6
@Nathan您的解决方案还有其他问题。一些环境似乎有绕开窗口创建的方法,而另一些则没有。例如,如果您想尝试一下,请在示例中将其替换env = gym.make('Breakout-v0')env = gym.make('CartPole-v0'),然后您将明白我的意思。“ Breakout”碰巧是一个Atari游戏,它使用atari_py.ALEInterface()渲染器并返回图像。见github.com/openai/gym/blob/master/gym/envs/atari/…–
mpacer

12

我设法在无头服务器上远程运行和渲染openai / gym(甚至使用mujoco)。

# Install and configure X window with virtual screen
sudo apt-get install xserver-xorg libglu1-mesa-dev freeglut3-dev mesa-common-dev libxmu-dev libxi-dev
# Configure the nvidia-x
sudo nvidia-xconfig -a --use-display-device=None --virtual=1280x1024
# Run the virtual screen in the background (:0)
sudo /usr/bin/X :0 &
# We only need to setup the virtual screen once

# Run the program with vitural screen
DISPLAY=:0 <program>

# If you dont want to type `DISPLAY=:0` everytime
export DISPLAY=:0

用法:

DISPLAY=:0 ipython2

例:

import gym
env = gym.make('Ant-v1')
arr = env.render(mode='rgb_array')
print(arr.shape)
# plot or save wherever you want
# plt.imshow(arr) or scipy.misc.imsave('sample.png', arr)

因此,可以肯定的是,这也适用于经典控制吗?
Toke Faurby

使用像CartPole这样的经典控件,您可以尝试使用“ ssh -X username @ hostname”并直接进行渲染。

我遇到了错误ContextException: Could not create GL context remote,没有其他解决方案对我有用,但这很好用。
Omegastick '18

10

我认为我们应该只使用OpenAI Gym将渲染捕获为视频wrappers.Monitor ,然后将其显示在Notebook中。

例:

依存关系

!apt install python-opengl
!apt install ffmpeg
!apt install xvfb
!pip3 install pyvirtualdisplay

# Virtual display
from pyvirtualdisplay import Display

virtual_display = Display(visible=0, size=(1400, 900))
virtual_display.start()

捕捉为视频

import gym
from gym import wrappers

env = gym.make("SpaceInvaders-v0")
env = wrappers.Monitor(env, "/tmp/SpaceInvaders-v0")

for episode in range(2):
    observation = env.reset()
    step = 0
    total_reward = 0

    while True:
        step += 1
        env.render()
        action = env.action_space.sample()
        observation, reward, done, info = env.step(action)
        total_reward += reward
        if done:
            print("Episode: {0},\tSteps: {1},\tscore: {2}"
                  .format(episode, step, total_reward)
            )
            break
env.close()

在笔记本中显示

import os
import io
import base64
from IPython.display import display, HTML

def ipython_show_video(path):
    """Show a video at `path` within IPython Notebook
    """
    if not os.path.isfile(path):
        raise NameError("Cannot access: {}".format(path))

    video = io.open(path, 'r+b').read()
    encoded = base64.b64encode(video)

    display(HTML(
        data="""
        <video alt="test" controls>
        <source src="data:video/mp4;base64,{0}" type="video/mp4" />
        </video>
        """.format(encoded.decode('ascii'))
    ))

ipython_show_video("/tmp/SpaceInvaders-v0/openaigym.video.4.10822.video000000.mp4")

希望对您有所帮助。;)


运行所有程序后,我最终收到“ NameError:无法访问:/tmp/SpaceInvaders-v0/openaigym.video.4.10822.video000000.mp4”。任何想法?
user2997154 '19

检查下的文件名/tmp/SpaceInvaders-v0。视频名称可能不同。另外,为提供一个已知的文件夹env = wrappers.Monitor(env, "/tmp/SpaceInvaders-v0")
Senthilkumar戈帕尔

这也不适用于经典控件,例如“ CartPole-v0”:ValueError:数组长度必须> = 0,而不是-48424951659315200
John Jiang

9

还有一个使用(Xvfb包装器)的解决方案pyvirtualdisplay。我喜欢此解决方案的一件事是,您可以从脚本内部启动它,而不必在启动时包装它:

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

1
我收到此错误:ValueError:以10为底的int()的无效文字:''
Crispy13 '20

8

我自己遇到了这个。将xvfb用作X服务器与Nvidia驱动程序有些冲突。但是最后这篇文章指出了我正确的方向。如果安装了带-no-opengl-files选件的Nvidia驱动程序和带--no-opengl-libs选件的CUDA,则Xvfb可以正常工作。如果您知道这一点,它应该可以工作。但是花了我很多时间才弄明白这一点,似乎我并不是唯一一个遇到xvfb和nvidia驱动程序问题的人。

在此处写下了所有必要步骤,以使用Ubuntu 16.04 LTSAWS EC2实例上进行所有设置


我尽最大努力遵循了指南,但无法使其正常工作。唯一的区别是我不是从源代码构建TF,但是由于此问题无关,所以我认为这无关紧要。
Toke Faurby

很抱歉听到这个消息。由于Amazon Deep Learning AMI现在包含具有GPU支持的Tensor Flow版本,因此我建议从那里开始:aws.amazon.com/marketplace/pp/B01M0AXXQB 但是,如果您仍然想从头开始设置,请提供一些信息。有关您遇到的问题的更多信息,所以我可以为您提供帮助。
I_like_foxes

2

我通过简单地使用PIL和Python图像库避免了使用matplotlib的问题:

import gym, PIL
env = gym.make('SpaceInvaders-v0')
array = env.reset()
PIL.Image.fromarray(env.render(mode='rgb_array'))

我发现我不需要设置XV帧缓冲区。


我非常怀疑这是否可以在无头服务器上运行。问题出在env.render功能上,PIL与该问题无关。
Toke Faurby

抱歉没注意到你用过SpaceInvaders-v0。此问题仅由某些环境(例如经典控件)引起。我适当地编辑了OP
Toke Faurby,

是的,我现在看到我的答案仅适用于某些模拟。太可惜了,健身房也很有限。
Doug Blank '18

2

我一直在寻找一种可以在Colaboratory中工作的解决方案,并最终解决了这个问题

from IPython import display
import numpy as np
import time

import gym
env = gym.make('SpaceInvaders-v0')
env.reset()

import PIL.Image
import io


def showarray(a, fmt='png'):
    a = np.uint8(a)
    f = io.BytesIO()
    ima = PIL.Image.fromarray(a).save(f, fmt)
    return f.getvalue()

imagehandle = display.display(display.Image(data=showarray(env.render(mode='rgb_array')), width=450), display_id='gymscr')

while True:
    time.sleep(0.01)
    env.step(env.action_space.sample()) # take a random action
    display.update_display(display.Image(data=showarray(env.render(mode='rgb_array')), width=450), display_id='gymscr')

编辑1:

您可以在Cartpole环境中使用xvfbwrapper。

from IPython import display
from xvfbwrapper import Xvfb
import numpy as np
import time
import pyglet
import gym
import PIL.Image
import io    

vdisplay = Xvfb(width=1280, height=740)
vdisplay.start()

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

def showarray(a, fmt='png'):
    a = np.uint8(a)
    f = io.BytesIO()
    ima = PIL.Image.fromarray(a).save(f, fmt)
    return f.getvalue()

imagehandle = display.display(display.Image(data=showarray(env.render(mode='rgb_array')), width=450), display_id='gymscr')


for _ in range(1000):
  time.sleep(0.01)
  observation, reward, done, info = env.step(env.action_space.sample()) # take a random action
  display.update_display(display.Image(data=showarray(env.render(mode='rgb_array')), width=450), display_id='gymscr')


vdisplay.stop()

如果您正在使用标准Jupyter,则有更好的解决方案。您可以使用CommManager将带有更新的数据URL的消息发送到HTML输出。

IPython内联屏幕示例

在Colab中,CommManager不可用。限制性更强的输出模块具有一种称为eval_js()的方法,该方法似乎有点慢。


2
它可以使用SpaceInvaders-v0,但是当我打电话CartPole-v0Pendulum-v0得到时NameError: name 'base' is not defined。任何想法?
Afshin Oroojlooy

@AfshinOroojlooy尝试!apt-get install python-pyglet && pip install pyglet然后重新启动运行时
shadi

@shadi,感谢您的回复。我前一段时间解决了这个问题。
Afshin Oroojlooy

2

在这里引用我的其他答案:仅在Jupyter笔记本中显示OpenAI体育馆

我在这里做了一个快速的示例,您可以使用它:https : //kyso.io/eoin/openai-gym-jupyter,其中有两个在Jupyter中渲染的示例-一个作为mp4,另一个作为实时gif。

.mp4示例非常简单。

import gym
from gym import wrappers

env = gym.make('SpaceInvaders-v0')
env = wrappers.Monitor(env, "./gym-results", force=True)
env.reset()
for _ in range(1000):
    action = env.action_space.sample()
    observation, reward, done, info = env.step(action)
    if done: break
env.close()

然后在新的单元格Jupyter单元中,或将其从服务器下载到可以观看视频的某个位置。

import io
import base64
from IPython.display import HTML

video = io.open('./gym-results/openaigym.video.%s.video000000.mp4' % env.file_infix, 'r+b').read()
encoded = base64.b64encode(video)
HTML(data='''
    <video width="360" height="auto" alt="test" controls><source src="data:video/mp4;base64,{0}" type="video/mp4" /></video>'''
.format(encoded.decode('ascii')))

如果您在具有公共访问权限的服务器上,则可以python -m http.server在Gym-results文件夹中运行,然后仅在此处观看视频。


2

我遇到了同样的问题,在这里偶然发现了答案。混合它们可以帮助我解决问题。

以下是分步解决方案:

安装以下内容:

apt-get install -y python-opengl xvfb

通过以下命令启动jupyter笔记本:

xvfb-run -s "-screen 0 1400x900x24" jupyter notebook

笔记本内部:

import gym
import matplotlib.pyplot as plt
%matplotlib inline

env = gym.make('MountainCar-v0') # insert your favorite environment
env.reset()
plt.imshow(env.render(mode='rgb_array')

现在,您可以将同一事物放入循环中以多次渲染。

from IPython import display

for _ in range(100):
    plt.imshow(env.render(mode='rgb_array'))
    display.display(plt.gcf())
    display.clear_output(wait=True)
    action = env.action_space.sample()
    env.step(action)

希望这对仍然面临问题的其他人也有用。感谢安德鲁斯内森的回答。


这个解决方案终于对我有用,但是我遇到了一个错误,AttributeError: 'ImageData' object has no attribute 'data'pyglet-v1.3.2这里的解决方案中为我安装了修复程序。
大卫,


1

这可能是一个完整的解决方法,但是我在桌面环境中使用了docker映像,并且效果很好。Docker映像位于https://hub.docker.com/r/dorowu/ubuntu-desktop-lxde-vnc/

运行的命令是

docker run -p 6080:80 dorowu/ubuntu-desktop-lxde-vnc

然后浏览http://127.0.0.1:6080/以访问Ubuntu桌面。

下面是显示gif的Mario bros健身房环境正在运行和呈现的gif图像。如您所见,它反应灵敏且流畅。

在此处输入图片说明


1

我创建了这个微型软件包,通过在代码中添加一行,您就可以将环境呈现到浏览器上。

把你的代码和替换功能您的正常env.render()使用yield env.render(mode='rgb_array')。用render_browser装饰器封装此功能。

import gym
from render_browser import render_browser

@render_browser
def test_policy(policy):
    # Your function/code here.
    env = gym.make('Breakout-v0')
    obs = env.reset()

    while True:
        yield env.render(mode='rgb_array')
        # ... run policy ...
        obs, rew, _, _ = env.step(action)

test_policy(policy)    

当您your_ip:5000在浏览器上访问时,test_policy()将被调用,您将能够在浏览器窗口中看到渲染的环境。

在此处输入图片说明


-1

在我的IPython环境中,Andrew Schreiber的解决方案无法平滑绘制图像。以下是我的解决方案:

如果在Linux服务器上,请使用以下命令打开jupyter:

$ xvfb-run -s "-screen 0 1400x900x24" jupyter notebook

在朱皮特

import matplotlib.pyplot as plt
%matplotlib inline
%matplotlib notebook
from IPython import display

显示迭代:

done = False
obs = env.reset()

fig = plt.figure()
ax = fig.add_subplot(111)
plt.ion()

fig.show()
fig.canvas.draw()

while not done:
    # action = pi.act(True, obs)[0] # pi means a policy which produces an action, if you have
    # obs, reward, done, info = env.step(action) # do action, if you have
    env_rnd = env.render(mode='rgb_array')
    ax.clear()
    ax.imshow(env_rnd)
    fig.canvas.draw()
    time.sleep(0.01)

2
这个解决方案NameError: name 'base' is not defined对我有帮助。任何想法?
Afshin Oroojlooy
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.