Как запустить OpenAI Gym .render () на сервере

Я запускаю скрипт python 2.7 на сервере p2.xlarge AWS через Jupyter (Ubuntu 14.04). Я хотел бы иметь возможность визуализировать свои симуляции.

Минимальный рабочий пример

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"

Хотелось бы кое-как увидеть симуляции. Было бы идеально, если бы я мог встроить его, но любой метод отображения был бы хорош.

Изменить: это проблема только в некоторых средах, например в классическом управлении.


Обновление I

Вдохновленный этим, я попробовал следующее вместо xvfb-run -s \"-screen 0 1400x900x24\" python <your_script.py> (который я не мог понять Работа).

xvfb-run -a jupyter notebook

Запуск оригинального скрипта теперь я получаю вместо

GLXInfoException: pyglet requires an X server with GLX

Обновление II

Проблема № 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.


Обновление III

Вдохновленный @ 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, чтобы он подумал, что к нему подключен монитор


Обновление IV

К вашему сведению, в Интернете есть решения с использованием шмеля, которые, похоже, работают. Это должно работать, если у вас есть контроль над сервером, но, поскольку AWS работает на виртуальной машине, я не думаю, что вы можете это использовать.


Обновить V

Просто если у вас есть эта проблема и вы не знаете, что делать (как я), состояние большинства сред достаточно простое, чтобы вы могли создать свой собственный механизм рендеринга. Не очень приятно, но .. знаете ли.


person Toke Faurby    schedule 22.10.2016    source источник
comment
Вы пробовали создать виртуальный экранный буфер, как в очень полезном сообщении об ошибке?   -  person Selali Adobor    schedule 22.10.2016
comment
В том-то и дело, я не знаю, как это сделать. В руководствах, которые я просмотрел, я не понимаю, как заставить его работать через сервер.   -  person Toke Faurby    schedule 22.10.2016
comment
Я обновил сообщение своей попыткой   -  person Toke Faurby    schedule 23.10.2016
comment
Я тоже застрял здесь, любая помощь будет принята с благодарностью :)   -  person vgoklani    schedule 04.11.2016
comment
Просто предупреждаю, @TokeFaurby, ваше решение устарело с 23 декабря 2016 года. Чтобы это работало, вам нужно использовать немного другой API и другой подход. Я думаю, что ваш подход больше не будет работать, поскольку класс VideoRecorder как часть env.wrapper.Monitor теперь вызывает env.render напрямую.   -  person mpacer    schedule 12.06.2017


Ответы (14)


Получил простое решение:

CartPole

If on a linux server, open jupyter with
$ xvfb-run -s "-screen 0 1400x900x24" jupyter notebook
In Jupyter
import matplotlib.pyplot as plt
%matplotlib inline
from IPython import display
After each step
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.env в show_state.

person Andrew Schreiber    schedule 19.07.2017
comment
Работает хорошо, спасибо, но env по-прежнему открывается во внешнем окне (я запускаю его локально, а не на удаленном сервере). Есть идеи, как это предотвратить? - person Lucas; 23.09.2017
comment
Я получаю ошибки /bin/xvfb-run: line 181: 0: command not found и /bin/xvfb-run: line 186: kill: (31449) - No such process. Любая идея? - person Afshin Oroojlooy; 16.10.2018
comment
Что означает 24 в 1400x900x24? Я предполагаю, что 1400 - ширина монитора, а 900 - высота монитора. - person Nathan; 22.08.2019
comment
24 определяет разрядность виртуального монитора - см. здесь - person BrandonHoughton; 23.08.2019
comment
Моя проблема возникает на этапе рендеринга: env = gym.make ('CartPole-v0'); env.render (режим = 'rgb_array'); дает мне ValueError: длина массива должна быть ›= 0, а не -48424951659315200 - person John Jiang; 25.10.2020

Эта проблема 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 для каждой позиции, и imshow imshow (или другие методы) matplotlib прекрасно их отображают.

Обратите внимание, что если вы отрисовываете несколько раз в одной и той же ячейке, это решение будет каждый раз строить отдельное изображение. Вероятно, это не то, что вам нужно. Я постараюсь обновить это, если найду способ обходного пути.

Обновите, чтобы отображать несколько раз в одной ячейке

На основе этот ответ 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)
person Nathan    schedule 08.06.2017
comment
Вы действительно пытались запустить это через сервер? Или вы тестировали это только на своей локальной машине? То, что вы предлагаете, по сути то же самое, что и в Обновлении II. Проблема в том, что env.render() импортирует gl_info за кулисами, даже если окно не открывается. mode=rgb_array это не меняет - person Toke Faurby; 08.06.2017
comment
Ах, я не пробовал на сервере AWS; у того, который я использовал, должно быть что-то настроено по-другому, чтобы я не получал ту же ошибку. Извини это не помогло - person Nathan; 08.06.2017
comment
@Nathan, с вашим решением возникла дополнительная проблема. У некоторых env есть способы обойти создание окна, а у других - нет. Например, если вы хотите попробовать это, замените env = gym.make('Breakout-v0') на env = gym.make('CartPole-v0') в своих примерах, и вы поймете, что я имею в виду. «Breakout» - это игра atari, которая использует atari_py.ALEInterface() в качестве средства визуализации и возвращает изображение. см. github.com/openai/gym/blob / master / gym / envs / atari / - person mpacer; 12.06.2017

Мне удалось запустить и визуализировать 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)
person Van    schedule 13.01.2018
comment
Так что, на всякий случай, это тоже сработало для классического управления? - person Toke Faurby; 14.01.2018
comment
С классическим элементом управления, таким как CartPole, вы можете попробовать ssh -X username @ hostname и выполнить рендеринг напрямую. - person Van; 19.01.2018
comment
Я получал ошибку ContextException: Could not create GL context remote, и ни одно из других решений не помогло мне, но это сработало отлично. - person Omegastick; 09.05.2018

Я думаю, нам следует просто записывать рендеры в виде видео с помощью OpenAI Gym wrappers.Monitor, а затем отображать их в Блокноте.

Пример:

Зависимости

!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")

Я надеюсь, что это помогает. ;)

person Trần Lê Thái Sơn    schedule 05.07.2018
comment
Я получаю NameError: Невозможно получить доступ: /tmp/SpaceInvaders-v0/openaigym.video.4.10822.video000000.mp4 в конце после запуска всего. Любая идея? - person user2997154; 15.10.2019
comment
Проверьте имя файла в /tmp/SpaceInvaders-v0. Название видео может быть другим. В качестве альтернативы укажите известную папку для env = wrappers.Monitor(env, "/tmp/SpaceInvaders-v0") - person Senthilkumar Gopal; 24.02.2020
comment
Это также не работает с классическим элементом управления, таким как CartPole-v0: ValueError: длина массива должна быть ›= 0, а не -48424951659315200 - person John Jiang; 25.10.2020

Также существует это решение, использующее pyvirtualdisplay (оболочку Xvfb). Что мне нравится в этом решении, так это то, что вы можете запускать его изнутри вашего скрипта, вместо того, чтобы оборачивать его при запуске:

from pyvirtualdisplay import Display
display = Display(visible=0, size=(1400, 900))
display.start()
person mdaoust    schedule 25.12.2017
comment
Я получил эту ошибку: ValueError: недопустимый литерал для int () с базой 10: '' - person Crispy13; 20.02.2020

Я сам с этим столкнулся. Использование xvfb в качестве X-сервера как-то конфликтует с драйверами Nvidia. Но, наконец, этот пост указал мне правильное направление. Xvfb работает без проблем, если вы устанавливаете драйвер Nvidia с параметром -no-opengl-files и CUDA с параметром --no-opengl-libs. Если вы это знаете, это должно сработать. Но так как мне потребовалось некоторое время, чтобы понять это, похоже, что я не единственный, кто сталкивается с проблемами с xvfb и драйверами nvidia.

Я записал все необходимые шаги для настройки всего на экземпляре AWS EC2 с Ubuntu 16.04 LTS здесь.

person I_like_foxes    schedule 13.11.2016
comment
Я следовал руководству изо всех сил, но не смог заставить его работать. Единственная разница в том, что я не собирал TF из исходников, но, поскольку эта проблема не связана, я не думаю, что это имеет значение. - person Toke Faurby; 12.05.2017
comment
Жаль это слышать. Поскольку AMI Amazon Deep Learning теперь содержит версию Tensor Flow с поддержкой графического процессора, я бы рекомендовал начать с этого момента: aws.amazon.com/marketplace/pp/B01M0AXXQB Но если вы все же хотите выполнить настройку с нуля, предоставьте дополнительную информацию о проблемах, с которыми вы столкнулись, чтобы я мог вам помочь. - person I_like_foxes; 14.05.2017

Я избежал проблем с использованием matplotlib, просто используя PIL, Python Image Library:

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

Я обнаружил, что мне не нужно устанавливать буфер кадра XV.

person Doug Blank    schedule 08.01.2018
comment
Я очень сомневаюсь, что это работает на безголовом сервере. Проблема в функции env.render, PIL не имеет к ней никакого отношения. - person Toke Faurby; 19.01.2018
comment
Извините, не заметил, что вы использовали SpaceInvaders-v0. Эта проблема вызвана только некоторой средой, например классическим управлением. Я отредактировал OP соответствующим образом - person Toke Faurby; 19.01.2018
comment
Да, теперь я понимаю, что мой ответ работает только с некоторыми моделями. Обидно и ограничение спортзала. - person Doug Blank; 20.01.2018

Я искал решение, которое работает в 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:

Вы можете использовать xvfbwrapper для среды Cartpole.

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 (), который кажется медленным.

person martinenzinger    schedule 22.09.2018
comment
Он работает с SpaceInvaders-v0, но когда я звоню CartPole-v0 или Pendulum-v0, я получаю NameError: name 'base' is not defined. Любая идея? - person Afshin Oroojlooy; 16.10.2018
comment
@AfshinOroojlooy попробуйте !apt-get install python-pyglet && pip install pyglet, а затем перезапустите среду выполнения - person Shadi; 23.01.2019
comment
@shadi, спасибо за ответ. Решил эту проблему некоторое время назад. - person Afshin Oroojlooy; 23.01.2019

Ссылаясь на мой другой ответ здесь: Отображать тренажерный зал OpenAI только в ноутбуке Jupyter < / а>

Я сделал здесь быстрый рабочий пример, который вы можете разветвить: 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 cell, либо загрузите ее с сервера в какое-нибудь место, где вы сможете просмотреть видео.

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 в папке с результатами в спортзале и просто смотреть видео там.

person Eoin Murray    schedule 11.01.2019

Я столкнулся с той же проблемой и нашел здесь ответы. Их смешивание помогло мне решить проблему.

Вот пошаговое решение:

Установите следующее:

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)

Надеюсь, это сработает для всех, кто все еще сталкивается с проблемой. Благодаря Эндрюсу и Натану за их ответы.

person suvigyavijay    schedule 17.04.2020
comment
Это решение, наконец, сработало для меня, но я получил ошибку AttributeError: 'ImageData' object has no attribute 'data', и установка pyglet-v1.3.2 устранила это для меня из решения по здесь. - person David; 09.07.2020

У меня была такая же проблема и решение I_like_foxes для переустановки драйверов nvidia без каких-либо исправлений opengl. Вот команды, которые я использовал для Ubuntu 16.04 и GTX 1080ti https://gist.github.com/8enmann/931ec2a9dc45fde871d2139a7d1f2d78

person Ben    schedule 03.08.2017

Возможно, это полный обходной путь, но я использовал образ докера с окружением рабочего стола, и он отлично работает. Образ докера находится по адресу 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.

Ниже приведена гифка, показывающая, как работает и визуализируется тренажерный зал братьев Марио. Как видите, он довольно отзывчивый и плавный.

введите описание изображения здесь

person Costa Huang    schedule 19.03.2019

Я создал этот мини-пакет, который позволяет отображать вашу среду в браузере, просто добавив одну строку в ваш код.

Поместите свой код в функцию и замените обычный 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(), и вы сможете увидеть визуализированную среду в окне браузера.

введите описание изображения здесь

person Dhruv Ramani    schedule 10.09.2020
comment
Ваша библиотека не работает. Когда я открыл браузер, я не увидел там окружение. - person David Lasry; 06.02.2021
comment
Библиотека, которая не работает, обычно связана с вашим env. Режим рендеринга rgb_array может быть не реализован. Это особенно актуально для не тренажерных залов на основе mujoco. - person Dhruv Ramani; 07.02.2021

В моей среде IPython решение Эндрю Шрайбера не может отображать изображение плавно. Вот мое решение:

Если на сервере Linux, откройте jupyter с помощью

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

В Jupyter

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)
person Tom    schedule 26.08.2018
comment
Это решение дает мне NameError: name 'base' is not defined. Любая идея? - person Afshin Oroojlooy; 16.10.2018