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.
Vous avez une solution simple qui fonctionne:
$ 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
.
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)
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.
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)
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)
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.
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()
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:
!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")
J'espère que ça aide. ;)
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.
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
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.
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.
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)