En este proyecto se implementarán tres modelos de DRL en un mismo entorno, con el objetivo de analizar distintas formas de aprendizaje de un agente y estudiar su rendimiento. El agente será entrenado con los métodos:
Uno de los objetivos más actuales del campo de la robótica es conseguir que un robot sea capaz de aprender a realizar una serie de acciones por si sólo, del mismo modo que lo hace un niño pequeño. Esta es, básicamente, una de las principales motivaciones del aprendizaje por refuerzo profundo. Para ello se necesitan sistemas de control eficientes, especialmente para tareas complejas como pueden ser un despegue o un aterrizaje propio de drones autónomos y cohetes espaciales, y de un posible futuro transporte urbano, o de los cohetes espaciales reutilizables.
Con esta idea, usaremos un entorno ya predefinido en OpenAI, el Lunar Lander.
Lunar Lander consiste en una nave espacial que debe aterrizar en un lugar determinado del campo de observación. El agente conduce la nave y su objetivo es conseguir aterrizar en la pista de aterrizaje, coordenadas (0,0), y llegar con velocidad 0 (es decir, no debe estamparse contra el suelo). La nave consta de tres motores (izquierda, derecha y el principal que tiene debajo) que le permiten ir corrigiendo su rumbo hasta llegar a destino.
Las acciones que puede realizar la nave (espacio de acciones) son discretas y se categorizan según:
Las recompensas obtenidas a lo largo del proceso de aterrizaje dependen de las acciones que se toman y del resultado que se deriva de ellas. Así:
Para más detalles sobre la definición del entorno de Lunar Lander, se recomienda consultar el código fuente: https://github.com/openai/gym/blob/master/gym/envs/box2d/lunar_lander.py
La solución óptima es aquella en la que el agente, con un desplazamiento eficiente, consigue aterrizar en la zona de aterrizaje (0,0), tocando con las dos patas en el suelo y con velocidad nula. Se considera que el agente ha aprendido a realizar la tarea (i.e. el "juego" termina) cuando obtiene una media de almenos 200 puntos durante 100 episodios consecutivos.
IMPORTANTE: el entorno Lunar Lander requiere de la librería box2d-py
:
conda install swig
y luego pip install box2d-py
desde la terminal !pip install box2d-py
Empezaremos cargando las principales librerías necesarias para la práctica:
import gym
import matplotlib.pyplot as plt
%matplotlib inline
!pip install box2d-py
!pip install torch
import torch
import numpy as np
import io
import time
Requirement already satisfied: box2d-py in /Users/rubenperezibanez/.virtualenvs/openia/lib/python3.8/site-packages You are using pip version 9.0.1, however version 20.3.1 is available. You should consider upgrading via the 'pip install --upgrade pip' command. Requirement already satisfied: torch in /Users/rubenperezibanez/.virtualenvs/openia/lib/python3.8/site-packages Requirement already satisfied: numpy in /Users/rubenperezibanez/.virtualenvs/openia/lib/python3.8/site-packages (from torch) Requirement already satisfied: future in /Users/rubenperezibanez/.virtualenvs/openia/lib/python3.8/site-packages (from torch) Requirement already satisfied: typing-extensions in /Users/rubenperezibanez/.virtualenvs/openia/lib/python3.8/site-packages (from torch) Requirement already satisfied: dataclasses in /Users/rubenperezibanez/.virtualenvs/openia/lib/python3.8/site-packages (from torch) You are using pip version 9.0.1, however version 20.3.1 is available. You should consider upgrading via the 'pip install --upgrade pip' command.
env = gym.make('LunarLander-v2')
print("Action space is {
} ".format(env.action_space))
print("Observation space is {} ".format(env.observation_space))
print("Reward range is {
} ".format(env.reward_range))
obs = env.reset()
print("Obs inicial: {
} ".format(obs))
print("Máximo de pasos establecidos por cada episodio es {}".format(env._max_episode_steps))
print("rThresh {
}".format(env.spec.reward_threshold))
print("Número maximo de episodios {}".format(env.spec.max_episode_steps))
#1- Fire left engine
#2- Fire down engine
#3- Fire right engine
Action space is Discrete(4) Observation space is Box(-inf, inf, (8,), float32) Reward range is (-inf, inf) Obs inicial: [-0.00469522 1.4010352 -0.4755985 -0.43933803 0.00544746 0.10773007 0. 0. ] Máximo de pasos establecidos por cada episodio es 1000 rThresh 200 Número maximo de episodios 1000
Environment Id | Observation Space | Action Space | Reward Range | tStepL | Trials | rThresh |
---|---|---|---|---|---|---|
LunarLander-v2 | Box(8,) | Discrete(4) | (-inf, inf) | 1000 | 100 | 200 |
env.render()
, sólo posible en local from gym.wrappers import Monitor
from IPython.display import HTML
import glob
from IPython import display as ipythondisplay
def show_video(iteration):
mp4list = glob.glob('video/'+str(iteration)+'/*.mp4')
if len(mp4list) > 0:
mp4 = mp4list[0]
video = io.open(mp4, 'r+b').read()
encoded = base64.b64encode(video)
ipythondisplay.display(HTML(data='''<video alt="test" autoplay
loop controls style="height: 400px;">
<source src="data:video/mp4;base64,{0}" type="video/mp4" />
</video>'''.format(encoded.decode('ascii'))))
else:
print("Could not find video")
def wrap_env(env, iteration):
env = Monitor(env, './video/'+str(iteration)+'/', force=True)
return env
import base64
num_episodes = 10 # number of episodes
max_steps_ep = 10000 # default max number of steps per episode (unless env has a lower hardcoded limit)
scores = []
q_estado= {
0 : 'No hacer nada',
1 : 'Encender motor izquierdo',
2 : 'Encender motor principal',
3 : 'Encender motor derecho',
}
actions = range(env.action_space.n)
for i in range(1, num_episodes+1):
env = gym.make('LunarLander-v2')
env = wrap_env(env,i)
state = env.reset()
score = 0
max_steps_ep = 0
while max_steps_ep<100:
max_steps_ep= max_steps_ep +1
action = np.random.choice(actions)
print(state)
print('Observation:'+ str(state) +',[..] , Action: '+ q_estado[action])
state, reward, done, info = env.step(action)
score += reward
if done:
break
if not done:
env.stats_recorder.save_complete()
env.stats_recorder.done = True
env.close()
print('Episode {}, score: {}'.format(i, score))
scores.append(score)
show_video(i)
[-0.00505362 1.4081988 -0.51190066 -0.12095536 0.00586276 0.11595318 0. 0. ] Observation:[-0.00505362 1.4081988 -0.51190066 -0.12095536 0.00586276 0.11595318 0. 0. ],[..] , Action: Encender motor principal [-0.01010981 1.406129 -0.511427 -0.09202451 0.01160524 0.11486121 0. 0. ] Observation:[-0.01010981 1.406129 -0.511427 -0.09202451 0.01160524 0.11486121 0. 0. ],[..] , Action: Encender motor principal [-0.01501703 1.4049863 -0.49730262 -0.0508507 0.01811743 0.13025592 0. 0. ] Observation:[-0.01501703 1.4049863 -0.49730262 -0.0508507 0.01811743 0.13025592 0. 0. ],[..] , Action: Encender motor derecho [-0.01984406 1.4032533 -0.48723984 -0.07708253 0.02260368 0.08973332 0. 0. ] Observation:[-0.01984406 1.4032533 -0.48723984 -0.07708253 0.02260368 0.08973332 0. 0. ],[..] , Action: Encender motor derecho [-0.02460146 1.400935 -0.47850528 -0.10307984 0.02533128 0.05455685 0. 0. ] Observation:[-0.02460146 1.400935 -0.47850528 -0.10307984 0.02533128 0.05455685 0. 0. ],[..] , Action: Encender motor derecho [-0.02926893 1.398013 -0.46721107 -0.12987505 0.02579436 0.00926276 0. 0. ] [...] Omitimos observaciones. [...] Observation:[-0.43387985 -0.07387536 -0.5512465 -1.311351 -0.21424979 0.1502227 1. 1. ],[..] , Action: Encender motor izquierdo [-0.43909368 -0.10260568 -0.5349258 -1.2755606 -0.20388208 0.20340443 1. 1. ] Observation:[-0.43909368 -0.10260568 -0.5349258 -1.2755606 -0.20388208 0.20340443 1. 1. ],[..] , Action: Encender motor principal Episode 1, score: -98.28223206017314
Además, he dejado en la carpeta video los diferentes videos sobre la ejecución del programa.
import base64
!pip install tqdm
num_episodes = 1000 # number of episodes
max_steps_ep = 10000 # default max number of steps per episode (unless env has a lower hardcoded limit)
scores = []
numero_pasos = []
actions = range(env.action_space.n)
from tqdm import tqdm
for i in tqdm(range(1, num_episodes+1)):
env = gym.make('LunarLander-v2')
state = env.reset()
score = 0
max_steps_ep = 0
while max_steps_ep< env._max_episode_steps:
max_steps_ep= max_steps_ep +1
action = np.random.choice(actions)
state, reward, done, info = env.step(action)
score += reward
if done:
break
env.close()
#print('Episode {}, score: {}'.format(i, score))
scores.append(score)
numero_pasos.append(max_steps_ep)
Requirement already satisfied: tqdm in /Users/rubenperezibanez/.virtualenvs/openia/lib/python3.8/site-packages
You are using pip version 9.0.1, however version 20.3.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
100%|██████████| 1000/1000 [00:28<00:00, 34.79it/s]
import matplotlib.pyplot as plt
plt.xlabel('Recompensa')
plt.ylabel('Cantidad')
plt.title('Histograma con la suma de recompensas de cada episodio')
plt.grid(True)
plt.hist(scores, bins =100)
plt.show()