Introducción al aprendizaje por refuerzo. Parte 4: Double DQN y Dueling DQN.

Markel Sanz Ausin
7 min readApr 14, 2020

En la parte 3 hemos visto cómo funciona el algoritmo DQN, y cómo éste puede aprender a solucionar problemas complejos. En esta parte veremos dos nuevos algoritmos que suponen mejoras respecto a DQN, son Double DQN y Dueling DQN. Pero antes, introduzcamos algunos términos que hemos pasado por alto.

Los algoritmos de aprendizaje por refuerzo se pueden clasificar en varias familias. La primera de estas familias depende de si el algoritmo aprende cómo funciona el entorno de manera explícita o no. Si el algoritmo utiliza la dinámica del entorno (también conocido como modelo) durante la toma de decisiones, entonces el algoritmo es basado en el modelo (model based), y si no lo hace será libre de modelo (model free). Un algoritmo basado en el modelo tiene que aprender (o tener acceso a) todas las probabilidades de transición de un estado a otro. Como muchos entornos son estocásticos (probabilísticos) y sus dinámicas desconocidas, el algoritmo debe aprender el modelo detrás de estas transiciones probabilísticas. Una vez aprendidas, utilizará esa información para tomar mejores decisiones. Por ejemplo, si tomar la acción 1 te llevará al estado A con probabilidad 0.9 y recibirás una recompensa de -10, o te llevará al estado B con una probabilidad de 0.1 y recibirás recompensa de +10; pero tomar la acción 2 te llevará al estado C con probabilidad de 1.0 y obtendrás una recompensa de +5, la mejor decisión es tomar la acción 2, ya que aunque la posible recompensa del estado B es muy grande, la probabilidad de terminar en ese estado es muy baja. Por lo tanto, no solo es importante usar las recompensas en la toma de decisiones, sino también el modelo. En el futuro hablaremos más de los algoritmos basados en el modelo.

La segunda familia en la que se pueden clasificar los algoritmos son fuera-de-la-política (off policy) y dentro-de-la-política (on-policy). Los algoritmos fuera-de-la-política aprenden la función de valor (value function), sin importar qué acciones tome el agente. Es decir, que la política de comportamiento (behavior policy) y la política objetivo (target policy) pueden ser distintas. La primera es la que utiliza el agente para explorar el entorno y recoger datos, mientras que la segunda es la que el agente intenta aprender y mejorar. Ésto significa que el agente puede explorar el entorno de forma completamente aleatoria con la política de comportamiento, y usar esos datos para aprender una política objetivo que sea capaz de obtener una recompensa muy alta en el futuro. En los algoritmos dentro-de-la-política, la política de comportamiento y la objetivo deben ser las mismas. Los algoritmos aprenden de los datos que deben recibir tras seguir la misma política que están aprendiendo.

A partir de ahora, clasificaremos los algoritmos en estas dos familias. Por ejemplo, tanto el algoritmo Q-Learning como DQN son algoritmos libre de modelo y fuera-de-la-política. Los dos algoritmos que veremos en esta parte, Double DQN y Dueling DQN, también son algoritmos libre de modelo y fuera-de-la-política.

Double DQN [1]

El problema con el algoritmo DQN es que sobreestima las recompensas reales; es decir, los valores-Q que aprende piensan que van a obtener una recompensa mayor de lo que en realidad obtendrá. Para solucionarlo, los autores del algoritmo Double DQN [1] proponen un sencillo truco: separar la selección y evaluación de la acción en dos pasos diferentes. En lugar de usar la ecuación de Bellman del algoritmo DQN, este algoritmo la cambia y se convierte en:

Imagen 1: La ecuación de Bellman para el algoritmo Double DQN.

Primero la red neuronal principal θ decide cuál es la mejor acción entre todas las posibles, y luego la red objetivo evalúa esa acción para conocer su valor-Q. Este simple cambio ha demostrado reducir las sobreestimaciones y resultar en mejores políticas.

Dueling DQN [2]

Este algoritmo divide los valores-Q en dos partes distintas, la función de valor (value function) V(s) y la función de ventaja (advantage function) A(s, a).

La función de valor V(s) nos dice cuánta recompensa obtendremos desde el estado s. La función de ventaja A(s, a) nos dice cuánto mejor es una acción respecto a las demás. Combinando el valor V y la ventaja A de cada acción, obtenemos los valores-Q:

Imagen 2: Definición de la función de ventaja.

Lo que propone el algoritmo Dueling DQN es que la misma red neuronal divida su capa final en dos, una para estimar el valor del estado s (V(s)) y otra para estimar la ventaja de cada acción a (A(s, a)), y al final juntar ambas partes en una sola, la cual estimará los valores-Q. Este cambio ayuda en algunos casos, porque a veces no es necesario saber exactamente al valor de cada acción, por lo que aprender el valor del estado puede ser suficiente.

Imagen 3. Imagen extraída del artículo del algoritmo Dueling DQN [2]. Arriba: arquitectura para DQN. Abajo: arquitectura para Dueling DQN.

Sin embargo, entrenar la red neuronal de esta simple manera, sumando el valor y la ventaja en la capa final, no es posible. Si tenemos Q=V+A, dada la función Q, no podemos determinar V y A, es decir, el problema es “inidentificable. Para ver esto claramente, por ejemplo, si te digo que Q es 20, y tienes que saber qué dos números suman 20 (20 = V + A), hay infinitas posibilidades. Para solucionarlo, el artículo propone un truco: forzar al valor-Q más alto a ser igual al valor V, haciendo que el valor más alto en la función de ventaja sea cero, y los demás valores sean negativos. Esto nos dirá exactamente cuál es el valor de V, y podremos calcular los valores de la función de ventaja desde ahí, solucionando el problema. Así es como se entrenaría el algoritmo:

Imagen 4: Truco para hacer el problema identificable.

Sin embargo, el artículo sugiere un pequeño cambio a estas ecuaciones. En lugar de usar el máximo, usaremos la media de las ventajas, así que eso será lo que hagamos (vea el artículo para más detalles). Así es como entrenaremos el algoritmo:

Imagen 5: Forma alternativa de hacer el problema identificable.

El código

Todo el código que usa TensorFlow lo puedes encontrar y ejecutar en este enlace (o la versión que usa PyTorch en este enlace).

Solucionaremos uno del los juegos de la saga Atari 2600 usando OpenAI Gym. El juego que he seleccionado es el de Pong, ya que es fácil de visualizar y entender, y es uno de los juegos más sencillos de solventar con aprendizaje por refuerzo profundo. Usaremos el código de la parte 3 como referencia. Pero esta vez cambiaremos la arquitectura de la red neuronal para dividir la capa final en dos, las funciones de valor y de ventaja (V y A en el código), y luego combinarlas para formar los valores-Q. También cambiaremos los tipos de capas de la red neuronal. Como el agente aprenderá directamente de los pixeles, las capas densas (dense o fully connected) no son la mejor opción. Usaremos capas convolucionales. El número de unidades en cada capa y los parámetros será el mismo que en el artículo Dueling DQN [2].

Algoritmo 1: arquitectura de la red convolucional para Dueling DQN.

Después, cambiaremos la función que ejecuta un paso de entrenamiento usando el descenso de gradiente. La modificaremos para implementar el paso de entrenamiento del algoritmo Double DQN en lugar del DQN normal. Esto significa que la ecuación de Bellman será la descrita anteriormente en este artículo, que es ligeramente diferente a la descrita en la parte 3.

Algoritmo 2: paso de entrenamiento para la ecuación de Bellman de Double DQN.

Ejecutaremos el bucle principal de entrenamiento de la misma forma que en las partes anteriories, recogiendo datos y guardándolos en el buffer para usarlos más tarde. Tras entrenar el algoritmo durante 1000 episodios, esto será lo que escriba. El retorno indica cuantos goles ha marcado cada jugador.

Episode: 0/1000, Epsilon: 0.999, Loss: 0.0296, Return: -21.00 Episode: 100/1000, Epsilon: 0.897, Loss: 0.0008, Return: -20.21 Episode: 200/1000, Epsilon: 0.787, Loss: 0.0031, Return: -19.93 Episode: 300/1000, Epsilon: 0.655, Loss: 0.0025, Return: -18.96 Episode: 400/1000, Epsilon: 0.496, Loss: 0.0031, Return: -17.66 Episode: 500/1000, Epsilon: 0.297, Loss: 0.0026, Return: -15.86 Episode: 600/1000, Epsilon: 0.010, Loss: 0.0088, Return: -9.10 Episode: 700/1000, Epsilon: 0.010, Loss: 0.0057, Return: 5.80 Episode: 800/1000, Epsilon: 0.010, Loss: 0.0011, Return: 12.86 Episode: 900/1000, Epsilon: 0.010, Loss: 0.0008, Return: 15.87 Episode: 1000/1000, Epsilon: 0.010, Loss: 0.0011, Return: 18.98

Y si visualizamos el resultado jugando una vez más y grabando los píxeles, veremos cómo se comporta nuestro agente (en verde).

Para ver todo el código de TensorFlow, sigue este enlace (o este enlace para la versión de PyTorch).

Referencias:

[1] Van Hasselt, Hado, Arthur Guez, and David Silver. “Deep reinforcement learning with double q-learning.” Thirtieth AAAI conference on artificial intelligence. 2016

[2] Wang, Ziyu, et al. “Dueling network architectures for deep reinforcement learning.” arXiv preprint arXiv:1511.06581 (2015)

Sutton, R. S., & Barto, A. G. (2018). Reinforcement learning: An introduction. MIT press.

Mi repositorio de GitHub con algoritmos frecuentes de aprendizaje por refuerzo profundo (en desarrollo): https://github.com/markelsanz14/independent-rl-agents

--

--