Aprendizaje por Refuerzo: Conceptos Fundamentales, Algoritmos y Práctica con PyTorch

Introducción

El Aprendizaje por Refuerzo (Reinforcement Learning, RL) es una rama clave de la inteligencia artificial y el aprendizaje automático, junto con el aprendizaje supervisado y no supervisado. Se inspira en la forma en que los organismos biológicos aprenden comportamientos óptimos mediante la interacción con su entorno. A diferencia del aprendizaje supervisado, RL no requiere conjuntos de datos etiquetados previamente. En su lugar, un agente aprende a través de prueba y error, adaptación y optimización para alcanzar un objetivo específico en un entorno dado.

Componentes centrales del RL

  • Estado (State): Representa la situación actual del entorno o sistema.
  • Acción (Action): Operación que el agente puede realizar en un estado determinado.
  • Recompensa (Reward): Retroalimentación numérica que cuantifica la reacción del entorno tras una acción.
  • Política (Policy): Función de mapeo que guía al agente sobre qué acción tomar en cada estado.

Estos cuatro elementos conforman el Proceso de Decisión de Markov (MDP), el modelo matemático central del RL.

Proceso de Decisión de Markov (MDP)

El MDP modela problemas de decisión mediante una tupla (S, A, R, P):

  • Espacio de estados (S): Conjunto de todos los estados posibles.
  • Espacio de acciones (A): Conjunto de acciones posibles en cada estado.
  • Función de recompensa (R): R(s, a, s') es la recompensa inmediata al pasar de s a s' mediante a.
  • Probabilidad de transición (P): P(s' | s, a) indica la probabilidad de llegar a s' desde s con a.

Estado, Acción, Recompensa y Política

  • Estado: En juegos de mesa, suele ser la posición de las piezas; en conducción autónoma incluye velocidad, ubicación y objetos cercanos.
  • Acción: Por ejemplo, en trading las acciones pueden ser "comprar", "vender" o "mantener".
  • Recompensa: Valora la bondad de una acción. Llegar a un destino da recompensa positiva; chocar contra una pared da recompensa negativa.
  • Política: Mapeo de estado a acción, representado como π(a|s), que devuelve la probabilidad de tomar a en s.

Algoritmos comunes de RL

Iteración de Valor (Value Iteration)

Método de programación dinámica que calcula la política óptima actualizando iterativamente la función de valor. Se usa en problemas MDP con modelo conocido (transiciones y recompensas conocidas). Aplicaciones: planificación de rutas, laberintos.

Q-Learning

Algoritmo de aprendizaje sin modelo que actualiza la función Q (valor de estado-acción) para encontrar la política óptima. No requiere conocer el modelo completo del entorno. Se usa en robótica, sistemas de recomendación y juegos multijugador.

Gradientes de Política (Policy Gradients)

Optimiza directamente los parámetros de la política calculando gradientes en el espacio de políticas. Adecuado para espacios de acción y estado continuos o de alta dimensión. Aplicaciones: procesamiento de lenguaje natural, control de robots.

Actor-Critic

Combina ventajas de métodos basados en valor y gradientes de política. El actor decide acciones y el crítico evalúa dichas decisiones. Logra aprendizaje más rápido y estable. Se usa en conducción autónoma, asignación de recursos y sistemas multiagente.

PPO (Proximal Policy Optimization)

PPO es un algoritmo de gradientes de política conocido por su eficiencia y estabilidad. Pertenece a la familia de optimización de políticas y se utiliza para resolver MDP.

Principio

PPO limita el tamaño del paso de actualización de la política para evitar degradaciones bruscas. Introduce una función objetivo con un término de recorte (clipping):

L(s, a, θ_k, θ) = min( (π_θ(a|s) / π_θ_k(a|s)) * A(s, a), clip(π_θ(a|s) / π_θ_k(a|s), 1-ε, 1+ε) * A(s, a) )

Detalles

  • Estimación de ventaja multietapa: Reduce el error de estimación.
  • Optimizador adaptativo: Normalmente usa Adam.
  • Muestreo paralelo: Mejora la eficinecia de muestra.

Ejemplo de código con PyTorch

import torch
import torch.nn as nn
import torch.optim as optim

class RedPolitica(nn.Module):
    def __init__(self, dim_estado, dim_accion):
        super().__init__()
        self.capa_oculta = nn.Linear(dim_estado, 128)
        self.capa_salida = nn.Linear(128, dim_accion)

    def forward(self, x):
        x = torch.relu(self.capa_oculta(x))
        return torch.softmax(self.capa_salida(x), dim=-1)

dim_estado = 4
dim_accion = 2
red = RedPolitica(dim_estado, dim_accion)
optimizador = optim.Adam(red.parameters(), lr=1e-3)
epsilon = 0.2

# Datos simulados
estados = torch.rand(10, dim_estado)
acciones = torch.randint(0, dim_accion, (10,))
ventajas = torch.rand(10)

with torch.no_grad():
    prob_vieja = red(estados).gather(1, acciones.unsqueeze(-1)).squeeze()

for _ in range(4):
    prob_nueva = red(estados).gather(1, acciones.unsqueeze(-1)).squeeze()
    relacion = prob_nueva / prob_vieja
    objetivo1 = relacion * ventajas
    objetivo2 = torch.clamp(relacion, 1-epsilon, 1+epsilon) * ventajas
    perdida = -torch.min(objetivo1, objetivo2).mean()

    optimizador.zero_grad()
    perdida.backward()
    optimizador.step()

print("Actualización PPO completada.")

Práctica con RL: Implementación paso a paso

Creación del modelo

Instalación de dependencias:

pip install gym torch

Importamos librerías y creamos el entorno CartPole:

import gym
import torch
import torch.nn as nn
import torch.optim as optim

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

Definimos una red neuronal simple para la política:

class RedPoliticaSimple(nn.Module):
    def __init__(self, entrada, salida):
        super().__init__()
        self.capa1 = nn.Linear(entrada, 64)
        self.capa2 = nn.Linear(64, salida)

    def forward(self, estado):
        x = torch.relu(self.capa1(estado))
        return torch.softmax(self.capa2(x), dim=-1)

dim_entrada = entorno.observation_space.shape[0]
dim_salida = entorno.action_space.n
red_pol = RedPoliticaSimple(dim_entrada, dim_salida)
optimizador = optim.Adam(red_pol.parameters(), lr=1e-2)

Evaluación del modelo

Función para evaluar la política en varios episodios:

def evaluar_politica(red, env, episodios=10):
    recompensa_total = 0
    for _ in range(episodios):
        estado = env.reset()
        terminado = False
        recompensa_episodio = 0
        while not terminado:
            estado_tensor = torch.FloatTensor(estado).unsqueeze(0)
            with torch.no_grad():
                probs = red(estado_tensor)
            accion = torch.argmax(probs).item()
            estado, recompensa, terminado, _ = env.step(accion)
            recompensa_episodio += recompensa
        recompensa_total += recompensa_episodio
    return recompensa_total / episodios

recompensa_media = evaluar_politica(red_pol, entorno)
print(f"Recompensa media en 10 episodios: {recompensa_media}")

Despliegue del modelo

Guardado y carga del modelo:

torch.save(red_pol.state_dict(), 'modelo_politica.pth')

red_cargada = RedPoliticaSimple(dim_entrada, dim_salida)
red_cargada.load_state_dict(torch.load('modelo_politica.pth'))

Exportación a ONNX para inferencia rápida:

entrada_ejemplo = torch.randn(1, dim_entrada)
torch.onnx.export(red_pol, entrada_ejemplo, "modelo_politica.onnx")

Etiquetas: PyTorch reinforcement-learning ppo markov-decision-process q-learning

Publicado el 6-14 21:06