Aprendizaje por Refuerzo con Gymnasium: Una Guía Práctica

El Aprendizaje por Refuerzo (RL) es uno de los tres paradigmas principales de aprendizaje automático, los otros dos son el aprendizaje supervisado y no supervisado. En RL, un agente aprende a interactuar con su entorno para maximizar las recompensas acumulativas. Aprende la acción óptima bajo diferentes condiciones ambientales a través de ensayo y error. El Aprendizaje por Refuerzo con Retroalimentación Humana (RLHF) permite al agente modificar su comportamiento en función de las entradas humanas en cada paso.

RL resuelve problemas como autos autónomos, trading automatizado, jugadores de computadora en videojuegos, entrenamiento de robots, y más. Cuando se utilizan redes neuronales profundas para aplicar algoritmos de RL, se llama Aprendizaje por Refuerzo Profundo.

En este tutorial, te mostraré cómo comenzar con Gymnasium, una biblioteca de Python de código abierto para desarrollar y comparar algoritmos de aprendizaje por refuerzo. Demostraré cómo configurarlo, explorar varios entornos de RL y usar Python para construir un agente simple para implementar un algoritmo de RL.

¿Qué es Gymnasium?

Gymnasium es una biblioteca de Python de código abierto diseñada para apoyar el desarrollo de algoritmos de RL. Para facilitar la investigación y el desarrollo en RL, Gymnasium proporciona:

  • Una amplia variedad de entornos, desde juegos simples hasta problemas que imitan escenarios de la vida real.
  • APIs optimizadas y envoltorios para interactuar con los entornos.
  • La capacidad de crear entornos personalizados y aprovechar el marco de API.

Los desarrolladores pueden construir algoritmos de RL y utilizar llamadas de API para tareas como:

  • Pasar la acción elegida por el agente al entorno.
  • Conocer el estado del entorno y la recompensa después de cada acción.
  • Entrenar el modelo.
  • Probar el rendimiento del modelo.

OpenAI’s Gym versus el Gimnasio de Farama

OpenAI no ha dedicado recursos significativos al desarrollo de Gym porque no era una prioridad comercial para la empresa. La Fundación Farama fue creada para estandarizar y mantener bibliotecas de RL a largo plazo. Gymnasium es el fork de la Fundación Farama de Gym de OpenAI. Gymnasium 0.26.2 es un reemplazo directo de Gym 0.26.2. Con el fork, Farama tiene como objetivo agregar métodos funcionales (además de basados en clases) para todas las llamadas de API, soportar entornos vectoriales y mejorar los envoltorios. El objetivo general es hacer que el marco sea más limpio y eficiente.

Configuración de Gymnasium

El gimnasio necesita versiones específicas (no las últimas versiones) de varios programas de dependencias como NumPy y PyTorch. Por lo tanto, recomendamos crear un entorno Conda o venv nuevo o un cuaderno nuevo para instalar, utilizar Gymnasium y ejecutar programas de RL. 

Puedes usar este cuaderno de DataLab para seguir el tutorial.

Instalación de Gymnasium

Para instalar Gymnasium en un servidor o máquina local, ejecuta: 

$ pip install gymnasium

Para instalar utilizando un Notebook como Google Colab o el DataLab de DataCamp, usa:

!pip install gymnasium

El comando anterior instala Gymnasium y las versiones correctas de las dependencias.

Explorando los entornos de Gymnasium

A partir de noviembre de 2024, Gymnasium incluye más de 60 entornos integrados. Para explorar los entornos integrados disponibles, utiliza la función gym.envs.registry.all(), como se ilustra en el ejemplo a continuación:

import gymnasium as gym for i in gym.envs.registry.keys(): print(i)

También puedes visitar la página de inicio del Gimnasio. La columna izquierda tiene enlaces a todos los entornos. La página web de cada entorno incluye detalles sobre él, como acciones, estados, etc. 

Los entornos están organi</diy6)zados en categorías como Control Clásico, Box2D y más. A continuación, enumero algunos de los entornos comunes en cada grupo:

  • Control Clásico: Estos son entornos canónicos utilizados en el desarrollo de RL; forman la base de muchos ejemplos de libros de texto. Ofrecen la combinación adecuada de complejidad y simplicidad para probar y evaluar nuevos algoritmos de RL. Los entornos de control clásico en el Gimnasio incluyen: 
    • Acrobot
    • Cart Pole
    • Mountain Car Discrete
    • Mountain Car Continuous
    • Pendulum
  • Box2D: Box2D es un Motor de Física 2D para Juegos. Los entornos basados en este motor incluyen juegos simples como:
    • Lunar Lander
    • Car Racing
  • ToyText: Estos son entornos pequeños y simples a menudo utilizados para depurar algoritmos de RL. Muchos de estos entornos se basan en el modelo de mundo de cuadrícula pequeña y en juegos de cartas simples. Ejemplos incluyen:
    • Blackjack
    • Taxi
    • Frozen Lake
  • MuJoCo: Multiarticulaciones dinámicas con Contacto (MuJoCo) es un motor de física de código abierto que simula entornos para aplicaciones como robótica, biomecánica, ML, etc. Los entornos de MuJoCo en Gymnasium incluyen:
    • Ant
    • Hopper
    • Humanoid
    • Swimmer
    • Y más

Además de los entornos integrados, Gymnasium se puede utilizar con muchos entornos externos utilizando la misma API.

Usaremos uno de los entornos de Control Clásico canónicos en este tutorial. Para importar un entorno específico, utiliza el comando .make() y pasa el nombre del entorno como argumento. Por ejemplo, para crear un nuevo entorno basado en CartPole (versión 1), utiliza el siguiente comando: 

import gymnasium as gym env = gym.make("CartPole-v1")

Entendiendo los conceptos de Aprendizaje por Refuerzo en Gymnasium

En resumen, el Aprendizaje por Refuerzo consiste en un agente (como un robot) que interactúa con su entorno. Una política decide las acciones del agente. Dependiendo de las acciones del agente, el entorno otorga una recompensa (o penalización) en cada momento. El agente utiliza el Aprendizaje por Refuerzo para descubrir la política óptima que maximiza las recompensas totales que el agente obtiene. 

Componentes de un entorno de Aprendizaje por Refuerzo

Los siguientes son los componentes clave de un entorno de RL:

  • Entorno: El sistema externo, mundo o contexto. El agente interactúa con el entorno en una serie de pasos de tiempo. En cada paso de tiempo, basado en la acción del agente, el entorno:
    • Da una recompensa (o penalización)
    • Decide el siguiente estado
  • Estado: Una representación matemática de la configuración actual del entorno.
    • Por ejemplo, el estado de un entorno de péndulo puede incluir la posición del péndulo y la velocidad angular en cada instante de tiempo.
    • Estado terminal: Un estado que no conduce a nuevos/otros estados.
  • Agente: El algoritmo que observa el entorno y toma diversas acciones basadas en esta observación. El objetivo del agente es maximizar sus recompensas.
    • Por ejemplo, el agente decide con qué fuerza y en qué dirección empujar el péndulo.
  • Observación: Una representación matemática de la visión del agente sobre el entorno, adquirida, por ejemplo, utilizando sensores. 
  • Acción: La decisión tomada por el agente antes de proceder al siguiente paso. La acción afecta el siguiente estado del entorno y le otorga al agente una recompensa. 
  • Recompensa: La retroalimentación del entorno al agente. Puede ser positiva o negativa, dependiendo de la acción y el estado del entorno. 
  • Retorno: El retorno acumulado esperado en futuros intervalos de tiempo. Las recompensas de intervalos de tiempo futuros se pueden descontar utilizando un factor de descuento.
  • Política: La estrategia del agente sobre qué acción tomar en varios estados. Se representa típicamente como una matriz de probabilidades, P, que asigna estados a acciones.
    • Dada un conjunto finito de m estados posibles y n acciones posibles, el elemento Pmn en la matriz denota la probabilidad de tomar la acción an en el estado sm.  
  • Episodio: La serie de pasos de tiempo desde el estado inicial (aleatorizado) hasta que el agente alcanza un estado terminal.

Espacio de observación y espacio de acción

La observación es la información que el agente recopila sobre el entorno. Un agente, por ejemplo, un robot, podría recolectar información ambiental utilizando sensores. Idealmente, el agente debería ser capaz de observar el estado completo, que describe todos los aspectos del entorno. En la práctica, el agente utiliza sus observaciones como un sustituto del estado. Así, las observaciones deciden las acciones del agente.

Un espacio es análogo a un conjunto matemático. El espacio de elementos X incluye todas las posibles instancias de X. El espacio de X también define la estructura (sintaxis y formato) de todos los elementos del tipo X. Cada entorno de Gimnasio tiene dos espacios, el espacio de acción, action_space, y el espacio de observación, observation_space. Tanto los espacios de acción como de observación derivan de la superclase gymnasium.spaces.Space

Espacio de observación

El espacio de observación es el espacio que incluye todas las observaciones posibles. También define el formato en el que se almacenan las observaciones. El espacio de observación se representa típicamente como un objeto de tipo Box. Este es un ndarray que describe los parámetros de las observaciones. La caja especifica los límites de cada dimensión. Puedes ver el espacio de observación para un entorno utilizando el método observation_space:

print("observation space: ", env.observation_space)

En el caso del entorno CartPole-v1, la salida se ve como el ejemplo a continuación:

observation space: Box([-4.8 -inf -0.41887903 -inf], [4.8 inf 0.41887903 inf], (4,), float32)

En este ejemplo, el CartPole-v1 el espacio de observación tiene 4 dimensiones. Los 4 elementos del array de observación son:

  • Posición del carrito – varía entre -4.8 y +4.8
  • Velocidad del carro – varía entre y +
  • Ángulo del poste – varía entre -0,4189 y +0,4189
  • Velocidad angular del poste – varía entre y +

Para ver un ejemplo de una matriz de observaciones individuales, utiliza el comando .reset().

observation, info = env.reset() print("observation: ", observation)

En el caso del entorno CartPole-v1, la salida se ve como en el ejemplo a continuación:

[ 0.03481963 -0.0277232 0.01703267 -0.04870504]

Los cuatro elementos de este array corresponden a las cuatro cantidades observadas (posición del carrito, velocidad del carrito, ángulo del poste, velocidad angular del poste), como se explicó anteriormente.

Espacio de acción

El espacio de acción incluye todas las posibles acciones que el agente puede tomar. El espacio de acción también define el formato en el que se representan las acciones. Puedes ver el espacio de acción para un entorno utilizando el método action_space:

print("action space: ", env.action_space)

En el caso del entorno CartPole-v1, la salida se ve como el ejemplo a continuación:

action space: Discrete(2)

En el caso del entorno CartPole-v1, el espacio de acción es discreto. Hay un total de dos acciones que el agente puede tomar:

  • 0: Empujar el carrito hacia la izquierda
  • 1: Empujar el carrito hacia la derecha

Construyendo tu primer agente de RL con Gymnasium

En las secciones anteriores, exploramos los conceptos básicos de RL y Gymnasium. En esta sección te mostramos cómo usar Gymnasium para construir un agente de RL.

Creación y reinicio del entorno

El primer paso es crear una instancia del entorno. Para crear nuevos entornos, utiliza el método .make().

env = gym.make('CartPole-v1')

Las interacciones del agente cambian el estado del entorno. El método .reset() reinicia el entorno a un estado inicial. Por defecto, el entorno se inicializa en un estado aleatorio. Puedes usar un parámetro SEED con el método .reset() para inicializar el entorno en el mismo estado cada vez que se ejecute el programa. El siguiente código muestra cómo hacerlo:

SEED = 1111 env.reset(seed=SEED)

El muestreo de acciones también implica aleatoriedad. Para controlar esta aleatoriedad y obtener un camino de entrenamiento totalmente reproducible, podemos sembrar los generadores de números aleatorios de NumPy y PyTorch:

np.random.seed(SEED) torch.manual_seed(SEED)

Acciones aleatorias versus inteligentes

En cada paso en un proceso de Markov, el agente puede elegir aleatoriamente una acción y explorar el entorno hasta llegar a un estado terminal. Al elegir acciones al azar:

  • Puede llevar mucho tiempo llegar al estado terminal.
  • Las recompensas acumulativas son mucho menores de lo que podrían haber sido.

Entrenar al agente para optimizar la selección de acciones basadas en experiencias previas (de interactuar con el entorno) es más eficiente para maximizar las recompensas a largo plazo.

El agente no entrenado comienza con acciones aleatorias basadas en una política inicializada de forma aleatoria. Esta política suele representarse como una red neuronal. Durante el entrenamiento, el agente aprende la política óptima que maximiza las recompensas. En RL, el proceso de entrenamiento también se llama optimización de políticas.

Hay varios métodos de optimización de políticas. Las ecuaciones de Bellman describen cómo calcular el valor de las políticas de RL y determinar la política óptima. En este tutorial, utilizaremos una técnica simple llamada gradientes de políticas. Otros métodos existen, como Optimización de Política Proximal (PPO).

Implementación de un Agente Simple de Gradiente de Políticas

Para construir un agente RL que utilice gradientes de política, creamos una red neuronal para implementar la política, escribimos funciones para calcular los retornos y la pérdida a partir de las recompensas paso a paso y las probabilidades de acción, y actualizamos iterativamente la política utilizando técnicas estándar de retropropagación.

Configuración de la red de política

Utilizamos una red neuronal para implementar la política. Debido a que CartPole-v1 es un entorno simple, utilizamos una red neuronal con:

  • Dimensiones de entrada iguales a la dimensionalidad del espacio de observación del entorno.
  • Una única capa oculta con 64 neuronas.
  • Las dimensiones de salida son iguales a la dimensionalidad del espacio de acción del entorno.

Por lo tanto, la función de la red de políticas es mapear estados observados a acciones. Dada una observación de entrada, predice la acción correcta. El código a continuación implementa la red de políticas:

class PolicyNetwork(nn.Module): def __init__(self, input_dim, hidden_dim, output_dim, dropout): super().__init__() self.layer1 = nn.Linear(input_dim, hidden_dim) self.layer2 = nn.Linear(hidden_dim, output_dim) self.dropout = nn.Dropout(dropout) def forward(self, x): x = self.layer1(x) x = self.dropout(x) x = F.relu(x) x = self.layer2(x) return x

Recolección de recompensas y el pase hacia adelante

Como se mencionó, en cada paso del proceso de Markov, el entorno otorga una recompensa basada en la acción y el estado del agente. El objetivo en RL es maximizar el retorno total.

  • El retorno en cada instante de tiempo es la suma acumulativa de las recompensas obtenidas desde el principio hasta ese paso.
  • El retorno total en cada episodio se obtiene acumulando todas las recompensas paso a paso de ese episodio. Así, el retorno total es el retorno en el último instante de tiempo (cuando el agente alcanza un estado terminal).

En la práctica, al acumular recompensas, es común:

  • Ajustar las recompensas futuras usando un factor de descuento.
  • Normalizar el arreglo de retornos paso a paso para asegurar un entrenamiento suave y estable.

El código a continuación muestra cómo hacerlo:

def calculate_stepwise_returns(rewards, discount_factor): returns = [] R = 0 for r in reversed(rewards): R = r + R * discount_factor returns.insert(0, R) returns = torch.tensor(returns) normalized_returns = (returns - returns.mean()) / returns.std() return normalized_returns

El pase hacia adelante consiste en ejecutar el agente basado en la política actual hasta que llegue a un estado terminal y recopilar las recompensas paso a paso y las probabilidades de acción. Los siguientes pasos explican cómo implementar el pase hacia adelante:

  • Restablecer el entorno a un estado inicial.
  • Inicializar buffers para almacenar las probabilidades de acción, las recompensas y el retorno acumulativo
  • Usar la función .step() para ejecutar de forma iterativa el agente en el entorno hasta que termine:
    • Obtener la observación del estado del entorno.
    • Obtenga la acción predicha por la política basada en la observación.
    • Utilice la función Softmax para estimar la probabilidad de tomar la acción predicha.
    • Simule una distribución de probabilidad categórica basada en estas probabilidades estimadas.
    • Muestree esta distribución para obtener la acción del agente.
    • Estime el logaritmo de la probabilidad de la acción muestreada de la distribución simulada.
  • Agregue el logaritmo de la probabilidad de las acciones y las recompensas de cada paso a sus respectivos buffers.
  • Estime los valores normalizados y descontados de los retornos en cada paso basados en las recompensas.
def forward_pass(env, policy, discount_factor): log_prob_actions = [] rewards = [] done = False episode_return = 0 policy.train() observation, info = env.reset() while not done: observation = torch.FloatTensor(observation).unsqueeze(0) action_pred = policy(observation) action_prob = F.softmax(action_pred, dim = -1) dist = distributions.Categorical(action_prob) action = dist.sample() log_prob_action = dist.log_prob(action) observation, reward, terminated, truncated, info = env.step(action.item()) done = terminated or truncated log_prob_actions.append(log_prob_action) rewards.append(reward) episode_return += reward log_prob_actions = torch.cat(log_prob_actions) stepwise_returns = calculate_stepwise_returns(rewards, discount_factor) return episode_return, stepwise_returns, log_prob_actions

Actualización de la política basada en las recompensas

La pérdida representa la cantidad sobre la cual aplicamos descenso de gradiente. El objetivo en RL es maximizar los retornos. Por lo tanto, usamos el valor de retorno esperado como un proxy para la pérdida. El valor de retorno esperado se calcula como el producto de los retornos esperados por paso y el logaritmo de las acciones por paso. El código a continuación calcula la pérdida:

def calculate_loss(stepwise_returns, log_prob_actions): loss = -(stepwise_returns * log_prob_actions).sum() return loss

Para actualizar la política, se ejecuta retropropagación con respecto a la función de pérdida. El método update_policy() a continuación invoca el método calculate_loss(). Luego se ejecuta la retropropagación en esta pérdida para actualizar los parámetros de la política, es decir, los pesos del modelo de la red de la política.

def update_policy(stepwise_returns, log_prob_actions, optimizer): stepwise_returns = stepwise_returns.detach() loss = calculate_loss(stepwise_returns, log_prob_actions) optimizer.zero_grad() loss.backward() optimizer.step() return loss.item()

Actualizar la política basada en el gradiente de los retornos se llama el método de gradiente de política

Entrenamiento de la política

Ahora tenemos todos los componentes necesarios para entrenar y evaluar la política. Implementamos el bucle de entrenamiento como se explica en los siguientes pasos:  

Antes de comenzar, declaramos los hiperparámetros, instanciamos una política y creamos un optimizador:

  • Declaramos los hiperparámetros como constantes en Python:
    • MAX_EPOCHS es el número máximo de iteraciones que estamos dispuestos a ejecutar para entrenar la política.
    • DISCOUNT_FACTOR decide la importancia relativa de las recompensas de pasos futuros. Un factor de descuento de 1 significa que todas las recompensas son igualmente importantes, mientras que un valor de 0 significa que solo es importante la recompensa del paso actual.
    • N_TRIALS es el número de episodios sobre los cuales promediamos los retornos para evaluar el desempeño del agente. Decidimos que el entrenamiento es exitoso si el retorno promedio sobre N_TRIALS episodios está por encima del umbral.
    • REWARD_THRESHOLD: Si la política puede lograr un retorno mayor que el umbral, se considera exitosa.
    • DROPOUT decide la fracción de los pesos que deben ser establecidos aleatoriamente en cero. La función de dropout establece aleatoriamente una fracción de los pesos del modelo en cero. Esto reduce la dependencia de neuronas específicas y previene el sobreajuste, haciendo que la red sea más robusta.
    • TASA_APRENDIZAJE decide cuánto pueden modificarse los parámetros de la política en cada paso. La actualización de los parámetros en cada iteración es el producto del gradiente y la tasa de aprendizaje. 
  • Define la política como una instancia de la clase PolicyNetwork (implementada anteriormente). 
  • Cree un optimizador utilizando el algoritmo Adam y la tasa de aprendizaje. 

Para entrenar la política, ejecutamos iterativamente los pasos de entrenamiento hasta que el retorno promedio (durante N_TRIALS) sea mayor que el umbral de recompensa:

  • Para cada episodio, ejecutar el pase hacia adelante una vez. Recolectar la probabilidad logarítmica de las acciones, los retornos paso a paso, y el retorno total de ese episodio. Acumular los retornos episódicos en un arreglo. 
  • Calcula la pérdida utilizando los logaritmos de las probabilidades y los retornos paso a paso. Ejecuta la retropropagación en la pérdida. Utiliza el optimizador para actualizar los parámetros de la política.
  • Verifica si el retorno promedio durante N_TRIALS supera el umbral de recompensa.

El código a continuación implementa estos pasos:

def main(): MAX_EPOCHS = 500 DISCOUNT_FACTOR = 0.99 N_TRIALS = 25 REWARD_THRESHOLD = 475 PRINT_INTERVAL = 10 INPUT_DIM = env.observation_space.shape[0] HIDDEN_DIM = 128 OUTPUT_DIM = env.action_space.n DROPOUT = 0.5 episode_returns = [] policy = PolicyNetwork(INPUT_DIM, HIDDEN_DIM, OUTPUT_DIM, DROPOUT) LEARNING_RATE = 0.01 optimizer = optim.Adam(policy.parameters(), lr = LEARNING_RATE) for episode in range(1, MAX_EPOCHS+1): episode_return, stepwise_returns, log_prob_actions = forward_pass(env, policy, DISCOUNT_FACTOR) _ = update_policy(stepwise_returns, log_prob_actions, optimizer) episode_returns.append(episode_return) mean_episode_return = np.mean(episode_returns[-N_TRIALS:]) if episode % PRINT_INTERVAL == 0: print(f'| Episode: {episode:3} | Mean Rewards: {mean_episode_return:5.1f} |') if mean_episode_return >= REWARD_THRESHOLD: print(f'Reached reward threshold in {episode} episodes') break

Por último, invoca la función main() para entrenar la política:

main()

Usa este libro de trabajo DataLab para ejecutar el algoritmo anterior directamente y resolver el entorno de CartPole utilizando RL. 

Técnicas Avanzadas en Gymnasium

Habiendo demostrado cómo implementar un algoritmo de RL, ahora discutimos algunas técnicas avanzadas comúnmente utilizadas en la práctica. 

Usando arquitecturas preconstruidas

Implementar algoritmos de RL desde cero es un proceso largo y difícil, especialmente para entornos complejos y políticas de vanguardia. 

Una alternativa más práctica es utilizar software como Stable Baselines3. Viene con implementaciones de algoritmos de RL probados y probados. Incluye agentes pre-entrenados, scripts de entrenamiento, herramientas de evaluación y módulos para trazar gráficos y grabar videos.

Ray RLib es otra herramienta popular para RL. RLib está diseñado como una solución escalable, lo que facilita la implementación de algoritmos de RL en sistemas multi-GPU. También soporta RL multiagente, lo que abre nuevas posibilidades como:

  • Aprendizaje multiagente independiente: Cada agente trata a otros agentes como parte del entorno.
  • Entrenamiento colaborativo multiagente: Un grupo de agentes comparte la misma política y funciones de valor y aprenden de las experiencias de los demás en paralelo.
  • Entrenamiento adversarial: Agentes (o grupos de agentes) compiten entre sí en entornos de juegos competitivos.

Tanto con RLib como con Stable Baselines3, puedes importar y utilizar entornos de OpenAI Gymnasium.

Entornos personalizados

Los entornos empaquetados con Gymnasium son la opción adecuada para probar nuevas estrategias de RL y entrenar políticas. Sin embargo, para la mayoría de las aplicaciones prácticas, necesitas crear y utilizar un entorno que refleje con precisión el problema que deseas resolver. Puedes usar Gymnasium para crear un entorno personalizado. La ventaja de usar entornos personalizados de Gymnasium es que muchas herramientas externas como RLib y Stable Baselines3 ya están configuradas para trabajar con la estructura de la API de Gymnasium.

Para crear un entorno personalizado en Gymnasium, necesitas definir:

  • El espacio de observación.
  • Las condiciones terminales.
  • El conjunto de acciones que el agente puede elegir.
  • Cómo inicializar el entorno (cuando se llama la función reset()).
  • Cómo el entorno decide el próximo estado dado las acciones del agente (cuando se llama la función step()).

Para obtener más información, sigue la guía del Gimnasio sobre la creación de entornos personalizados.

Mejores Prácticas para Usar el Gimnasio

Experimenta con diferentes entornos

El código en este tutorial mostró cómo implementar el algoritmo de gradiente de política en el entorno CartPole. Este es un entorno simple con un espacio de acción discreto. Para entender mejor el RL, te aconsejamos que apliques el mismo algoritmo de gradiente de política (y otros algoritmos, como PPO) en otros entornos.

Por ejemplo, el entorno Pendulum tiene un espacio de acción continuo. Consiste en una sola entrada representada como una variable continua: el (magnitude y dirección del) torque aplicado al péndulo en un estado dado. Este torque puede tomar cualquier valor entre -2 y +2.

Experimentar con diferentes algoritmos en varios entornos te ayuda a comprender mejor los diferentes tipos de soluciones de RL y sus desafíos.

Monitorea el progreso del entrenamiento

Los entornos de RL a menudo consisten en robots, péndulos, coches de montaña, videojuegos, etc. Visualizar las acciones del agente dentro del entorno proporciona una mejor comprensión intuitiva del rendimiento de la política.

En Gymnasium, el método env.render() visualiza las interacciones del agente con el entorno. Muestra gráficamente el estado actual del entorno: pantallas de juego, la posición del péndulo o del poste del carrito, etc. La retroalimentación visual de las acciones del agente y las respuestas del entorno ayuda a monitorear el rendimiento del agente y su progreso a lo largo del proceso de entrenamiento.

Existen cuatro modos de renderizado: “humano”, “rgb_array”, “ansi” y “rgb_array_list”. Para visualizar el rendimiento del agente, utiliza el modo de renderizado “humano”. El modo de renderizado se especifica al inicializar el entorno. Por ejemplo:

env = gym.make(‘CartPole-v1’, render_mode=’human’)

Para realizar la representación, involucra el método .render() después de cada acción realizada por el agente (llamando al método .step()). El seudocódigo a continuación ilustra cómo hacer esto:

while not done: … step, reward, terminated, truncated, info = env.step(action.item()) env.render()

Solución de errores comunes

Gymnasium facilita la interacción con entornos de RL complejos. Sin embargo, es un software en constante actualización con muchas dependencias. Por lo tanto, es esencial estar atento a algunos tipos comunes de errores.

Problemas de versiones

  • Desajuste de versión de Gimnasio: El paquete de software del Gimnasio de Farama se bifurcó de Gimnasio de OpenAI a partir de la versión 0.26.2. Ha habido algunos cambios significativos entre las versiones antiguas de Gimnasio y las nuevas versiones de Gimnasio. Muchas implementaciones disponibles públicamente se basan en las versiones antiguas de Gimnasio y es posible que no funcionen directamente con la versión más reciente. En tales casos, es necesario retroceder la instalación a una versión más antigua o adaptar el código para que funcione con la versión más nueva.
  • Desajuste de versión del entorno: Muchos entornos de Gymnasium tienen diferentes versiones. Por ejemplo, hay dos entornos CartPole – CartPole-v1 y CartPole-v0. Aunque el comportamiento del entorno es el mismo en ambas versiones, algunos de los parámetros, como la longitud del episodio, el umbral de recompensa, etc., pueden ser diferentes. Una política entrenada en una versión puede no funcionar tan bien en otra versión del mismo entorno. Necesitas actualizar los parámetros de entrenamiento y volver a entrenar la política para cada versión del entorno. 
  • Desajuste en las versiones de las dependencias: Gymnasium depende de dependencias como NumPy y PyTorch. A partir de diciembre de 2024, las versiones más recientes de estas dependencias son numpy 2.1.3 y torch 2.5.1. Sin embargo, Gymnasium funciona mejor con torch 1.13.0 y numpy 1.23.3. Podrías encontrar problemas si instalas Gymnasium en un entorno con estas dependencias preinstaladas. Recomendamos instalar y trabajar con Gymnasium en un entorno Conda nuevo. 

Problemas de convergencia

  • Hiperparámetros: Al igual que otros algoritmos de aprendizaje automático, las políticas de RL son sensibles a hiperparámetros como la tasa de aprendizaje, el factor de descuento, etc. Recomendamos experimentar y ajustar los hiperparámetros manualmente o utilizando técnicas automatizadas como la búsqueda en cuadrícula y la búsqueda aleatoria.
  • Exploración versus explotación: Para algunas clases de políticas (como PPO), el agente adopta una estrategia de dos puntas: explorar el entorno para descubrir nuevos caminos y adoptar un enfoque codicioso para maximizar las recompensas basado en los caminos conocidos hasta ahora. Si explora demasiado, la política no converge. Por el contrario, nunca intenta el camino óptimo si no explora lo suficiente. Por lo tanto, encontrar el equilibrio adecuado entre exploración y explotación es esencial. También es común priorizar la exploración en episodios más tempranos y la explotación en episodios posteriores durante el entrenamiento.

Estabilidad del entrenamiento

  • Tasas de aprendizaje elevadas: Si la tasa de aprendizaje es demasiado alta, los parámetros de la política experimentan grandes actualizaciones en cada paso. Esto podría llevar potencialmente a perder el conjunto óptimo de valores. Una solución común es decaer gradualmente la tasa de aprendizaje, asegurando actualizaciones más pequeñas y estables a medida que el entrenamiento converge.
  • Exploración excesiva: Demasiada aleatoriedad (entropía) en la selección de acciones evita la convergencia y conduce a grandes variaciones en la función de pérdida entre pasos sucesivos. Para tener un proceso de entrenamiento estable y convergente, equilibra la exploración con la explotación.
  • Elección incorrecta de algoritmo: Algoritmos simples como el gradiente de política pueden llevar a un entrenamiento inestable en entornos complejos con grandes espacios de acción y estado. En tales casos, recomendamos utilizar algoritmos más robustos como PPO y Optimización de Región de Confianza de Política (TRPO). Estos algoritmos evitan grandes actualizaciones de política en cada paso y pueden ser más estables.
  • Aleatoriedad: Los algoritmos de RL son notoriamente sensibles a los estados iniciales y a la aleatoriedad inherente a la selección de acciones. Cuando una ejecución de entrenamiento es inestable, a veces se puede estabilizar utilizando una semilla aleatoria diferente o reinicializando la política.

Conclusión

En este tutorial, exploramos los principios básicos de RL, discutimos Gymnasium como un paquete de software con una API limpia para interactuar con varios entornos de RL, y mostramos cómo escribir un programa en Python para implementar un algoritmo de RL simple y aplicarlo en un entorno de Gymnasium.

Después de comprender los conceptos básicos en este tutorial, recomiendo utilizar entornos de Gymnasium para aplicar los conceptos de RL y resolver problemas prácticos como optimización de rutas de taxis y simulaciones de comercio de acciones.

Source:
https://www.datacamp.com/tutorial/reinforcement-learning-with-gymnasium