curso
Introducción al Q-Learning: Tutorial para principiantes
El aprendizaje por refuerzo (RL) es la parte del ecosistema del aprendizaje automático en la que el agente aprende interactuando con el entorno para obtener la estrategia óptima para alcanzar los objetivos. Es muy diferente de los algoritmos de aprendizaje automático supervisado, en los que tenemos que ingerir y procesar esos datos. El aprendizaje por refuerzo no requiere datos. En su lugar, aprende del entorno y del sistema de recompensas para tomar mejores decisiones.
Por ejemplo, en el videojuego Mario, si un personaje realiza una acción aleatoria (por ejemplo, moverse a la izquierda), en función de esa acción puede recibir una recompensa. Tras realizar la acción, el agente (Mario) se encuentra en un nuevo estado, y el proceso se repite hasta que el personaje del juego llega al final de la fase o muere.
Este episodio se repetirá varias veces hasta que Mario aprenda a navegar por el entorno maximizando las recompensas.
Imagen del autor
Podemos dividir el aprendizaje por refuerzo en cinco sencillos pasos:
- El agente se encuentra en el estado cero en un entorno.
- Llevará a cabo una acción basada en una estrategia específica.
- Recibirá una recompensa o un castigo en función de esa acción.
- Aprendiendo de los movimientos anteriores y optimizando la estrategia.
- El proceso se repetirá hasta que se encuentre una estrategia óptima.
Obtenga más información leyendo nuestro tutorial Introducción al aprendizaje por refuerzo. Explorará más a fondo cómo funciona el aprendizaje por refuerzo con ejemplos de código.
En este tutorial, aprenderemos sobre Q-learning y entenderemos por qué necesitamos Deep Q-learning. Además, aprenderemos a crear y entrenar algoritmos de Q-learning desde cero utilizando Numpy y OpenAI Gym.
Nota: Si es nuevo en el aprendizaje automático, le recomendamos que realice nuestro itinerario profesional de Científico de aprendizaje automático con Python para comprender mejor el Aprendizaje por refuerzo y Q-Learning.
¿Qué es Q-Learning?
Q-learning es un algoritmo sin modelo, basado en valores y fuera de política que encontrará la mejor serie de acciones basándose en el estado actual del agente. La "Q" significa calidad. La calidad representa el valor de la acción para maximizar las recompensas futuras.
Los algoritmos basados en modelos utilizan funciones de transición y recompensa para estimar la política óptima y crear el modelo. En cambio, los algoritmos sin modelo aprenden las consecuencias de sus acciones a través de la experiencia sin función de transición y recompensa.
El método basado en el valor entrena la función de valor para aprender qué estado es más valioso y actuar. Por otro lado, los métodos basados en políticas entrenan directamente la política para aprender qué acción tomar en un estado determinado.
En la política desactivada, el algoritmo evalúa y actualiza una política que difiere de la política utilizada para realizar una acción. Por el contrario, el algoritmo on-policy evalúa y mejora la misma política utilizada para realizar una acción.
Terminologías clave en Q-learning
Antes de entrar de lleno en cómo funciona el Q-learning, necesitamos aprender algunas terminologías útiles para entender los fundamentos del Q-learning.
- Estado(s): posición actual del agente en el entorno.
- Acción(a): paso dado por el agente en un estado determinado.
- Recompensas: por cada acción, el agente recibe una recompensa y una penalización.
- Episodios: el final de la etapa, donde los agentes no pueden emprender nuevas acciones. Se produce cuando el agente ha alcanzado el objetivo o ha fracasado.
- Q(St+1, a): valor Q óptimo esperado de realizar la acción en un estado concreto.
- Q(St,At): es la estimación actual de Q(St+1, a).
- Tabla Q: el agente mantiene la tabla Q de conjuntos de estados y acciones.
- Diferencias temporales (TD): se utiliza para estimar el valor esperado de Q(St+1, a) utilizando el estado y la acción actuales y el estado y la acción anteriores.
¿Cómo funciona Q-Learning?
Aprenderemos en detalle cómo funciona el aprendizaje Q utilizando el ejemplo de un lago helado. En este entorno, el agente debe cruzar el lago helado desde el inicio hasta la meta, sin caer en los agujeros. La mejor estrategia es alcanzar los objetivos por el camino más corto.
Gif por autor
Mesa Q
El agente utilizará una tabla Q para tomar la mejor acción posible en función de la recompensa esperada para cada estado del entorno. En palabras sencillas, una tabla Q es una estructura de datos de conjuntos de acciones y estados, y utilizamos el algoritmo de aprendizaje Q para actualizar los valores de la tabla.
Función Q
La función Q utiliza la ecuación de Bellman y toma como entrada el estado(s) y la acción(a). La ecuación simplifica el cálculo de los valores de estado y de estado-acción.
Imagen de freecodecamp.org
Algoritmo de aprendizaje Q
Imagen del autor
Inicializar Q-Table
Primero inicializaremos la tabla Q. Construiremos la tabla con columnas basadas en el número de acciones y filas basadas en el número de estados.
En nuestro ejemplo, el personaje puede moverse hacia arriba, abajo, izquierda y derecha. Tenemos cuatro acciones posibles y cuatro estados (inicio, inactivo, camino equivocado y fin). También puede considerar el camino equivocado para caer en el agujero. Inicializaremos la tabla Q con valores a 0.
Imagen del autor
Elija una acción
El segundo paso es bastante sencillo. Al principio, el agente elegirá tomar la acción aleatoria (hacia abajo o hacia la derecha), y en la segunda ejecución, utilizará una tabla Q actualizada para seleccionar la acción.
Realizar una acción
La elección de una acción y su ejecución se repetirán varias veces hasta que se detenga el bucle de entrenamiento. La primera acción y el primer estado se seleccionan mediante la tabla Q. En nuestro caso, todos los valores de la tabla Q son cero.
A continuación, el agente se moverá hacia abajo y actualizará la tabla Q mediante la ecuación de Bellman. Con cada movimiento, actualizaremos los valores en la Tabla Q y también la utilizaremos para determinar el mejor curso de acción.
Inicialmente, el agente se encuentra en modo de exploración y elige una acción aleatoria para explorar el entorno. La Estrategia Epsilon Greedy es un método sencillo para equilibrar la exploración y la explotación. La épsilon representa la probabilidad de elegir explorar y explotar cuando hay menos posibilidades de explorar.
Al principio, la tasa épsilon es más alta, lo que significa que el agente está en modo de exploración. Al explorar el entorno, el épsilon disminuye y los agentes empiezan a explotarlo. Durante la exploración, con cada iteración, el agente adquiere más confianza en la estimación de los valores Q
Imagen del autor
En el ejemplo del lago helado, el agente desconoce el entorno, por lo que realiza una acción aleatoria (moverse hacia abajo) para empezar. Como podemos ver en la imagen anterior, la tabla Q se actualiza utilizando la ecuación de Bellman.
Medir las recompensas
Después de emprender la acción, mediremos el resultado y la recompensa.
- La recompensa por alcanzar el objetivo es +1
- La recompensa por tomar el camino equivocado (caer en el agujero) es 0
- La recompensa por inactividad o movimiento en el lago helado también es 0.
Actualizar tabla Q
Actualizaremos la función Q(St,At) mediante la ecuación. Utiliza los valores Q estimados del episodio anterior, la tasa de aprendizaje y el error de Diferencias Temporales. El error de diferencias temporales se calcula utilizando la recompensa inmediata, la recompensa futura máxima esperada descontada y el valor Q de la estimación anterior.
El proceso se repite varias veces hasta que se actualiza la tabla Q y se maximiza la función de valor Q.
Imagen del autor | Equation Visuals de Thomas Simonini
Al principio, el agente está explorando el entorno para actualizar la tabla Q. Y cuando la Q-Table esté lista, el agente empezará a explotar y a tomar mejores decisiones.
Imagen del autor
En el caso de un lago helado, el agente aprenderá a tomar el camino más corto para llegar a la meta y evitar saltar a los agujeros.
Tutorial de Python de Q-Learning
En esta sección, construiremos nuestro modelo Q-learning desde cero utilizando el entorno Gym, Pygame y Numpy. El tutorial de Python es una versión modificada del Cuaderno de Thomas Simonini. Incluye la inicialización del entorno y la tabla Q, la definición de la política codiciosa, la configuración de los hiperparámetros, la creación y ejecución del bucle de entrenamiento y la evaluación, y la visualización de los resultados.
Si tiene problemas para crear y ejecutar su bucle de entrenamiento, puede consultar el código fuente con el resultado.
Puesta en marcha
Configurar una pantalla virtual
Primero instalaremos todas las dependencias para generar un vídeo de reproducción (Gif). Necesitaremos una pantalla virtual (pyvirtualdisplay) para renderizar el entorno y grabar los fotogramas.
Nota: al utilizar `%%capture` estamos suprimiendo la salida de la celda Jupyter.
%%capture
!pip install pyglet==1.5.1
!apt install python-opengl
!apt install ffmpeg
!apt install xvfb
!pip3 install pyvirtualdisplay
# Virtual display
from pyvirtualdisplay import Display
virtual_display = Display(visible=0, size=(1400, 900))
virtual_display.start()
Instalar dependencias
Ahora instalaremos las dependencias que nos ayudarán a crear, ejecutar y evaluar el bucle de entrenamiento.
- gimnasio: Se utiliza para inicializar el entorno FrozenLake-v1.
- pygame: Utilizado para la interfaz de usuario de FrozenLake-v1.
- numPy: Se utiliza para crear y manejar la tabla Q.
%%capture
!pip install gym==0.24
!pip install pygame
!pip install numpy
!pip install imageio imageio_ffmpeg
Importar los paquetes
Ahora importaremos las bibliotecas necesarias.
- Imageio se utiliza para crear la animación.
- tqdm se utiliza para las barras de progreso.
import numpy as np
import gym
import random
import imageio
from tqdm.notebook import trange
Entorno del gimnasio Frozen Lake
Vamos a crear un entorno 4x4 antideslizante utilizando la biblioteca de gimnasia Frozen Lake.
- Hay dos versiones de cuadrícula, "4x4" y "8x8".
- Si `is_slippery=True`, es posible que el agente no se mueva en la dirección prevista debido a la naturaleza resbaladiza del lago helado.
Tras inicializar el entorno, realizaremos un análisis medioambiental.
env = gym.make("FrozenLake-v1",map_name="4x4",is_slippery=False)
print("Observation Space", env.observation_space)
print("Sample observation", env.observation_space.sample()) # display a random observation
Hay 16 espacios únicos en el entorno que se muestran en posiciones aleatorias.
Observation Space Discrete(16)
Sample observation 15
Descubramos el número de acciones y mostremos la acción aleatoria.
El espacio de acción:
- 0: mover a la izquierda
- 1: bajar
- 2: mover a la derecha
- 3: ascender
Función de recompensa:
- Alcanzar el objetivo: +1
- Cayendo en el agujero: 0
- Permanecer en el lago helado: 0
print("Action Space Shape", env.action_space.n)
print("Action Space Sample", env.action_space.sample())
Action Space Shape 4
Action Space Sample 1
Crear e inicializar la tabla Q
La tabla Q tiene columnas como acciones y filas como estados. Podemos utilizar OpenAI Gym para encontrar el espacio de acción y el espacio de estado. A continuación, utilizaremos esta información para crear la tabla Q.
state_space = env.observation_space.n
print("There are ", state_space, " possible states")
action_space = env.action_space.n
print("There are ", action_space, " possible actions")
There are 16 possible states
There are 4 possible actions
Para inicializar la Q-Table, crearemos un array Numpy de state_space y actions space. Crearemos una matriz de 16 X 4.
def initialize_q_table(state_space, action_space):
Qtable = np.zeros((state_space, action_space))
return Qtable
Qtable_frozenlake = initialize_q_table(state_space, action_space)
Política Epsilon-greedy
En la sección anterior, hemos aprendido acerca de la estrategia codiciosa épsilon que maneja los compromisos de exploración y explotación. Con una probabilidad de 1 - ɛ, hacemos explotación, y con la probabilidad ɛ, hacemos exploración.
En la epsilon_greedy_policy lo haremos:
- Genera el número aleatorio entre 0 y 1.
- Si el número aleatorio es mayor que épsilon, haremos explotación. Significa que el agente tomará la acción con el valor más alto dado un estado.
- Si no, haremos exploración (Tomar acciones al azar).
def epsilon_greedy_policy(Qtable, state, epsilon):
random_int = random.uniform(0,1)
if random_int > epsilon:
action = np.argmax(Qtable[state])
else:
action = env.action_space.sample()
return action
Definir la política codiciosa
Como sabemos, Q-learning es un algoritmo off-policy, lo que significa que la política de acción y la función de actualización son diferentes.
En este ejemplo, la política Epsilon Greedy es la política de actuación, y la política Greedy es la política de actualización.
La política Greedy también será la política final cuando se entrene al agente. Se utiliza para seleccionar el valor de estado y acción más alto de la tabla Q.
def greedy_policy(Qtable, state):
action = np.argmax(Qtable[state])
return action
Hiperparámetros del modelo
Estos hiperparámetros se utilizan en el bucle de entrenamiento, y afinarlos te dará mejores resultados.
El Agente necesita explorar suficiente espacio de estados para aprender una buena aproximación de valores; necesitamos tener un decaimiento progresivo de épsilon. Si la tasa de decaimiento es alta, el agente puede quedarse atascado, ya que no ha explorado suficiente espacio de estados.
- Hay 10.000 episodios de formación y 100 de evaluación.
- El índice de aprendizaje es de 0,7.
- Estamos utilizando "FrozenLake-v1" como entorno con 99 pasos máximos por episodio.
- La gamma (tasa de descuento) es 0,95.
- eval_seed: semilla de evaluación para el entorno.
- La probabilidad épsilon de exploración al inicio es 1,0, y la probabilidad mínima será 0,05.
- La tasa de decaimiento exponencial de la probabilidad épsilon es de 0,0005.
# Training parameters
n_training_episodes = 10000
learning_rate = 0.7
# Evaluation parameters
n_eval_episodes = 100
# Environment parameters
env_id = "FrozenLake-v1"
max_steps = 99
gamma = 0.95
eval_seed = []
# Exploration parameters
max_epsilon = 1.0
min_epsilon = 0.05
decay_rate = 0.0005
Formación de modelos
En el bucle de entrenamiento:
- Crear un bucle para los episodios de formación.
- Primero reduciremos epsilon. Como cada vez necesitamos menos exploración y más explotación con cada episodio.
- Restablece el entorno.
- Crear un bucle anidado para los pasos máximos.
- Elija la acción utilizando la política codiciosa épsilon.
- Realiza la acción (At) y observa la recompensa esperada(Rt+1) y el estado(St+1).
- Realiza la acción (a) y observa el estado resultante (s') y la recompensa (r).
- Actualiza la función Q utilizando la fórmula.
- Si `done= True`, termina el episodio y rompe el bucle.
- Por último, cambia el estado actual por un nuevo estado.
- Una vez completados todos los episodios de entrenamiento, la función devolverá la tabla Q actualizada.
def train(n_training_episodes, min_epsilon, max_epsilon, decay_rate, env, max_steps, Qtable):
for episode in trange(n_training_episodes):
epsilon = min_epsilon + (max_epsilon - min_epsilon)*np.exp(-decay_rate*episode)
# Reset the environment
state = env.reset()
step = 0
done = False
# repeat
for step in range(max_steps):
action = epsilon_greedy_policy(Qtable, state, epsilon)
new_state, reward, done, info = env.step(action)
Qtable[state][action] = Qtable[state][action] + learning_rate * (reward + gamma * np.max(Qtable[new_state]) - Qtable[state][action])
# If done, finish the episode
if done:
break
# Our state is the new state
state = new_state
return Qtable
Tardamos 3 segundos en terminar 10.000 episodios de entrenamiento.
Qtable_frozenlake = train(n_training_episodes, min_epsilon, max_epsilon, decay_rate, env, max_steps, Qtable_frozenlake)
Como podemos ver, la Q-Table entrenada tiene valores, y el agente ahora utilizará estos valores para navegar por el entorno y alcanzar el objetivo.
Qtable_frozenlake
array([[0.73509189, 0.77378094, 0.77378094, 0.73509189],
[0.73509189, 0. , 0.81450625, 0.77378094],
[0.77378094, 0.857375 , 0.77378094, 0.81450625],
[0.81450625, 0. , 0.77378094, 0.77378094],
[0.77378094, 0.81450625, 0. , 0.73509189],
[0. , 0. , 0. , 0. ],
[0. , 0.9025 , 0. , 0.81450625],
[0. , 0. , 0. , 0. ],
[0.81450625, 0. , 0.857375 , 0.77378094],
[0.81450625, 0.9025 , 0.9025 , 0. ],
[0.857375 , 0.95 , 0. , 0.857375 ],
[0. , 0. , 0. , 0. ],
[0. , 0. , 0. , 0. ],
[0. , 0.9025 , 0.95 , 0.857375 ],
[0.9025 , 0.95 , 1. , 0.9025 ],
[0. , 0. , 0. , 0. ]])
Evaluación
El agente_de_evaluación se ejecuta durante `n_episodios_de_evaluación` y devuelve la media y la desviación estándar de la recompensa.
- En el bucle, comprobaremos primero si hay una semilla de evaluación. Si no, entonces reiniciaremos el entorno sin semillas.
- El bucle anidado se ejecutará hasta max_steps.
- El agente tomará la acción que tenga la máxima recompensa futura esperada en un estado dado utilizando Q-Table.
- Calcula la recompensa.
- Cambia el estado.
- Si ha terminado (el agente cae en el agujero o se ha alcanzado el objetivo), rompa el bucle.
- Añade los resultados.
- Al final, utilizaremos estos resultados para calcular la media y la desviación típica.
def evaluate_agent(env, max_steps, n_eval_episodes, Q, seed):
episode_rewards = []
for episode in range(n_eval_episodes):
if seed:
state = env.reset(seed=seed[episode])
else:
state = env.reset()
step = 0
done = False
total_rewards_ep = 0
for step in range(max_steps):
# Take the action (index) that have the maximum reward
action = np.argmax(Q[state][:])
new_state, reward, done, info = env.step(action)
total_rewards_ep += reward
if done:
break
state = new_state
episode_rewards.append(total_rewards_ep)
mean_reward = np.mean(episode_rewards)
std_reward = np.std(episode_rewards)
return mean_reward, std_reward
Como puede ver, obtuvimos la puntuación perfecta con desviación típica cero. Significa que nuestro agente ha alcanzado el objetivo en los 100 episodios.
# Evaluate our Agent
mean_reward, std_reward = evaluate_agent(env, max_steps, n_eval_episodes, Qtable_frozenlake, eval_seed)
print(f"Mean_reward={mean_reward:.2f} +/- {std_reward:.2f}")
Mean_reward=1.00 +/- 0.00
Visualización del resultado
Hasta ahora, hemos estado jugando con números, y para dar la demo, necesitamos crear un Gif animado del agente desde que empieza hasta que llega a la meta.
- Primero crearemos el estado reseteando el entorno con un entero aleatorio 0-500.
- Renderiza el entorno utilizando rdb_array para crear un array de imágenes.
- Luego añade la `img` al array `images`.
- En el bucle, tomaremos el paso usando la Q-Table y renderizaremos la imagen para cada paso.
- Al final, usaremos este array e imageio para crear un Gif de un fotograma por segundo.
def record_video(env, Qtable, out_directory, fps=1):
images = []
done = False
state = env.reset(seed=random.randint(0,500))
img = env.render(mode='rgb_array')
images.append(img)
while not done:
# Take the action (index) that have the maximum expected future reward given that state
action = np.argmax(Qtable[state][:])
state, reward, done, info = env.step(action) # We directly put next_state = state for recording logic
img = env.render(mode='rgb_array')
images.append(img)
imageio.mimsave(out_directory, [np.array(img) for i, img in enumerate(images)], fps=fps)
Si estás en un cuaderno Jupyter, puedes mostrar el Gif utilizando la función `IPython.display` Image.
video_path="/content/replay.gif"
video_fps=1
record_video(env, Qtable_frozenlake, video_path, video_fps)
from IPython.display import Image
Image('./replay.gif')
Ahora puedes compartir estos resultados con tus colegas y compañeros de clase o publicarlos en las redes sociales.
Preguntas frecuentes sobre Q-Learning
¿Cuál es la desventaja del Q-learning?
El proceso de aprendizaje en Q-learning es costoso para el agente, especialmente en los primeros pasos. ¿Por qué? Para hacer converger la política óptima, cada par de estado y acción se visita con frecuencia.
¿Por qué el aprendizaje Q se llama aprendizaje Q?
En Q-learning, "Q" significa calidad. Representa lo útil que es una acción determinada para conseguir recompensas futuras, lo que se utiliza para crear un sistema de mapas de estado y acción para maximizar las recompensas esperadas.
¿Por qué Q-Learning está fuera de la política?
En el aprendizaje Q, la política actualizada es diferente de la política de comportamiento (acción), y por eso se llama algoritmo off-policy.
¿Converge siempre el aprendizaje Q?
Sí. Durante el entrenamiento, el algoritmo siempre converge a la política óptima.
¿Por qué necesitamos el aprendizaje Q profundo?
El aprendizaje Q es un algoritmo sencillo diseñado para un entorno más pequeño y discreto. En el caso de un entorno más grande, necesitaremos una tabla Q de estados y acciones increíblemente grande que requerirá más memoria y computación para entrenarla. Por su parte, el aprendizaje Q profundo sustituye la tabla Q por una red neuronal para manejar grandes entornos que implican acciones y estados continuos.
Cursos de aprendizaje automático
tutorial
Aprendizaje automático de datos categóricos con el tutorial de Python
tutorial
Tutorial del Optimizador Adam: Intuición e implementación en Python
tutorial
Tutorial sobre el uso de XGBoost en Python
Bekhruz Tuychiev
16 min
tutorial
Comprender la regresión logística en el tutorial de Python
Avinash Navlani
10 min
tutorial
¿Qué es el Refuerzo?
Vinod Chugani
11 min
tutorial
Introducción a k-Means Clustering con scikit-learn en Python
Kevin Babitz
21 min