Acceso abierto al libro Torres J.; (2021). Introducción al aprendizaje por refuerzo profundo. Teoría y práctica en Python. WATCH THIS SPACE Book Series. Kindle Direct Publishing. ISBN 9798599775416
En este primer capítulo presentaremos brevemente qué es el aprendizaje por refuerzo profundo y cómo se diferencia de otras aproximaciones al Machine Learning.
También en este primer capítulo se introducirán los conceptos básicos del aprendizaje por refuerzo, y se presentará el entorno Frozen-Lake del paquete Gym, que será el ejemplo base que usaremos para poner en práctica los conceptos y algoritmos que se vayan introduciendo.
1.1 Contexto
En los últimos años se han sucedido avances notorios en inteligencia artificial. Por ejemplo, AlphaGo derrotó al mejor jugador humano profesional en el juego de Go. O hace dos años, por ejemplo, nuestro amigo Oriol Vinyals y su equipo en DeepMind mostraron cómo el agente de AlphaStar vencía a jugadores profesionales en el juego de StarCraft II. O unos meses más tarde, el bot de juego Dota-2 de OpenAI se convirtió en el primer sistema de AI en vencer a los campeones mundiales en un juego de deportes electrónicos. Todos estos sistemas tienen en común que utilizan aprendizaje por refuerzo profundo, Deep Reinforcement Learning (DRL) en inglés. Veamos, en esta sección, qué se entiende por inteligencia artificial y por aprendizaje por refuerzo profundo.
Inteligencia artificial
A veces, la terminología en sí puede dar lugar a confusión. Esto ocurre, por ejemplo, con el término inteligencia artificial, Artificial Intelligence (AI), de cuyo uso se abusa actualmente. Propongo dar un paso atrás para repasar los tipos de aprendizaje automático que pueden realizar los programas ejecutados en supercomputadores como el Marenostrum en el Barcelona Supercomputing Center[1] (BSC).
La inteligencia artificial — que es el principal campo de la informática en el que se enmarca el aprendizaje por refuerzo, Reinforcement Learning(RL) en inglés — es una disciplina que se ocupa de crear programas informáticos que muestren una «inteligencia» similar a la humana. La inteligencia artificial es un área muy amplia. Ni siquiera el libro de texto más autorizado sobre inteligencia artificial, escrito por Stuart Rusell y Peter Norvig, ofrece una definición precisa, y discute definiciones sobre inteligencia artificial desde diferentes perspectivas[2].
Aportando un enfoque más general, podríamos aceptar una definición simple en la que por inteligencia artificial entendiéramos «aquella inteligencia que muestran las máquinas, en contraste con la inteligencia natural de los humanos». En este sentido, una posible definición concisa y general de inteligencia artificial podría ser «el esfuerzo por automatizar las tareas intelectuales que suelen realizar los humanos».
El área de la inteligencia artificial es un campo muy amplio que abarca muchas áreas del conocimiento relacionadas con el aprendizaje automático; incluso se incluyen muchos más enfoques no siempre catalogados como aprendizaje automático. Además, a lo largo del tiempo, a medida que los computadores han sido cada vez más capaces de «hacer cosas», han ido cambiando las tareas o tecnologías consideradas «inteligentes».
Esto explica por qué desde los años 50 la inteligencia artificial ha experimentado varias oleadas de optimismo, seguidas por la decepción y la pérdida de financiación e interés (épocas conocidas como AI winter[3]), y seguidas luego de nuevos enfoques, éxito y financiación. Además, durante la mayor parte de su historia, la investigación en inteligencia artificial se ha dividido en subcampos basados en consideraciones técnicas o herramientas matemáticas concretas y con comunidades de investigación separadas que no se comunicaban suficientemente entre sí.
Machine Learning
Machine Learning (ML), traducido al castellano como aprendizaje automático (aunque yo voy a mantener su nombre en inglés en este libro para concretar más cuando hablo de la disciplina), es en sí mismo un gran campo de investigación y desarrollo. En concreto, Machine Learning se podría definir como «el subcampo de la inteligencia artificial que proporciona a los conputadores la capacidad de aprender sin ser explícitamente programados, es decir, sin que estos necesiten que el programador indique las reglas que deben seguir para lograr su tarea, sino que la hacen automáticamente».
Generalizando, podemos decir que Machine Learning consiste en desarrollar para cada problema un algoritmo de predicción para un caso de uso particular. Estos algoritmos aprenden de los datos con el fin de encontrar patrones o tendencias para comprender qué nos dicen estos datos y, de esta manera, construir un modelo para predecir o clasificar.
Dada la madurez del área de investigación en Machine Learning, existen muchos enfoques bien establecidos para el aprendizaje automático por parte de máquinas. Cada uno de ellos utiliza una estructura algorítmica diferente para optimizar las predicciones basadas en los datos recibidos. En resumen, Machine Learning es un amplio campo con una compleja taxonomía de algoritmos que se agrupan, en general, en tres grandes categorías: aprendizaje supervisado (supervised learning en inglés), aprendizaje no supervisado (unsupervised learning en inglés) y aprendizaje por refuerzo (reinforcement learning en inglés).
Veamos, a continuación, una breve descripción de cada una de estas categorías con el objetivo de enmarcar mejor el aprendizaje por refuerzo dentro de la familia Machine Learning. Si quiere profundizar más en Machine Learning, un buen punto de partida es el libro Python Machine Learning de Sebastian Raschka y Vahid Mirjalili, traducido al español por la editorial Marcombo[4].
Nos referimos a aprendizaje supervisado cuando los datos que usamos para el entrenamiento incluyen la solución deseada, llamada etiqueta (label). En este caso el aprendizaje radica en aprender un modelo (o función) que mapea una entrada a una salida. Un escenario óptimo permitirá que el modelo, una vez entrenado, determine correctamente las etiquetas para datos de entrada no vistos anteriormente. Este modelo se construye con un algoritmo que iterativamente va afinando el modelo mediante la generación de predicciones sobre los datos de entrenamiento y va comparando estas predicciones con la respuesta correcta que el algoritmo conoce. De aquí que se denomine aprendizaje supervisado. En cambio, nos referimos a aprendizaje no supervisadocuando los datos de entrenamiento no incluyen las etiquetas, y es el algoritmo el que intentará clasificar la información por sí mismo.
Hablamos de aprendizaje por refuerzo cuando el modelo se implementa en forma de un agente que deberá explorar un espacio desconocido y determinar las acciones a llevar a cabo mediante «prueba y error». Aprenderá por sí mismo gracias a las recompensas y penalizaciones que obtiene de sus acciones. El agente debe actuar y crear la mejor estrategia posible para obtener la mayor recompensa en tiempo y forma.
Es importante notar que ambos paradigmas de aprendizaje — no supervisado y por refuerzo — requieren que el entrenamiento esté diseñado por un humano. En el caso del aprendizaje no supervisado, se definen los objetivos (por ejemplo, obtener la agrupación correcta para una imagen); en el caso del aprendizaje por refuerzo, se definen las recompensas por un comportamiento exitoso (por ejemplo, obtener una puntuación alta en un juego). Por lo tanto, los «entrenadores humanos», aunque no intervienen directamente en el bucle del aprendizaje, sí definen los límites del aprendizaje en ambos casos. Entraremos en detalle sobre esto, ya que es el tema central del libro.
Pero, como decíamos, la taxonomía es muy amplia y podríamos incluso mencionar otras categorías, como el aprendizaje autosupervisado (self-supervised learning), que podríamos considerar una instancia específica del aprendizaje supervisado. Es como un aprendizaje supervisado pero las etiquetas no están anotadas por humanos, sino por sistemas automáticos a partir de otros datos o heurísticas. En todo caso, podríamos catalogar en este grupo las técnicas que no requieren a humanos en el bucle de aprendizaje.
Deep Learning
Ortogonal a esta categorización, podemos considerar una poderosa aproximación al ML llamada Deep Learning (DL) en inglés, o aprendizaje profundo. Usaremos ambos términos a lo largo del libro, puesto que ambos son usados indistintamente en los libros sobre el tema en lengua española.
Los algoritmos de Deep Learning se basan en redes neuronales artificiales, cuyas estructuras algorítmicas permiten que modelos compuestos por múltiples capas de procesamiento aprendan representaciones de datos con varios niveles de abstracción.
DL no es una rama de ML separada, por lo que no está destinada a una tarea diferente a las descritas anteriormente. Podríamos ver el DL como una colección de técnicas y métodos para usar redes neuronales que resuelven tareas de aprendizaje automático, ya sea aprendizaje supervisado, aprendizaje no supervisado o aprendizaje por refuerzo. Podemos representar gráficamente esta idea de forma sintética, como vemos en la Figura 1.1.
Si quiere profundizar más en Deep Learning, un buen punto de partida es el libro Python Deep Learning, publicado en español por la editorial Marcombo[5].
Aprendizaje por refuerzo profundo
El Deep Learning es una de las mejores herramientas que tenemos hoy en día para aprender de grandes cantidades de datos o descubrir patrones en entornos no estructurados. Pero esto no es una toma de decisiones; es un problema de reconocimiento. El aprendizaje por refuerzo proporciona esta función, la de tomar decisiones.
En realidad, el aprendizaje por refuerzo puede resolver los problemas utilizando una variedad de métodos y técnicas de ML, desde árboles de decisión hasta redes neuronales, pasando por la gran mayoría de técnicas disponibles en ML. Sin embargo, en este libro, solo consideraremos redes neuronales; de aquí lo de «profundo» en el nombre de las técnicas que presentaremos en los futuros libros. Es decir, adoptaremos soluciones que resultan de la utilización simultánea de técnicas de aprendizaje por refuerzo (Reinforcement Learning) y técnicas de aprendizaje profundo (Deep Learning).
Sin embargo, las redes neuronales no son necesariamente la mejor solución para todos los problemas. Por ejemplo, las redes neuronales requieren mucha información y son difíciles de interpretar (y comprender sus decisiones). Aun así, sin duda, en este momento son una de las técnicas disponibles más poderosas, y su rendimiento suele ser muy bueno. Por ello, la mayoría de los algoritmos de aprendizaje por refuerzo que se utilizan usan redes neuronales para entrenar el agente.
1.2 Aprendizaje por refuerzo
En esta sección, vamos a realizar una primera aproximación a los conceptos básicos del aprendizaje por refuerzo.
Aprender interactuando
Aprender interactuando con nuestro entorno es probablemente el primer enfoque que nos viene a la mente cuando pensamos en la naturaleza del aprendizaje por refuerzo. Es la forma en que intuimos que un bebé aprende. Y sabemos que estas interacciones son, sin duda, una fuente esencial de conocimiento sobre nuestro entorno y sobre nosotros mismos a lo largo de la vida, no solo en los primeros años.
Por ejemplo, cuando estamos aprendiendo a conducir un automóvil, somos plenamente conscientes de cómo responde el entorno a lo que hacemos y, a su vez, también buscamos influir en lo que sucede en nuestro entorno a través de nuestras acciones. Aprender de la interacción es un concepto fundamental que subyace en casi todas las teorías de aprendizaje y es la base del aprendizaje por refuerzo.
El enfoque del aprendizaje por refuerzo se centra en el aprendizaje dirigido a objetivos a partir de la interacción mucho más que otros enfoques de aprendizaje dentro del Machine Learning. En concreto, a la entidad que aprende no se le dice qué acciones realizar, sino que debe descubrir por sí misma — mediante «prueba y error» — qué acciones producen la mayor recompensa. Ese es en realidad su objetivo: maximizar la recompensa.
Además, estas acciones pueden afectar no solo a la recompensa inmediata sino también a las recompensas futuras (llamadas también «recompensas retrasadas»), ya que las acciones actuales determinarán situaciones futuras (como ocurre en la vida real). Estas dos características, búsqueda por «prueba y error» y recompensa retrasada (delayed reward en inglés), son dos características distintivas del aprendizaje por refuerzo que cubriremos a lo largo del libro.
Piezas básicas en el aprendizaje por refuerzo
El aprendizaje por refuerzo es un campo que está influenciado por una variedad de campos bien establecidos, que abordan problemas de toma de decisiones en condiciones de incertidumbre. Por ejemplo, el campo Control Theory estudia formas de controlar sistemas dinámicos complejos. Sin embargo, en este caso la dinámica de los sistemas que tratamos de controlar se suele conocer de antemano, a diferencia de lo que ocurre en el aprendizaje por refuerzo. Otro campo puede ser el de Operations Research,que también estudia la toma de decisiones en condiciones de incertidumbre pero que a menudo contempla espacios de acción mucho más amplios que los que se ven comúnmente en el aprendizaje por refuerzo.
Como resultado, existe una sinergia entre estos campos de investigación, lo que sin duda es positivo para el avance de la ciencia, pero también trae algunas inconsistencias en terminologías, notaciones, etc. Por eso, en este apartado, proporcionaremos una introducción a la terminología que usaremos a lo largo del libro sobre el aprendizaje por refuerzo, que es esencialmente una formalización de un problema de toma de decisiones.
Agente y entorno
En el aprendizaje por refuerzo hay dos componentes básicos: el agente y el entorno.
Un agente (agent) representa la «solución». Es un programa cuyo único rol es el de tomar decisiones (realizar acciones), para resolver problemas de toma de decisiones bajo incertidumbre.
Un entorno (environment) es la representación de un «problema», que es todo lo que viene después de la decisión del agente. El entorno responde con las consecuencias de esas acciones, que son observaciones o estados, y recompensa (también a veces en forma de costes o castigos).
Por ejemplo, en el juego de tres en línea, podemos considerar que el agente es uno de los jugadores y el entorno incluye el juego de mesa y al otro jugador.
Estos dos componentes centrales interactúan continuamente, de manera que el agente intenta influir en el entorno a través de acciones y, a su vez, el entorno reacciona a las acciones del agente. La forma en que el entorno reacciona a acciones específicas del agente se define mediante un modelo que puede ser o no ser conocido por el agente, y esto diferencia dos situaciones:
- Cuando el agente conoce el modelo subyacente del entorno, nos referimos a esta situación como un aprendizaje por refuerzo basado en modelo, omodel-based en inglés. En este caso, el agente dispone de una descripción completa del entorno y, como veremos en el capítulo 4, podremos encontrar la solución óptima mediante programación dinámica (dynamic programming).
- Cuando el agente no conoce el modelo del entorno, este debe tomar decisiones con información incompleta. El agente puede intentar aprender el modelo explícitamente como parte del algoritmo. En este caso lo llamamos aprendizaje por refuerzo sin modelo, o model-free en inglés. Veremos, en los capítulos 5 y 6, los algoritmos básicos que permiten el aprendizaje de los agentes en esta situación en que no conocen la dinámica del entorno.
Estado
El entorno está representado por un conjunto de variables relacionadas con el problema (que dependerán del tipo de problema que queramos resolver). Este conjunto de variables y todos los valores posibles que pueden realizar se denomina espacio de estados (state space). Un estado(state) es una instanciación del espacio de estados, un conjunto de valores que toman las variables.
Debido a que a menudo consideramos que el agente no tiene acceso al estado completo del entorno, de manera estricta se le llama observación (observation) a la parte del estado que el agente puede observar. Sin embargo, a menudo veremos en la literatura — y también en este libro — que se usa el término «estado» en lugar del término «observación» por simplicidad, a pesar de que no se pueda observar toda la información del estado del entorno en un escenario model-free.
Acción y función de transición
En cada estado, el entorno pone a disposición un conjunto de acciones (actions space), de las cuales el agente elegirá una acción(action). El agente influye en el entorno a través de estas acciones, y el entorno puede cambiar de estado como respuesta a la acción del agente. La función responsable de este mapeo se denomina en la literatura función de transición (transition function) o probabilidades de transición (transition probabilities) entre estados. En general, consideramos un escenario model-free cuando el agente no tiene acceso a esta función de transición y debe estimarla por su cuenta.
Recompensa
El entorno normalmente tiene una tarea bien definida y puede proporcionar al agente una señal de recompensa (reward) como respuesta directa a las acciones del agente. Esta recompensa es una retroalimentación sobre cómo la última acción realizada por el agente contribuye al logro de la tarea que debe realizar el agente. La función responsable de este mapeo se llama función de recompensa (reward function). Como veremos más adelante, el objetivo del agente es maximizar la recompensa que recibe, por lo que las recompensas son la motivación que el agente necesita para actuar con el comportamiento deseado.
Definir la función de recompensa es una de las partes más complejas en la modelización de un problema, porque a menudo solo al final de todo (final de una partida de ajedrez) podemos saber si una acción determinada realizada por el agente era buena o no. Es decir, se trata de la situación que ya hemos avanzado en el apartado anterior, donde nos encontramos con recompensas retrasadas. Trataremos con mucho más detalle este tema en el próximo capítulo.
El ciclo de aprendizaje por refuerzo
En la Figura 1.2 resumimos los conceptos introducidos hasta ahora en lo que llamamos ciclo de aprendizaje por refuerzo o bucle de aprendizaje por refuerzo.
Las interacciones entre el agente y el entorno se prolongan durante varios ciclos. A cada ciclo lo llamaremos time step, y marca una interacción entre el agente y el entorno en el tiempo. También se usa iteración como sinónimo de time step cuando estamos programando, puesto que los time step son los índices de los bucles. En cada time step, el agente observa el entorno, realiza una acción y recibe un nuevo estado y recompensa.
El ciclo comienza con el agente observando el entorno (paso 1 en la Figura 1.2) a partir del estado y la recompensa de su anterior acción. El agente usa este estado y esta recompensa para decidir la siguiente acción a realizar (paso 2 de la Figura 1.2). Luego, el agente realiza una acción sobre el entorno en un intento de controlarlo de manera favorable para él (paso 3 de la Figura 1.2). Finalmente, el entorno reacciona a la acción y su estado interno cambia como consecuencia de la acción del agente (paso 4 de la Figura 1.2). Entonces, el ciclo se repite.
El conjunto del estado, la acción, la recompensa y el nuevo estado en cada time step se llama experiencia y, como veremos, estos procesos forman una tupla que será usada para el aprendizaje del agente.
Episodio
La tarea que el agente está tratando de resolver puede tener o no tener un final natural. Las tareas que tienen un final natural, como una partida de ajedrez, se denominan tareas episódicas (episodic tasks). Por el contrario, las tareas que no lo tienen se denominan tareas continuas (continuous tasks); por ejemplo, aprender el movimiento hacia adelante de un robot. La secuencia de time steps desde el principio hasta el final de una tarea episódica se llama episodio (episode). Veremos, en el siguiente capítulo, cómo podemos tratar las tareas continuas, considerando una parte de su «episodio infinito», que llamaremos trayectoria.
Retorno
En general, los agentes requieren varios episodios de tiempo para aprender a resolver una tarea. La suma de las recompensas recolectadas en un solo episodio se llama retorno (return). Y esta medida es la que guía en el aprendizaje a los agentes que, como ya hemos avanzado, en general están diseñados para maximizar este retorno.
Una de las limitaciones es que, a veces, estas recompensas no se revelan al agente hasta el final de un episodio, como ya hemos mencionado antes; en este caso, las llamamos recompensa retrasada (delayed reward). Por ejemplo, en el juego de tres en línea, las recompensas por cada movimiento (acción) no se conocen hasta el final. Sería una recompensa positiva si el agente ganara el juego (porque el agente habría logrado el resultado deseado) o una recompensa negativa (penalización) si el agente perdiera el juego.
Exploración versus explotación
Al tratar de obtener muchas recompensas, un agente puede usar las mejores acciones de las que haya intentado en el pasado y que sabe que serán acciones efectivas para producir recompensas. Pero para descubrir las mejores acciones, paradójicamente, tiene que probar acciones que nunca había seleccionado anteriormente.
En resumen, un agente tiene que explotar lo que ya ha experimentado para obtener la mayor recompensa posible pero, al mismo tiempo, también tiene que explorar para poder descubrir y disponer de una mejor selección de acciones en el futuro. El dilema exploración-explotación (exploration-exploitation dilemma) es un tema crucial y todavía es un tema de investigación actual en el área. En el capítulo 6, introduciremos y veremos cómo programar este dilema ante estas dos posibles situaciones.
1.3 Modelización de un problema
Avancemos en la comprensión del aprendizaje por refuerzo observando un ejemplo simple: «el lago congelado» o Frozen-Lake[6], que presentaremos en esta sección. Frozen-Lake es un conocido entorno de mundo cuadriculado simple (grid-world) que se usa en muchos libros para iniciarse en este tema.
Con este ejemplo de entorno revisaremos la terminología de aprendizaje por refuerzo introducida hasta ahora y veremos cómo se concreta en un caso práctico como en el entorno Frozen-Lake.
Frozen-Lake: un lago congelado donde patinar
El entorno Frozen-Lake simula una pista de patinaje sobre hielo. Esta pista está dividida en 16 celdas (4 × 4) y en algunas de estas celdas se ha roto el hielo, tal como se muestra en la Figura 1.3.
El patinador, nuestro agente, empieza a patinar en la posición superior izquierda y su objetivo es alcanzar la posición inferior derecha evitando caer en los cuatro agujeros que hay en la pista.
En este entorno, si el agente se cae en uno de estos agujeros, el episodiotermina y la recompensa (reward) obtenida es «0». Si el agente llega a la celda de destino, recibe una recompensa de «+1» y el episodio termina. Como hemos avanzado, la cuadrícula es de 4 × 4, lo que significa un espacio de estados compuesto por 16 estados (numerados del 0 al 15).
El entorno Frozen-Lake forma parte de una librería Python llamada Gym[7], que incluye un conjunto de entornos simulados puestos a disposición de la comunidad de programadores por parte de OpenAI, una organización de investigación en inteligencia artificial. Gym ofrece una gran variedad de entornos para entrenar a un agente, que van desde tareas de control clásicas hasta entornos que reproducen los famosos juegos Atari de los años 80. En siguientes capítulos del libro usaremos otros entornos que ofrece esta librería.
Para alcanzar la celda destino, el agente tiene un espacio de accionescompuesto por movimientos en cuatro direcciones: izquierda, abajo, derecha y arriba (left, down, right, up). También sabemos que hay una valla alrededor de la pista de patinaje (totalmente transparente, para no afectar visualmente al paraje natural donde se encuentra el lago congelado, como se muestra en la Figura 1.3). Por tanto, si el agente intenta salir de la cuadrícula, simplemente rebotará en la valla transparente y volverá a quedarse en la celda desde la que intentó moverse.
Para poder experimentar con este mismo entorno en varios capítulos, usaremos varias versiones de Frozen-Lake que ofrece la librería Gym. En la primera versión, el patinador consigue ir en la dirección que se ha propuesto sin ningún problema. En la segunda, se añade incertidumbre en la ejecución de la acción que se ha propuesto realizar el patinador. Veamos un poco más en detalle esta segunda versión, que se llama «slippery» (resbaladiza), para diferenciarla de la primera.
Debido a que el lago está congelado y es muy resbaladizo, las acciones del agente no siempre resultan como se esperaba. En concreto, si el patinador quiere ir hacia una dirección, hay 1/3 de probabilidad de que se deslice hacia la derecha y 1/3 de que se deslice hacia la izquierda, desviándose así de su trayectoria deseada. Es decir, si por ejemplo el agente realiza la acción de ir hacia la derecha, hay solo un 33% de probabilidad de que se mueva a la derecha, un 33% de probabilidad de que termine en la celda de arriba y un 33% de probabilidad de que termine en la celda de abajo.
Esta peculiaridad de comportamiento de este entorno, a pesar de ser muy simple, y quizás un poco exagerada — por el hecho de que suceda un tercio de veces en cada caso — , nos ayuda a aprender cómo los algoritmos de aprendizaje por refuerzo consiguen lidiar con la incertidumbre en el resultado de nuestras acciones — incertidumbre inherente en el mundo real y que, por tanto, es muy importante incluir en nuestros modelos matemáticos para poder, luego, implementar los algoritmos de aprendizaje — .
Este comportamiento del entorno se refleja en la función de transiciónpresentada anteriormente. De momento, no entramos en más detalles sobre esta función, que trataremos en el siguiente capítulo. A modo de resumen, en la Figura 1.4 representamos de forma visual toda la información tratada hasta ahora para nuestro ejemplo de entorno Frozen-Lake.
Programación del entorno
Veamos cómo se puede crear este entorno usando la librería Gym. En las siguientes explicaciones asumiremos que estamos usando el entorno de ejecución Colab ofrecido por Google, que ya hemos introducido anteriormente, para ejecutar el código descrito en esta sección. Si está usando una instalación local de Jupyter Notebook en su ordenador, las explicaciones son equivalentes.
Quizás la única diferencia radica en que en Colab el paquete Gym ya se encuentra instalado, es decir, no hace falta ejecutar el comando pip install. Si prefiere utilizar su entorno de programación Python local a su ordenador, puede instalar Gym siguiendo los pasos que se proporcionan en la GitHub de OpenAI Gym[8].
El primer paso es importar la librería:
import gym
Luego, se debe especificar el entorno que deseamos usar de los que ofrece Gym. Como hemos avanzado, usaremos el entorno Frozen-Lake. Para empezar, crearemos un entorno con el método make() en su versión no resbaladiza, indicándolo como argumento:
env = gym.make(‘FrozenLake-v0’, is_slippery=False)
El entorno del juego se restablece al estado inicial usando el método reset() del entorno:
env.reset()
Para ver una vista del estado del juego, podemos usar el método render()del entorno:
env.render()
La superficie renderizada que produce este método es una cuadrícula de caracteres 4 × 4 como la siguiente:
En esta cuadrícula, el carácter resaltado indica la posición del agente en el time step actual y las letras nos indican el significado de cada celda del tablero:
- «S» indica la celda de inicio (S de start).
- «F» indica una celda de superficie congelada (F de frozen).
- «H» indica una celda donde hay un agujero en el hielo (H de hole).
- «G» indica la celda objetivo (G de goal).
En la documentación oficial[9] de la librería Gym se pueden encontrar todos los detalles sobre los diferentes entornos que ofrece esta librería y toda la información sobre cómo configurarlos.
Sin duda la librería Gym es una librería muy importante dentro del área de aprendizaje por refuerzo y, por ello, muchos libros actuales sobre aprendizaje por refuerzo incluyen un capítulo dedicado a Gym. En este libro hemos considerado que no hacía falta porque, en cierto modo, podría desdibujar el relato que guía al lector en el aprendizaje a través de este libro. Recomendamos una visita a la documentación de Gym antes de avanzar en la lectura de este libro para hacerse una idea de todas las posibilidades que ofrece esta librería.
Programación del agente
Por el momento, crearemos el agente más sencillo que se nos ocurra. Un agente «torpe», por llamarlo de alguna manera, que lo único que sabe hacer es realizar acciones, que decide sin ningún criterio. Para este propósito, podemos usar el método action_space.sample() del entorno, que nos devuelve una acción aleatoria dentro del espacio de acciones posibles.
Mirando la Figura 1.3 podemos ver que, como mínimo, requerimos de 6 acciones bien elegidas para que el patinador pueda llegar a la celda destino. En la Figura 1.5 mostramos una posible secuencia de acciones que puede realizar el patinador para llegar a la celda destino (aunque hay más opciones).
Por tanto, decidimos programar este primer agente de manera que le permitamos realizar todas las acciones que quiera para moverse por la pista de hielo. Al final, mostramos por pantalla cómo le ha ido, si ha llegado a la celda destino o no. El siguiente código puede ser nuestro primer agente «torpe»:
import gym env = gym.make(“FrozenLake-v0”, is_slippery=False) env.reset() env.render() is_done = False t = 0 while not is_done: action = env.action_space.sample() state, reward, is_done, _ = env.step(action) env.render() t += 1 print(“\nlast state =”, state) print(“reward = “, reward) print(“time steps =”, t)
El código empieza importando la librería gym y crea el entorno Frozen-Lake no resbaladizo, es decir, que no hay aleatoriedad o incertidumbre en la acción realizada (en el siguiente capítulo veremos las implicaciones de la opción resbaladiza). Antes de empezar a patinar, nos aseguramos de que el entorno está inicializado correctamente usando el método reset().
A continuación, creamos un bucle que en cada iteración — que representa un time step de la interacción del agente con el entorno — decide una acción con el método sample() y la realiza con el método step().
La acción se le pasa al método como argumento, y este método step() devuelve una tupla con cuatro elementos:
state, reward, is_done, _ = env.step(action)
Analicemos un poco más cada uno de los elementos que componen esta tupla que nos devuelve el método, y cuyo significado es el mismo para todos los entornos simulados de la librería Gym:
- El primero es el estado (u observación) en el que nos encontramos después de realizar la acción especificada en el argumento del método.
- El segundo es la recompensa que se ha conseguido al haber realizado esta acción.
- El tercero es un valor booleano que nos indica si el entorno ya ha finalizado. En nuestro caso, puede ser o bien por haber caído en un agujero — y, por tanto, haber fracasado en el objetivo — o bien por haber llegado a la celda objetivo. El motivo por el que ha finalizado el episodio lo debemos deducir nosotros a partir del estado que nos indica el primer elemento.
- El cuarto argumento nos devuelve información adicional del entorno en cada time step, que puede ser diferente en diferentes entornos. En nuestro caso de Frozen-Lake, lo descartamos.
Si ejecutamos este código, generará una salida por pantalla como la que se muestra en la Figura 1.6, donde podemos observar en cada time step la acción y el estado del entorno, puesto que hemos usado el método render()del entorno en el interior del bucle.
En este caso concreto de ejecución, vemos que nuestro agente acabó en un agujero, en concreto en la celda 5, después de realizar 4 acciones. Puede probar varias ejecuciones de este mismo código; podrá comprobar que es casi imposible encontrar un episodio de nuestro agente «torpe» en el que, con acciones seleccionadas al azar, pueda superar los obstáculos y llegar a la celda de destino 15 sin antes caer en un agujero.
Entonces, ¿cómo podríamos construir un agente para conseguir el objetivo? Esto es precisamente de lo que trata este libro, y en próximos capítulos veremos cómo son los métodos fundamentales en aprendizaje por refuerzo en los que se basan los métodos actuales para programar agentes que puedan alcanzar la celda destino.

La clase Agent
Aprovechemos este ejemplo simple para ver cómo codificaremos los agentes en este libro para tener un código más «limpio» que ayude a las explicaciones. El mismo código anterior se puede expresar de la siguiente manera, donde explícitamente creamos una instancia de la clase Agent() que implementa el método de select_action() para decidir qué acción va a realizar el agente:
Es decir, nuestro agente «torpe», que decide las acciones a realizar aleatoriamente — de la misma manera que en el anterior ejemplo — , ahora estará implementado como una clase:
De momento, nuestra clase agente solo ofrece el método select_action(), que retorna una acción aleatoria usando el método action_space.sample(), que ofrece el entorno. En este código hemos creado un entorno interno en el agente con el único propósito de poder llamar a este método action_space.sample().
En el GitHub del libro hemos incluido el código que ejecuta varias veces un agente «torpe», creando una función test que envuelve el bucle anterior, para ver si en algún caso aleatoriamente nuestro agente «torpe» es capaz de llegar a la celda destino:
Puede ver que es un código muy simple, que simplemente genera 1000 episodios y muestra por pantalla qué porcentaje ha finalizado en el estado 15, es decir, en la celda destino.
En la ejecución que hemos realizado vemos que solo consigue finalizar en la casilla objetivo alrededor del 2% de las ocasiones. Le proponemos que pruebe varias ejecuciones; verá que, dada la aleatoriedad en la elección de la acción, siempre será un porcentaje muy bajo.
1.4 En qué se diferencia el aprendizaje
En este primer capítulo hemos introducido la idea básica de aprendizaje por refuerzo. Hemos visto que se trata de un proceso de aprendizaje de prueba y error basado en recompensas. Ahora que sabemos un poco más sobre él, y antes de entrar en más profundidad en el tema, es un buen momento para contrastar este tipo de aprendizaje con los otros tipos dentro del Machine Learning, para ayudarnos a entender mejor su forma de aprender.
Aprendizaje por refuerzo versus aprendizaje supervisado
Como ya hemos avanzado, en el aprendizaje supervisado el sistema aprende de los datos de entrenamiento que son datos etiquetados; parejas de datos de entrada y salida. En este caso, el modelo (agente) se entrena usando los datos de entrenamiento de tal manera que el modelo puede generalizar su aprendizaje a nuevos datos, no vistos anteriormente.
Veamos la diferencia entre el aprendizaje supervisado y el aprendizaje por refuerzo con un ejemplo. Imaginemos que queremos entrenar a un agente para jugar a un juego en línea usando el aprendizaje supervisado. En este caso, entrenaríamos el modelo del agente con algún algoritmo de optimización usando un conjunto de datos de entrenamiento que incluyera todos los movimientos que un jugador puede hacer en cada estado, junto con etiquetas que indicarán si es un buen movimiento o no.
En el caso del aprendizaje por refuerzo, nuestro agente no recibirá ningún tipo de datos de entrenamiento. En cambio, se le permitirá interactuar con un entorno que simula el juego y que le proporcionará una recompensa al agente por cada acción que realice en ese entorno. En este caso el agente aprenderá interactuando con el entorno, y mediante prueba y error irá aprendiendo — gracias a la recompensa que se le va dando en cada interacción — qué acciones debe elegir para maximizar la recompensa total que puede recibir.
Aprendizaje por refuerzo versus aprendizaje no supervisado
Al igual que en el aprendizaje supervisado, en el aprendizaje no supervisado entrenamos el modelo del agente en función de los datos de entrenamiento. Pero en el caso del aprendizaje no supervisado, los datos de entrenamiento no contienen etiquetas, lo cual puede conllevar, cuando uno se inicia en el tema, a la idea errónea de que el aprendizaje por refuerzo es un tipo de aprendizaje no supervisado debido a que no tenemos etiquetas como datos de entrada. Pero no lo es. En el aprendizaje no supervisado el modelo aprende de la estructura oculta en los datos de entrada, mientras que en aprendizaje por refuerzo el modelo aprende de las recompensas que intenta maximizar.
Un ejemplo habitual para explicar el aprendizaje no supervisado es el de un sistema de recomendación de películas que quiere recomendar a alguien una nueva película. Con el aprendizaje no supervisado, sirviéndose por ejemplo de algoritmos de clustering, el modelo del agente encontrará películas similares a las que la persona interesada (u otras personas con un perfil similar al suyo) ha visto antes y recomendará estas nuevas películas.
Pero esta aproximación es poco flexible, y a veces no permite usar fácilmente el feedback del usuario mientras está viendo la película. En cambio, con el aprendizaje por refuerzo el agente puede traducir este feedback más fácilmente en forma de recompensas. Por ejemplo, una recompensa podría ser el tiempo dedicado a ver una película, o el tiempo dedicado a ver el tráiler de la película, o cuántas películas seguidas ha visto, etc.
En este ejemplo concreto, un agente de aprendizaje por refuerzo es más flexible, y puede saber si la preferencia de película cambia mientras la persona en cuestión la está viendo, y sugerir nuevas películas modificando de forma dinámica esa preferencia. Evidentemente, estos diferentes paradigmas de aprendizaje no son excluyentes entre sí, y pueden complementarse y ser usados a la vez para resolver un determinado problema.
¿Dónde están los datos en el aprendizaje por refuerzo?
Con lo que hemos dicho en los dos anteriores puntos, podríamos llegar a pensar que en realidad en el aprendizaje por refuerzo no tenemos «datos», a diferencia de lo que tenemos en el aprendizaje supervisado o no supervisado. Sin embargo, los datos son en realidad el mismo entorno; al interactuar el agente con este entorno se crean datos, que llamaremos «trayectorias», que son secuencias de observaciones y acciones muy útiles para entrenar a los agentes, como veremos en siguientes capítulos.
El aprendizaje por refuerzo en realidad también permite usar datos adicionales o trayectorias que existen de anteriores experiencias de interacciones de otros entornos y agentes. Pero de momento, para el propósito de este libro, podemos decir que en el contexto puro de aprendizaje por refuerzo los únicos datos son el entorno.
REFERENCIAS DEL CAPÍTULO:
[1] Véase https://www.bsc.es/marenostrum/marenostrum [Consultado: 29/01/2020].
[2] Stuart J Russell and Peter Norvig; (2009). A Modern Approach (AIMA), 3rd edition, Prentice Hall. ISBN 0–13–604259–7.
[3] Véase https://en.wikipedia.org/wiki/AI_winter [Consultado: 16/01/2021].
[4] Raschka S., Mirjalili V.; (2019). Python Machine Learning. Aprendizaje automático y aprendizaje profundo con Python, scikit-learn y TensorFlow. Editorial Marcombo.
[5] Torres J.; (2020). Python Deep Learning. Introducción práctica con Keras y TensorFlow 2. Editorial Marcombo.
[6] Véase https://gym.openai.com/envs/FrozenLake-v0/ Consultado: 16/01/2021].
[7] Véase https://gym.openai.com Consultado: [16/01/2021].
[8] Véase https://github.com/openai/gym [Consultado: 16/01/2021].
[9] Véase http://gym.openai.com/docs/ [Consultado: 16/01/2021].