web-dev-qa-db-fra.com

Comment exécuter OpenAI Gym .render () sur un serveur

J'exécute un script python 2.7 sur un serveur p2.xlarge AWS via Jupyter (Ubuntu 14.04). J'aimerais pouvoir rendre mes simulations.

Exemple de travail minimal

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

env.render() commet (entre autres choses) les erreurs suivantes:

...
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"

Je voudrais savoir comment être capable de voir les simulations. Ce serait idéal si je pouvais le mettre en ligne, mais n'importe quelle méthode d'affichage serait bien.

Edit: ce problème ne concerne que certains environnements, comme le contrôle classique.


Mise à jour I

Inspiré par this J'ai essayé ce qui suit au lieu du xvfb-run -s \"-screen 0 1400x900x24\" python <your_script.py> (que je n'ai pas pu me mettre au travail).

xvfb-run -a jupyter notebook

Exécuter le script original que je reçois maintenant à la place

GLXInfoException: pyglet requires an X server with GLX

Mise à jour II

Problème # 154 semble pertinent. J'ai essayé de désactiver la fenêtre contextuelle et de créer directement les couleurs RVB

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

Je reçois ImportError: cannot import name gl_info.


Mise à jour III

En m'inspirant de @ Torxed , j'ai essayé de créer un fichier vidéo, puis de le rendre (solution tout à fait satisfaisante).

Utilisation du code de ' Enregistrement et téléchargement des résultats

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()

J'ai essayé de suivre vos suggestions, mais j'ai obtenu ImportError: cannot import name gl_info lors de l'exécution de env.monitor.start(...

D'après ma compréhension, le problème est que OpenAI utilise pyglet et que pyglet 'a besoin d'un écran pour calculer les couleurs RVB de l'image à restituer. Il faut donc tromper python pour penser qu'il y a un moniteur connecté


Mise à jour IV

Pour votre information, il existe des solutions en ligne utilisant bourdon qui semblent fonctionner. Cela devrait fonctionner si vous avez le contrôle sur le serveur, mais comme AWS est exécuté sur un VM, je ne pense pas que vous puissiez l'utiliser.


Update V

Si vous avez ce problème et que vous ne savez pas quoi faire (comme moi), l'état de la plupart des environnements est assez simple pour que vous puissiez créer votre propre mécanisme de rendu. Pas très satisfaisant, mais .. vous savez.

43
Toke Faurby

Vous avez une solution simple qui fonctionne:

CartPole

$ 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())

Remarque: si votre environnement n'est pas unwrapped, transmettez env.env à show_state.

19
Andrew Schreiber

J'ai réussi à exécuter et à rendre openai/gym (même avec mujoco) à distance sur un serveur sans tête.

# 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

Usage:

DISPLAY=:0 ipython2

Exemple:

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)
9
Van

Ce problème GitHub a donné une réponse qui a très bien fonctionné pour moi. C'est agréable car il ne nécessite aucune dépendance supplémentaire (je suppose que vous avez déjà matplotlib) ou configuration du serveur.

Il suffit de courir, par exemple:

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()

Utiliser mode='rgb_array' vous restitue un numpy.ndarray avec les valeurs RVB pour chaque position, et matplotlib's imshow (ou d'autres méthodes) les affichent bien.

Notez que si vous rendez plusieurs fois dans la même cellule, cette solution trace une image distincte à chaque fois. Ce n'est probablement pas ce que vous voulez. Je vais essayer de mettre à jour cela si je trouve une bonne solution de contournement pour cela.

Mise à jour pour rendre plusieurs fois dans une cellule

Sur la base de la réponse this StackOverflow, voici un extrait fonctionnel (notez qu'il peut exister des moyens plus efficaces de le faire avec un tracé interactif; cette manière semble un peu lente sur ma machine):

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)

Mise à jour pour augmenter l'efficacité

Sur ma machine, c'était environ 3 fois plus vite. La différence est qu'au lieu d'appeler imshow à chaque rendu, nous modifions simplement les données RVB du tracé d'origine.

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)
8
Nathan

Je suis tombé dessus moi-même. Utiliser xvfb en tant que serveur X se heurte quelque peu aux pilotes Nvidia . Mais finalement ce message m’a orienté dans la bonne direction .. Xvfb fonctionne sans aucun problème si vous installez le pilote Nvidia avec le L'option -no-opengl-files et CUDA avec l'option --no-opengl-libs . Si vous le savez, cela devrait fonctionner. Mais comme cela m’a pris un certain temps avant de comprendre cela, il semble que je ne sois pas le seul à avoir des problèmes avec xvfb et les pilotes nvidia.

J'ai noté toutes les étapes nécessaires pour tout configurer sur une instance AWS EC2 avec Ubuntu 16.04 LTS here.

7
I_like_foxes

Il y a aussi cette solution using pyvirtualdisplay (un wrapper Xvfb). Ce que j’aime dans cette solution, c’est que vous pouvez le lancer depuis votre script au lieu de l’emballer au lancement:

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

Je pense que nous devrions simplement capturer les rendus sous forme de vidéo en utilisant OpenAI Gym wrappers.Monitor.__, puis les afficher dans le bloc-notes.

Exemple:

Les dépendances

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

Capture en vidéo

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()

Afficher dans le cahier

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

J'espère que ça aide. ;)

5

J'ai évité les problèmes d'utilisation de matplotlib en utilisant simplement PIL, Python Image Library:

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

J'ai trouvé que je n'avais pas besoin de définir le tampon d'images XV.

3
Doug Blank

J'ai eu le même problème et la solution I_like_foxes pour réinstaller les pilotes nvidia sans aucun problème fixe opengl. Voici les commandes que j'ai utilisées pour Ubuntu 16.04 et GTX 1080ti https://Gist.github.com/8enmann/931ec2a9dc45fde871d2139a7d1f2d78

2
Ben

Je cherchais une solution qui fonctionne dans Colaboratory et qui a abouti à cette

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')

EDIT 1:

Vous pouvez utiliser xvfbwrapper pour l'environnement 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()

Si vous travaillez avec Jupyter standard, il existe une meilleure solution. Vous pouvez utiliser CommManager pour envoyer des messages avec des URL de données mises à jour à votre sortie HTML. 

Exemple d'écran en ligne IPython

Dans Colab, CommManager n'est pas disponible. Le module de sortie plus restrictif a une méthode appelée eval_js () qui semble être un peu lente.

1
martinenzinger

Référencer mon autre réponse ici: Afficher uniquement la salle de sport OpenAI dans le cahier Jupyter

J'ai fait ici un exemple pratique rapide que vous pourriez utiliser: https://kyso.io/eoin/openai-gym-jupyter avec deux exemples de rendu dans Jupyter - l'un en tant que mp4 et l'autre en tant que gif en temps réel .

L'exemple .mp4 est assez simple.

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()

Ensuite, dans une nouvelle cellule Jupyter, ou téléchargez-la du serveur sur un emplacement où vous pouvez visionner la vidéo.

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')))

Si vous êtes sur un serveur avec un accès public, vous pouvez exécuter python -m http.server dans le dossier gym-results et simplement regarder les vidéos.

0
Eoin Murray

Dans mon environnement IPython, la solution d'Andrew Schreiber ne peut pas tracer une image en douceur. Voici ma solution:

Si vous êtes sur un serveur linux, ouvrez jupyter avec

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

Dans Jupyter

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

Affichage de l'itération:

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)
0
Tom