Logo web 1938
 

Deep Reinforcement. .

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:

  • DQN doble (DDQN)
  • Dueling DQN
  • REINFORCE con línea de base

Contexto

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.

title

Las acciones que puede realizar la nave (espacio de acciones) son discretas y se categorizan según:

  • 0 : No hacer nada
  • 1 : Encender motor izquierdo
  • 2 : Encender motor principal
  • 3 : Encender motor derecho

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í:

  • Desplazarse de arriba a abajo, hasta la zona de aterrizaje puede resultar en +100...+140 puntos
  • Si se estrella, pierde -100 puntos
  • Si consigue aterrizar en la zona de aterrizaje (velocidad 0), gana +100 puntos
  • Si aterriza pero no en la zona de aterrizaje (fuera de las banderas amarillas) se pierden puntos
  • El contacto de una pata con el suelo recibe +10 puntos (si se pierde contacto después de aterrizar, se pierden puntos)
  • Cada vez que enciende el motor principal pierde -0.3 puntos
  • Cada vez que enciende uno de los motores de izquierda o derecha, pierde -0.03 puntos

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.

Inicialización y exploración del entorno

IMPORTANTE: el entorno Lunar Lander requiere de la librería box2d-py:

  • En local: instalar conda install swig y luego pip install box2d-py desde la terminal
  • En Google Colab: iniciar siempre notebook con !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.
Inicializar el entorno 'Lunar-Lander-v2'. Extraer el valor del umbral de recompensa definido en el entorno, el rango de recompensas permitido, el máximo de pasos establecidos por cada episodio, la dimensión del espacio de acciones, y la dimensión del espacio de observación.
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 IdObservation SpaceAction SpaceReward RangetStepLTrialsrThresh
LunarLander-v2Box(8,)Discrete(4)(-inf, inf)1000100200
Mostrar la representación vectorial de cada observación del entorno junto con la acción aleatoria seleccionada (ej. 'Observation: [..] , Action: Fire down engine'), en un intervalo de 10 episodios de 100 pasos cada uno. Opcional: visualizar los 10 episodios 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.

Ejecutar 1000 episodios con el máximo de pasos establecido en el entorno de Lunar Lander, tomando acciones de forma aleatoria. Almacenar la suma de recompensas de cada episodio y los pasos que han sido necesarios para completar el episodio. Mostrar:
  • Histograma con la suma de recompensas de cada episodio
  • Histograma con los pasos que han sido necesarios para completar el episodio
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()