Q-learning: Aprendizaje automático por refuerzo

“Tekno the Robotic Puppy” by Toyloverz – Own work. Licensed under CC BY-SA 3.0 via Wikimedia Commons

Últimamente se ha dado bastante bombo a la investigación realizada por la empresa Deep Mind donde consiguen que un programa aprenda a jugar a juegos clásicos de Atari. El artículo original es del 2013, pero por alguna razón la prensa se ha vuelto loca hablando del tema en 2015. El artículo de Deep Mind combina el reciente interés en deep learning con el clásico algoritmo de aprendizaje por refuerzo q-learning, inventado hace más de 25 años.

También a raíz de ese artículo, he estado aprendiendo sobre q-learning, y ¡es mucho más sencillo de lo que imaginaba! Así que no he podido resistirme a implementarlo y compartir lo que he aprendido.

Aprendizaje por refuerzo

Sirius

Sirius – Foto de Ricardo Rodríguez

¿Cómo aprende un perro trucos nuevos como sentarse o tumbarse? Cada vez que lo hace bien, se le da un premio. Esa chuche simplemente es un refuerzo positivo. A la larga, nuestra mascota aprenderá que hacer el truco bien tiene una recompensa. La idea se puede extender a los algoritmos que aprenden de forma automática. Tenemos que dar a nuestros algoritmos chuches digitales.

Vamos a explorar esta idea con un juego: el 3 en raya. Si tenemos un algoritmo que aprende por refuerzo, podríamos ofrecer un refuerzo positivo cada vez que el algoritmo gana. La idea básica del aprendizaje por refuerzo es probar a realizar movimientos y observar el refuerzo que proporcionan.

No es difícil para un algoritmo recordar qué movimientos concretos ganan la partida. Por ejemplo, supongamos que el tablero tiene dos X en línea y la siguiente casilla en la misma línea está vacía. El algoritmo se enfrentará a esta situación múltiples veces, y si prueba diferentes movimientos cada vez, después de algunas pruebas el algoritmo descubrirá que poner una X en la casilla que forma una línea garantiza un refuerzo positivo. Vemos que el refuerzo no sólo depende de la acción que se realiza, sino también del estado en que se encuentra el tablero antes de realizar esa acción, porque poner la X en esa casilla en otros momentos de la partida no gana la partida.

Refuerzo

Refuerzo positivo al realizar una acción que gana la partida.

Existen otros algoritmos de aprendizaje por refuerzo, pero q-learning es uno de los más populares por su efectividad, y por las posibilidades que ofrece para combinarlo con otras técnicas, como redes de neuronas, deep learning, etc..

Tabla de recompensas

Siguiendo con el juego del 3 en raya, vamos a intentar aprender cual es la mejor jugada para cada estado del tablero. Para eso, definamos una tabla cuyas filas corresponden a estados del tablero, y cuyas columnas corresponden a acciones. Cada celda de esta tabla contendrá la recompensa recibida para una combinación (estado, acción).

Si ahora analizamos muchas partidas de 3 en raya, la tabla contendrá todas las recompensas posibles.

Refuerzo directo

Tabla de recompensas directas al ejecutar una acción (A) en un estado (E). Se muestran sólo algunas filas y columnas, pero la tabla es mucho mayor..

¿De cuántos estados estamos hablando? Cada casilla del tablero puede estar en 3 estados (vacía, X u O), y tenemos 9 casillas, por lo tanto hay 19683 estados (39). Si queremos rompernos más la cabeza, hay muchos estados que son imposibles, pero olvidemos esto por ahora, para simplificar.

¿Y las acciones? En cualquier situación un jugador puede poner su ficha en un máximo de 9 casillas. No todas las acciones son válidas en cada estado, algunas casillas pueden estar ocupadas, hablaremos de esto más tarde, pero en principio pongamos todas en la tabla. El caso es que esta tabla mencionada anteriormente con las recompensas tendría menos de 200.000 celdas, así que se puede almacenar en memoria sin problema.

Ahora tenemos una tabla con recompensas. En los estados en que es posible recibir una recompensa, es fácil decidir cual es la mejor acción: la que obtiene la mayor recompensa. Si ahora intentamos utilizar esta tabla para jugar una partida, vemos que nos falta mucha información. Sólo conocemos las recompensas recibidas cuando ganamos una partida, pero ¿qué hacemos en todas las jugadas intermedias?

Rellenar la tabla para las jugadas intermedias es precisamente el objetivo del algoritmo q-learning. En una jugada intermedia, ¿qué hace que una acción sea mejor que las demás? Si pensamos en este juego concreto, seguro que tenéis muchas ideas específicas, pero q-learning utiliza un concepto genérico y fácil de calcular: la recompensa a largo plazo. La idea es construir una tabla que en lugar de recompensas directas, contenga una mezcla de la recompensa directa (a corto plazo) y las recompensas a largo plazo.

Un truco para quienes quieran probar estas ideas con 3 en raya. Si sólo ofrecemos recompensas al ganar, el algoritmo no sabrá distinguir entre perder y empatar. Por eso, es una buena idea ofrecer una recompensa (algo menor) también al empatar.

En juegos más complejos en los que se puedan recibir recompensas no sólo al final de la partida, sino también durante la partida (por ejemplo, en ajedrez se pueden comer fichas al rival), es importante combinar ambos tipos de recompensa, a corto y largo plazo. Por cierto, si alguien está pensando en aplicar esta técnica al ajedrez, cuidado con el número de estados, aproximadamente un 2 seguido de 40 ceros. Como anécdota, ni todos los discos duros del mundo juntos tienen tanta capacidad de almacenamiento.

Recompensa a largo plazo y mixta (discounted reward)

La recompensa a largo plazo es la recompensa que esperamos acumular a la larga si en cada estado realizamos la mejor acción posible. Desde el punto de vista de nuestra mascota, la recompensa a largo plazo es el número de galletas que acabará recibiendo si se tumba cuando oye nuestra orden. La recompensa mixta (en inglés se suele llamar discounted reward) es una combinación de la recompensa a largo plazo con la recompensa directa, y se calcula de forma voraz (greedy). Veamos un ejemplo de lo que sucede en el algoritmo, empezando por el final de la partida y volviendo a la jugada anterior. Ya hemos visto que cuando ganamos una partida, empezando desde un cierto estado del tablero, realizamos una acción, y ésta produce un refuerzo positivo:

Movimiento ganador

Recompensa directa para un movimiento ganador.

Además, para ese estado, coincide que es la única acción que produce un refuerzo positivo, por tanto, es la mejor acción. Ahora, demos un paso atrás, y fijémonos en un estado anterior. Desde el punto de vista del jugador que pone las X, este podría ser un estado anterior:

Refuerzo directo en un estado intermedio

Recompensa directa en un estado intermedio.

En este estado intermedio, realizar la acción indicada en rojo no tiene ninguna recompensa directa, pero ya hemos visto antes que a largo plazo vamos a recibir una recompensa.

Ahora que tenemos dos estados consecutivos, podemos introducir el concepto de experiencia. Una experiencia incluye un estado, la acción realizada, la recompensa recibida, y como novedad, el estado siguiente tras realizar esta acción.

Ojo, porque en un juego por turnos este concepto del estado siguiente es un poco confuso. En principio podríamos pensar que partiendo de un tablero vacío, si el algoritmo pone una X, el estado siguiente es un tablero con una casilla cubierta. Sin embargo, esto no es así. Q-learning sólo se preocupa por aprender qué hacer cuando es su turno. Tras cubrir el tablero con una X, es el turno del rival. Cuando el rival haya colocado una O, volverá a ser el turno del algoritmo. Este es el estado del tablero que debemos usar como estado siguiente en las experiencias.

Continuando con el ejemplo anterior, una experiencia partiendo del estado intermedio (estado, acción, recompensa, estado siguiente) podría ser:

Experiencia

Experiencia (estado, acción, recompensa, estado siguiente)

Es decir, partiendo del estado de la izquierda, realizando la acción en rojo, no recibimos recompensa, y tras jugar nuestro rival, nos encontramos con el estado que figura a la derecha (vuelve a ser nuestro turno). Es cierto que en este caso el rival está realizando una mala jugada, pero sirve para ejemplificar de manera sencilla el algoritmo.

Con esa información, y la tabla que ya tiene algunas recompensas directas, q-learning ya puede trabajar para rellenar más celdas de nuestra tabla. Como se menciona al principio de esta sección, ya sabemos cual es la mejor jugada cuando nos encontramos con el estado de la derecha, y sabemos qué recompensa produce. Utilizaremos esa recompensa directa en el estado de la derecha para aprender algo sobre la recompensa a largo plazo asociada al estado de la izquierda y la acción en rojo.

Para un estado y una acción es posible tener múltiples experiencias. En el 3 en raya, las experiencias que nos encontraremos dependen de lo que decida hacer el rival. Por eso, hay que usar las experiencias con cautela y aprender sólo un poco de cada una.

Algoritmo

Todo lo que necesitamos almacenar en memoria durante el aprendizaje es una tabla como la mencionada anteriormente con las recompensas para estados y acciones. Esta tabla va a contener la recompensa mixta para cada celda. Siendo sinceros, en realidad tiene nuestra mejor estimación de esta recompensa, que al principio será un desastre, y a medida que aprendemos de distintas experiencias, se va volviendo más y más precisa.

El algoritmo necesita dos parámetros que debemos ajustar en función del problema que estemos resolviendo:

  • Velocidad de aprendizaje (learning rate). Es un valor entre 0 y 1 que indica cuánto podemos aprender de cada experiencia. 0 significa que no aprendemos nada de una nueva experiencia, y 1 significa que olvidamos todo lo que sabíamos hasta ahora y nos fiamos completamente de la nueva experiencia.
  • Factor de descuento (discount factor). Es también un valor entre 0 y 1 que indica cuán importante es el largo plazo. 0 significa que sólo nos importan los refuerzos inmediatos, y 1 significa que los refuerzos inmediatos no importan, sólo importa el largo plazo. Ojo, porque valores muy cercanos a 1 tienden a divergir. Este factor nos ayuda a mezclar recompensas directas con recompensas a largo plazo y producir la recompensa mixta.

En ambos parámetros los extremos son poco útiles. La velocidad de aprendizaje se puede ajustar en función de la incertidumbre respecto a los estados siguientes en las experiencias. Por ejemplo, en el 3 en raya la incertidumbre viene de las posibles jugadas del rival, que puede realizar hasta 9 acciones diferentes. Por tanto, una velocidad de aprendizaje superior a 1/9 da un peso excesivo a las nuevas experiencias y olvida demasiado rápido las anteriores.

El factor de descuento establece un balance entre el refuerzo inmediato y el refuerzo a largo plazo. En el caso del 3 en raya, sólo recibimos refuerzos a corto plazo cuando se acaba la partida, así que este factor no importa mucho, cualquier valor entre 0.1 y 0.9 funcionará muy bien. En otros problemas donde se puedan recibir refuerzos intermedios, debemos decidir dónde poner la balanza.

El código para actualizar la recompensa mixta en una celda de la tabla cuando tenemos una experiencia (estado, acción, refuerzo, siguienteEstado) es:

siguienteRefuerzoMixto = maxRefuerzo(tabla, siguienteEstado)
tabla[estado, accion] += velocidadAprendizaje * (
    refuerzo + factorDescuento * siguienteRefuerzoMixto
    - tabla[estado, accion]);

Donde mayorRefuerzo(tabla, siguienteEstado) es el máximo refuerzo mixto que se puede conseguir entre todas las acciones desde el siguiente estado (el máximo valor entre todas las celdas de esa fila). Esto asume que en cada estado siempre queremos realizar la acción que produce la mayor recompensa mixta.

El algoritmo completo para aprender a partir de una lista de experiencias sería algo así:

tabla = zeros(#estados, #acciones)
for paso in 1..MAX_PASOS:
  for experiencia in experiencias:
    estado, accion, refuerzo, siguienteEstado = experiencia
    siguienteRefuerzoMixto = maxRefuerzo(tabla, siguienteEstado)
    tabla[estado, accion] += velocidadAprendizaje * (
      refuerzo + factorDescuento * siguienteRefuerzoMixto
      - tabla[estado, accion]);

Donde MAX_PASOS es el número de veces que usaremos todas las experiencias para refinar la tabla. Otra opción es vigilar cuánto estamos cambiando la tabla en cada paso y continuar hasta que estos cambios sean muy pequeños.

Una vez que terminamos el aprendizaje, es muy fácil utilizar esta tabla para tomar decisiones. Si estamos en un estado E:

mejorRefuerzo = mayorRefuerzo(tabla, E)
for accion in ACCIONES:
  if tabla[E, accion] == mejorRefuerzo:
    return accion

Aprendizaje en tiempo real (online)

Si tenemos un registro de partidas de 3 en raya lo suficientemente grande, podemos generar la tabla de refuerzos mixtos extrayendo una lista de experiencias de este registro y usándolas para actualizar la tabla una y otra vez hasta que las celdas se estabilicen y prácticamente no aprendan nada nuevo.

Sin embargo, ¿qué hacemos si no tenemos este registro? ¿No es posible aprender como los humanos, jugando? Pues efectivamente es posible, aunque hay que introducir la idea de la exploración.

El problema de aprender jugando es que, como se mencionaba anteriormente, al principio la tabla tiene estimaciones pésimas del refuerzo mixto, y si seguimos a ciegas la tabla para decidir nuestros movimientos, es posible que nunca descubramos las mejores jugadas, porque ya tenemos jugadas mediocres que continuamos ejecutando una y otra vez porque no conocemos nada mejor.

Seguro que habéis oído muchas veces que arriesgarse a cometer errores es la mejor forma de aprender. Pues en el aprendizaje en tiempo real es fundamental. Si queremos que nuestra tabla esté llena de valores útiles, necesitamos arriesgarnos a perder algunas partidas y explorar opciones nuevas.

La gran pregunta es cómo encontrar un equilibrio razonable entre explorar y hacer caso de la tabla. Existen múltiples opciones, pero una bastante común consiste en usar los refuerzos que podemos encontrar en la tabla para las diferentes acciones como una distribución de probabilidad. De esa forma, las acciones que produzcan un mayor refuerzo serán elegidas más a menudo que las acciones que produzcan un menor refuerzo, pero todas las acciones tendrán su oportunidad en algún momento.

Para ilustrar la técnica de la distribución de probabilidad, supongamos un sistema con 5 acciones. Vamos a dibujar una caja para cada acción con tamaños proporcionales a los refuerzos de dichas acciones, y las colocamos juntas en fila:

Eligiendo acciones al azar, con probabilidad proporcional al refuerzo de cada acción.

Como se ve en la regla del dibujo, la longitud total de la fila de cajas es 0.72. Si elegimos un número al azar en el rango de la regla (de 0 a 0.72), estará situado junto a cajas grandes más a menudo que junto a cajas pequeñas. Lo importante es que la probabilidad de que ese número elegido al azar esté junto a una caja específica es proporcional a la longitud de esa caja, que es justo lo que nos interesa.

El algoritmo de exploración si tenemos una lista de refuerzos correspondiente a cada acción sería:

refuerzoTotal = sum(refuerzos)
distancia = random(0, refuerzoTotal)
for accion in ACCIONES:
  if distancia <= refuerzos[accion]:
    return accion
  else:
    distancia -= refuerzos[accion]

Otra pregunta es hasta cuándo seguir usando exploración. Esto depende mucho del problema. En el caso del 3 en raya, llegaremos a un punto en que la tabla se estabiliza mucho y no se aprende nada nuevo, y en ese caso podemos dejar de explorar y seguir la mejor acción siempre. En casos en que el algoritmo se tenga que enfrentar a entornos dinámicos donde la mejor acción pueda cambiar con el tiempo, puede ser interesante mantener siempre la exploración activa.

Y ahora, un truco. Si no queréis pasar innumerables horas jugando contra vuestro ordenador al 3 en raya para que aprenda, ¡ponedlo a jugar contra si mismo! En menos de un minuto se puede jugar un millón de partidas, más que suficiente para que aprenda a jugar como un maestro a este juego tan simple.

Acciones inválidas

En el juego del 3 en raya, no todas las acciones son posibles en cada estado. En concreto, no podemos poner una ficha encima de otra. Esto no es un problema para q-learning. Si no se eligen estas acciones, nunca habrá experiencias con ellas. Entonces, nunca vamos a intentar actualizar la tabla para acciones inválidas y se quedarán en 0.

Sin embargo, estas celdas de la tabla sí son un problema para la exploración. Debemos tener cuidado de que el algoritmo de exploración no intente elegir acciones imposibles.

Q-learning en sistemas continuos

Hay una propiedad interesante del ejemplo del 3 en raya que hace que resulte muy fácil utilizar q-learning: hay un número discreto de estados, y un número discreto de acciones. Además, son números relativamente pequeños y manejables, ¡no como el ajedrez!

Un ejemplo donde el estado es continuo es un robot aspirador. Su estado es la información recibida por una serie de sensores de distancia, suciedad, etc. Estos sensores producen información prácticamente continua (la distancia puede tomar en teoría infinitos valores diferentes). En otros casos, como el ajedrez, los estados son discretos, pero su número es tan grande, que es inviable usar una tabla.

Un ejemplo donde la acción es continua es el control de un automóvil. Las acciones incluyen el ángulo de giro del volante y la presión de los pedales, que son valores continuos también.

No quiero entrar muy en detalle acerca de los sistemas continuos porque no es el objetivo de este artículo, pero os dejo algunas ideas y enlaces por si tenéis curiosidad y queréis profundizar un poco más.

Para sistemas con estados continuos, la idea es sustituir las columnas de la tabla de refuerzos mixtos por algún mecanismo que aproxime funciones, como por ejemplo una red de neuronas. Típicamente se utiliza una red de neuronas separada para cada acción, cuya entrada es el estado, y cuya salida es una única neurona con el refuerzo mixto de la acción correspondiente.

Es decir, para encontrar el refuerzo de un estado y una acción, en lugar de indexar una tabla, usamos una codificación del estado en forma de lista de valores, se lo damos a una red de neuronas, y la red produce una salida que es precisamente el refuerzo de ese estado para una de las acciones. Repetimos esto para las redes correspondientes a las demás acciones, y ya tenemos una lista de refuerzos para elegir la mejor acción.

Para aprender, en lugar de actualizar la tabla, entrenamos las redes. En algunos casos, sobre todo cuando se utiliza deep learning con redes profundas, puede ser interesante combinar todas las acciones en una misma red con una salida para cada acción. Normalmente las primeras capas de estas redes profundas no varían entre acciones, y el entrenamiento es mucho más rápido así. El artículo (en inglés) de Deep Mind es un buen ejemplo.

Para sistemas con acciones continuas, la cosa se complica un poco. Ya no nos sirve una red de neuronas para cada acción, porque hay infinitas acciones. Tampoco nos sirve una red de neuronas con varias salidas, porque necesitaría infinitas salidas. Una posibilidad es combinar el estado y la acción como entradas a una red, e interpretar la salida como el refuerzo de esa acción en ese estado. El problema es cómo elegir la mejor acción para un estado, habría que realizar un muestreo, probando con múltiples acciones para buscar la mejor, un proceso muy lento.

En este caso es necesario cambiar un poco el algoritmo para poder decidir la mejor acción de forma eficiente. Normalmente se utilizan sistemas llamados Actor-Crítico (actor-critic). El crítico suele ser una red de neuronas que estima el mayor refuerzo que se puede conseguir en un determinado estado. Es decir, como entrada tiene un estado, y como salida un refuerzo (en teoría, el refuerzo de realizar la mejor acción en ese estado). El actor es otra red de neuronas que estima la mejor acción para un determinado estado. Su entrada es también el estado, y la salida es una acción (la mejor).

El crítico suele entrenarse con todas las experiencias, mientras que el actor suele entrenarse sólo cuando una experiencia ofrece un refuerzo mixto mejor que el conocido por el crítico hasta ahora. Este artículo (en inglés) explica esta y otras técnicas.

Fácil, ¡para toda la familia!

El algoritmo q-learning asusta un poco cuando se lee la teoría detrás de él, con los modelos ocultos de Markov, las diferencias temporales, etc. Pero en su forma básica es muy sencillo de implementar (una tabla y un par de líneas de código) y los resultados son increíbles. En realidad, lleva más tiempo programar todo lo relacionado con el juego del 3 en raya que q-learning.

Os animo a intentarlo, ¡es muy divertido!

Gracias a Silvia Izquierdo, Ana Diaz y Javier Loureiro por revisar este artículo.

Anuncios

Acerca de Rubén L.

Software Engineer
Esta entrada fue publicada en Español, ingeniería y etiquetada , , , , , , , , , . Guarda el enlace permanente.

5 respuestas a Q-learning: Aprendizaje automático por refuerzo

  1. Pingback: ¿Qué es y cómo funciona “Deep Learning”? | Rubén López

  2. Jose Luis dijo:

    Muy bueno, tengo una duda. En algún punto sería necesario tener una matriz que contenga las probabilidades de ir a un nuevo estado a partir de de una acción a para implementar el algoritmo? Por ejemplo, que haya una probabilidad de 0.3 de que con la acción 2, el estado 1 vaya al estado 2.

    • Rubén L. dijo:

      Gracias por el comentario, Jose Luis.

      Para aplicar q-learning no hace falta construir la matriz de probabilidades. La matriz de refuerzos tiene toda la información que necesitas. Lo que te interesa en cada estado es elegir la acción que maximiza el refuerzo a largo plazo.

      Que conste que es una buena pregunta, porque las probabilidades acabarán afectando a cómo se genera la matriz de refuerzos. Por ejemplo, si en el estado 1 con la acción A es más probable ir al estado 2 que al estado 3, entonces el refuerzo a largo plazo de la celda (estado 1, acción A) estará más influenciado por el mejor refuerzo a largo plazo del estado 2 que el del estado 3. Pero esto pasa simplemente porque uno aparece más veces que el otro cuando entrenas con muchos datos.

      Lo bueno es que el algoritmo hace todo esto por ti, no necesitas que el programa tenga en cuenta las probabilidades de forma explícita.

  3. Alex dijo:

    Hola, yo tengo un problema bastante similar a este pero a la vez un tanto más complejo, en la universidad nos plantean hacer un agente automático del pac-man, este agente aparece en un tablero de dos dimensiones y tiene que perseguir a unos fantasmas (4 fantasmas). Mi problema de partida es que me piden que decida la información que define un estado del juego, esto es porque los tableros no son tan pequeños como el de tres en raya creo yo. y las acciones son moverse arriba abajo izq o derecha, aparte los fantasmas se mueven de forma aleatoria(esto sería como en el caso de las tres en raya, la persona que pone los círculos). Me podrías aclarar cómo debería definir estos estados, ya que tiene que ser un espacio de estados finito. Por último destacar que tenemos acceso a información, como dist a los fantasmas, movimientos posibles ya que si te sales del tablero ese movimiento no es posible y algún dato más. Un saludo y gracias d antemano.

    • Rubén L. dijo:

      Deberías intentar resolver los problemas que te plantean en la universidad por ti mismo, es la mejor forma de aprender. Te puedo dar algunas pistas.
      El tablero es efectivamente más grande que el tres en raya:
      http://vignette1.wikia.nocookie.net/pacman/images/d/dc/Pac-Man_-_Pac-Man_Collection_(GBA).png/revision/latest?cb=20131204144030
      No he contado todas las posiciones, pero tiene toda la pinta de que hay más de 200. Pongamos que son 200 por simplificar. Piensa que pac-man puede estar en cada una de esas 200, y por cada posición de pacman, cada fantasma puede estar en otras 200 también (no se pueden solapar, pero eso no reduce demasiado el número de estados). Si multiplicas, ya te sale un número que no cabe en memoria (te dejo a ti el ejercicio matemático). Y aún te falta duplicar el número de estados para tener en cuenta si pacman ha comido una bola mágica y se puede comer a los fantasmas, y si quieres codificar en qué dirección se mueve cada fantasma, necesitas multiplicar un poco más.
      Aunque no quepa en memoria, todavía puedes aplicar q-learning si cabe en disco. Simplemente será algo más lento por todos los accesos a disco.
      Otra opción es descartar información y codificar cada estado usando menos datos de los disponibles. Algunas ideas:
      – Cuantificar las posiciones. Es decir, si hay 200 posiciones en el tablero, reducir la resolución a 50 o menos. Varias posiciones reales serían el mismo estado para q-learning.
      – Usar las distancias a los fantasmas en lugar de su posición absoluta. La distancia euclídea es un número real, así que habría que discretizarla.
      – Seguro que tu profesor te ha dado alguna idea más en clase.

      Piensa como un jugador: serías capaz de decidir por dónde moverte si lo único que conoces es a qué distancia están los fantasmas? O necesitas saber dónde están exactamente para poder esquivarlos?

      Otra opción es lo que han hecho los chicos de DeepMind, el estado es un screenshot del juego más un par de screenshots de los instantes de tiempo anteriores para poder descubrir velocidades. El problema es que entonces no puedes aplicar q-learning mediante una tabla, tienes que usar una red de neuronas como han hecho ellos.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s