Saltar al contenido

# aprendizaje-por-refuerzo-en-python

Aprendizaje por Refuerzo en Python

Volver a la portada del curso
Notebook

Notebook: Ejemplo Completo

Sección 5 · Proyecto Aplicado

Notebook: el robot del almacén, de principio a fin

Este notebook junta todo el curso en un solo recorrido: el robot del almacén de PyShop empieza moviéndose al azar y termina con una política que llega siempre al andén por la ruta más corta. Esta guía acompaña al notebook robot-del-almacen: explica cómo abrirlo, qué hace cada sección, qué números debes obtener y qué conviene observar. También es la solución de referencia del proyecto final, así que te conviene dominarlo antes de empezar el tuyo.

Cómo abrirlo

Instala las dependencias en tu entorno virtual con pip install gymnasium numpy matplotlib y abre el notebook en Jupyter, VS Code o Google Colab. El curso usa Gymnasium 1.4.0 y NumPy 2.4.6. Todo es determinista (semillas fijas) y rápido: entrenar 500 episodios en el almacén tarda menos de un segundo, así que puedes volver a correr las celdas cuantas veces quieras.

1. Funciones del curso y línea base

La primera celda copia los datos del curso: el entorno AlmacenPyShop (5×5, −1 por paso, +10 en el andén, −10 en un derrame, 50 pasos como máximo) y las funciones elegir_accion, evaluar y mapa_politica. Luego mide al robot aleatorio: retorno medio de −31.87 en 1000 episodios. Ese número es el piso: cualquier agente que aprenda tiene que superarlo.

2. La regla de Q-learning a mano

Q-learning ajusta un valor de la tabla después de cada paso:

$$Q(s, a) \leftarrow Q(s, a) + \alpha\,\big[r + \gamma \max_{a'} Q(s', a') - Q(s, a)\big]$$

El notebook hace una actualización con números: si $Q(s, a) = 0$, $r = -1$, el mejor valor del estado siguiente es 2, $\alpha = 0.1$ y $\gamma = 0.95$, el nuevo valor es $0 + 0.1 \times (-1 + 0.95 \times 2 - 0) = 0.09$. La tasa de aprendizaje $\alpha$ decide cuánto se mueve el valor hacia el objetivo en cada paso.

3. La clase Agente

class Agente:
    def __init__(self, n_estados, n_acciones, alfa=0.1, gamma=0.95, seed=42):
        self.Q = np.zeros((n_estados, n_acciones))
        self.alfa, self.gamma = alfa, gamma
        self.rng = np.random.default_rng(seed)

    def actuar(self, estado, epsilon):
        return elegir_accion(self.Q, estado, epsilon, self.rng)

    def aprender(self, s, a, r, s2, terminado):
        objetivo = r + (0 if terminado else self.gamma * self.Q[s2].max())
        self.Q[s, a] += self.alfa * (objetivo - self.Q[s, a])

actuar aplica ε-greedy sobre la tabla; aprender aplica la regla anterior. Fíjate en el 0 if terminado: al llegar al andén o a un derrame no hay futuro que sumar. Un corte por tiempo (truncated) sí conserva el valor futuro.

4. Entrenar 500 episodios

El bucle de entrenamiento reinicia el entorno, deja que el agente actúe y aprenda paso a paso, y baja ε de 1 a 0.05 multiplicándolo por 0.99 después de cada episodio. La curva de retornos suavizada sube así:

EpisodiosRetorno medio
1-50−26.88
51-100−9.86
101-200−0.02
201-3001.98
451-5002.54

El primer episodio con la ruta óptima (retorno 3) es el 101. Al final la media no llega a 3 porque el agente todavía explora un 5 % de las veces.

5. La política en flechas y la evaluación

mapa_politica dibuja la mejor acción de cada casilla:

→ → ↓ ← ↓
↓ E ↓ D ↓
↓ E ↓ → ↓
→ → ↓ E ↓
D → → → A

Evaluada sin explorar durante 100 episodios, la política obtiene retorno 3.0 y 100 % de éxito. En la salida, Q[0] vale [−1.777, −3.528, 0.95, −1.825]: la mejor acción es derecha. Observa la flecha ← de la casilla (0, 3): es una casilla que el robot casi nunca visita, y la tabla solo es buena donde hubo experiencia.

6. Mapa de calor de V(s)

El valor de cada estado es su mejor valor de acción, $V(s) = \max_a Q(s, a)$; en la salida vale 0.95. El notebook lo dibuja con Matplotlib como una cuadrícula de 5×5. A lo largo de la ruta aprendida el valor crece paso a paso, de 0.95 en la salida a 10 en la casilla que está junto al andén (el último paso solo cobra el +10). Las casillas poco visitadas de arriba a la derecha quedan con valores bajos o negativos, y los estantes, derrames y el andén se quedan en 0 porque el agente nunca actúa desde ellos.

7. Experimento con α y γ

Retorno medio de los últimos 50 episodios con distintos hiperparámetros (los demás fijos):

  • $\gamma$ 0.5 → 2.60; 0.95 → 2.54; 0.99 → 2.62. Los tres resuelven el almacén con 100 % de éxito.
  • $\alpha$ 0.01 → −1.18, y la política greedy no llega nunca (retorno −50, 0 %): aprende demasiado lento para 500 episodios. $\alpha$ 0.1 → 2.54; $\alpha$ 0.5 → 2.18, ambos con 100 %.

8. El almacén resbaloso

Con crear_almacen(resbaloso=0.1), el 10 % de las veces el robot se desliza a un lado. Hace falta más práctica: 2000 episodios con decaimiento 0.998. La evaluación da retorno 1.04 y 93 % de éxito. Ya no se puede ganar siempre: un resbalón cerca de un derrame puede acabar mal.

9. El mismo agente en Taxi-v4

La clase no sabe nada del almacén: solo necesita el número de estados y de acciones. En Taxi-v4 (500 estados, 6 acciones), con 3000 episodios, los últimos 100 dan 4.98 de media y la evaluación, retorno 7.63 con 100 % de éxito.

10. Guardar y cargar la tabla

np.save("q_almacen.npy", agente.Q) guarda la tabla de 25 × 4 y np.load la recupera; el notebook comprueba que la política cargada da la misma evaluación.

Qué debes obtener

−31.87 al azar; 0.09 en la actualización a mano; −26.88 → 2.54 en la curva y primer óptimo en el episodio 101; 3.0 y 100 % en la evaluación; 93 % en el almacén resbaloso; 7.63 y 100 % en Taxi-v4. Los ejercicios con assert del final verifican estas cifras. Si alguna no coincide, revisa que reset reciba la semilla de cada episodio y que el agente se cree con seed=42.

Recursos