Antes de empezar
Varios ejercicios usan las variables y funciones de la teoría: MAPA, FLECHAS, paso, iteracion_de_valor, politica_desde_v, politica_optima, q_learning, codificar, mapas_publicos e imitador. Abre un cuaderno nuevo en Colab, pega y ejecuta en orden los bloques de la ficha Código y después trabaja debajo. Intenta cada ejercicio con lápiz y papel antes de abrir la respuesta.
Ejercicios
1. El retorno a mano
Un robot puede elegir entre dos caminos. El camino A llega en 6 pasos a una meta que da +1. El camino B llega en 3 pasos a una «meta chica» que da +0,5. Las demás recompensas son 0.
a) Con γ = 0,9, ¿cuánto vale el retorno de cada camino? ¿Cuál prefiere el robot?
b) ¿Y con γ = 0,5?
c) Comprueba las cuentas con código.
Respuesta
La recompensa llega en el último paso, así que se multiplica por γ una vez por cada paso de espera: k − 1 veces.
a) Con γ = 0,9: el camino A vale 0,9⁵ · 1 = 0,59049 y el B vale 0,9² · 0,5 = 0,81 · 0,5 = 0,405. Prefiere el A: la meta grande compensa la espera.
b) Con γ = 0,5: el A vale 0,5⁵ = 0,03125 y el B vale 0,5² · 0,5 = 0,125. Ahora prefiere el B. Con un descuento fuerte, el robot es impaciente: un premio chico pronto le gana a uno grande tarde.
for gamma in [0.9, 0.5]:
camino_a = gamma ** 5 * 1
camino_b = gamma ** 2 * 0.5
print(f"γ = {gamma}: A = {camino_a:.5f}, B = {camino_b:.5f}")
γ = 0.9: A = 0.59049, B = 0.40500
γ = 0.5: A = 0.03125, B = 0.12500
2. Una corrección de Q-learning a mano
El robot está en la casilla s y cree que la acción a vale Q(s, a) = 0,2. Da el paso, recibe r = 0 y llega a s′, donde el mejor de sus cuatro Q vale 0,5. Usa α = 0,5 y γ = 0,9.
a) ¿Cuál es el objetivo r + γ · máx Q(s′, ·)? ¿Cuál es la sorpresa? ¿Cuánto vale Q(s, a) después de la corrección?
b) Ahora imagina que, desde la misma casilla con el mismo Q(s, a) = 0,2, el paso cae en una trampa: r = −1 y el episodio termina. ¿Cuánto vale Q(s, a) después?
Respuesta
a) El objetivo es 0 + 0,9 · 0,5 = 0,45. La sorpresa es 0,45 − 0,2 = 0,25: la acción era mejor de lo que creía. Con α = 0,5 se corrige la mitad: 0,2 + 0,5 · 0,25 = 0,325.
b) El episodio terminó, así que no hay futuro: el objetivo es solo r = −1. La sorpresa es −1 − 0,2 = −1,2, y el nuevo valor es 0,2 + 0,5 · (−1,2) = −0,4. Una sola caída basta para que esa acción quede por debajo de las otras.
alfa, gamma, q = 0.5, 0.9, 0.2
objetivo = 0 + gamma * 0.5
print(round(q + alfa * (objetivo - q), 3))
objetivo = -1 # trampa: sin futuro
print(round(q + alfa * (objetivo - q), 3))
0.325
-0.4
3. ¿Qué pasa con γ = 0,5 y con γ = 1?
Corre la iteración de valor sobre MAPA con γ = 0,5 y con γ = 1. Para cada uno, mira el valor del inicio, la acción que elige la política en el inicio y en cuántas de las 40 casillas libres coincide con politica_optima (la de γ = 0,9). Antes de correrlo, predice: ¿cambia el camino con γ = 0,5? ¿Y con γ = 1?
Respuesta
libres = ~np.isin(MAPA, ["#", "M", "T"])
for g in [0.5, 1.0]:
V_g, vueltas_g = iteracion_de_valor(MAPA, gamma=g)
pol_g = politica_desde_v(MAPA, V_g, gamma=g)
iguales = (pol_g == politica_optima)[libres].sum()
print(f"γ = {g}: {vueltas_g} vueltas, V del inicio {V_g[0, 0]:.6f}")
print(f" acción en el inicio {FLECHAS[pol_g[0, 0]]}, "
f"coincide en {iguales} de 40")
γ = 0.5: 18 vueltas, V del inicio 0.000122
acción en el inicio ↓, coincide en 40 de 40
γ = 1.0: 18 vueltas, V del inicio 1.000000
acción en el inicio ↑, coincide en 9 de 40
Con γ = 0,5 el valor del inicio es diminuto, 0,5¹³ ≈ 0,000122, pero la política es la misma en las 40 casillas. En este mapa solo hay recompensa al final y el entorno es determinista: para cualquier γ entre 0 y 1, el mejor plan es el camino más corto, y γ solo cambia cuánto valen las casillas, no el orden entre ellas.
Con γ = 1 todo se rompe. Llegar en 14 pasos o en 1000 da lo mismo, así que toda casilla desde la que se puede llegar vale 1, igual que el inicio. Hasta quedarse quieto vale 1: chocar contra el borde deja al robot en una casilla de valor 1. Las cuatro acciones empatan, argmax elige la primera, ↑, y el robot choca contra el borde para siempre. Solo coincide con la política óptima en 9 casillas. Sin descuento (y sin costo por paso), el robot no tiene ninguna prisa.
4. La tasa de aprendizaje α
Entrena el Q-learning de la teoría con α = 0,05, 0,5 y 1, con todo lo demás igual. Compara la recompensa media de los primeros y de los últimos 100 episodios y el Q del inicio con el valor exacto, 0,254. ¿Cuál aprende más rápido? ¿Por qué α = 1 no causa problemas en este entorno?
Respuesta
for alfa in [0.05, 0.5, 1.0]:
Q_a, rec = q_learning(MAPA, alfa=alfa)
print(f"α = {alfa}: primeros 100 {rec[:100].mean():.2f}, "
f"últimos 100 {rec[-100:].mean():.2f}, "
f"Q del inicio {Q_a[0, 0].max():.3f}")
α = 0.05: primeros 100 -0.24, últimos 100 0.84, Q del inicio 0.225
α = 0.5: primeros 100 -0.24, últimos 100 0.84, Q del inicio 0.254
α = 1.0: primeros 100 -0.24, últimos 100 0.84, Q del inicio 0.254
Sorpresa: las recompensas son las mismas con los tres α. El robot elige sus acciones por cuál Q es el más alto, no por cuánto vale exactamente, y en este mapa ese orden se decide igual con cualquier α: una trampa deja la acción en negativo, una meta la deja en positivo. Donde sí se nota α es en los números. Con α = 0,05, el Q del inicio va en 0,225, todavía lejos del valor exacto 0,254: cada experiencia lo mueve solo un 5 % de la sorpresa. Con α = 0,5 y con α = 1 ya llegó.
α = 1 no causa problemas porque el entorno es determinista: la misma acción da siempre el mismo resultado, así que reemplazar la estimación entera por lo último que se vio no pierde nada. Si el robot resbalara a veces, cada experiencia diría algo distinto y con α = 1 la tabla saltaría de un valor a otro sin asentarse; ahí conviene un α chico, que promedia muchas experiencias.
5. Encuentra el error
Alguien quiere probar el imitador con una sola situación y escribe esto:
mapa, inicio, dist = mapas_publicos[0]
x = torch.tensor(codificar(mapa, inicio))
x = x.permute(1, 2, 0).unsqueeze(0)
print(tuple(x.shape))
print(imitador(x))
(1, 8, 8, 3)
Traceback (most recent call last):
...
RuntimeError: Given groups=1, weight of size [32, 3, 3, 3], expected input[1, 8, 8, 3] to have 3 channels, but got 8 channels instead
¿Qué está mal y cómo se arregla?
Respuesta
permute(1, 2, 0) movió los canales al final: el tensor quedó como (1, 8, 8, 3), la forma de una imagen de matplotlib. nn.Conv2d espera (N, C, H, W), así que leyó 8 canales donde esperaba 3. codificar ya devuelve (3, 8, 8); basta con agregar el eje del lote:
x = torch.tensor(codificar(mapa, inicio)).unsqueeze(0)
print(tuple(x.shape))
with torch.no_grad():
print(FLECHAS[imitador(x).argmax().item()])
(1, 3, 8, 8)
↑
6. El error compuesto en números
Una red imitadora da un paso bueno con probabilidad p, y supón que los pasos son independientes.
a) Con p = 0,95, ¿qué probabilidad tiene de completar sin errores un camino de 10 pasos? ¿Y uno de 20?
b) ¿Qué p hace falta para completar sin errores un camino de 20 pasos el 90 % de las veces?
Respuesta
a) 0,95¹⁰ ≈ 0,599 y 0,95²⁰ ≈ 0,358. Con caminos el doble de largos, la probabilidad casi se reduce a la mitad, aunque la red sea igual de buena en cada paso.
b) Hace falta p²⁰ = 0,9, o sea, p = 0,9 elevado a 1/20 (la raíz vigésima de 0,9), que es más o menos 0,9947: menos de un error cada 190 pasos. Por eso la imitación pura es tan exigente en tareas largas, como manejar.
print(round(0.95 ** 10, 3), round(0.95 ** 20, 3))
p_necesaria = 0.9 ** (1 / 20)
print(round(p_necesaria, 4), round(1 / (1 - p_necesaria)))
0.599 0.358
0.9947 190
7. ¿Refuerzo, imitación o supervisado?
Para cada situación, di qué tipo de aprendizaje usarías y por qué.
a) Un programa aprende a jugar ajedrez jugando millones de partidas contra sí mismo; solo sabe al final si ganó, perdió o empató.
b) Un auto aprende a mantenerse en su carril a partir de horas de video grabado mientras manejaban personas, con el ángulo del volante en cada momento.
c) Un modelo aprende a reconocer prendas en fotos etiquetadas.
d) Imagina un robot de limpieza al que se premia cada vez que su cámara no ve suciedad. ¿Qué podría «aprender» que nadie quería?
Respuesta
a) Refuerzo. No hay un experto que diga la jugada correcta en cada posición; solo una recompensa al final (ganar, perder, empatar), que llega tarde.
b) Imitación (clonación de comportamiento): hay demostraciones de expertos, cada situación con la acción que tomaron. Ojo con el error compuesto: el video solo muestra al auto bien centrado, nunca cómo corregir cuando se desvía, que es justo el problema que DAgger ataca.
c) Supervisado, como en los temas 18 a 20: cada foto tiene su respuesta y no hay acciones ni pasos.
d) Podría aprender a mirar a la pared, a taparse la cámara o a quedarse quieto en un rincón limpio: así su cámara nunca ve suciedad y recibe el premio sin limpiar nada. El agente optimiza lo que se premia, no lo que se quería. Una recompensa mejor premiaría la suciedad recogida.
Mini-proyecto: un robot que mejora con DAgger
Vas a aplicar una ronda de DAgger al imitador de la teoría y a medir si ayuda.
- La línea de base. Anota la tasa de llegada del imitador de la teoría en los mapas públicos y, por grupos de largo, la tasa sin ningún error.
- Mapas nuevos para la ronda. Genera 1000 mapas nuevos con
mapa_al_azary otra semilla (por ejemplo,np.random.default_rng(7)). No uses los mapas públicos ni los ocultos para esto: son para medir. - Que juegue la red. Escribe una versión de
jugarque, además del recorrido, guarde cada situación que visitó la red concodificar(mapa, s). Juega en los 1000 mapas. - Que etiquete el experto. Para cada situación visitada, pide al experto su acción con
experto(dist, s). Ojo: si la red se quedó chocando contra una pared, la misma casilla aparece muchas veces; puedes guardarla una sola vez. - Juntar y reentrenar. Une los ejemplos nuevos con
X_entyy_ent(connp.concatenate), arma un cargador nuevo y entrena una red igual aimitadordesde cero, con la misma semilla y las mismas 10 épocas. - Compara en los mapas públicos. ¿Subió la tasa de llegada? ¿En qué grupo de largo mejoró más? Repite los pasos 3 a 5 una segunda ronda si tienes tiempo, y haz una tabla con las rondas.
- Mide al final. Con la mejor versión, elegida solo con los mapas públicos, mide una sola vez en mapas ocultos. Los de la teoría ya se usaron una vez para medir el imitador original: genera 300 mapas ocultos nuevos con otra semilla, guárdalos sin mirarlos y mide ahí.
- Concluye. Escribe tres conclusiones de una o dos frases: ¿cuánto ayudó DAgger? ¿Qué tipo de mapas siguen siendo difíciles? ¿Cuántas preguntas le hiciste al experto, y cuánto costaría eso si el experto fuera una persona?
Si quieres ir más lejos con el refuerzo: agrega a paso una recompensa de −0,01 en cada paso normal y repite el Q-learning de la teoría con ε = 0. ¿Qué cambia? Pista: con un costo por paso, las acciones ya probadas quedan por debajo de 0 y las que nunca se probaron, en 0, parecen mejores. El robot explora aunque ε sea 0.
Errores comunes
- Olvidar que el episodio terminó. Si el paso cae en la meta o en una trampa, el objetivo es solo r: no hay casilla siguiente de la que sumar γ · máx Q.
- Evaluar con ε. La recompensa durante el entrenamiento incluye los pasos al azar. Para saber qué aprendió el robot, sigue sus flechas sin exploración, como hicimos con
llega_desde. - ε = 0 desde el principio. Sin exploración, el robot repite el primer camino que encontró y no sabe nada del resto del mapa.
- γ = 1 en un problema sin costo por paso. Llegar en 14 pasos o en 1000 da lo mismo, y quedarse quieto vale tanto como avanzar (ejercicio 3).
- Creerle a la recompensa media del final. Una curva de recompensa salta mucho de episodio a episodio: mira la media móvil y prueba con varias semillas antes de concluir.
- Repartir los pasos, no los mapas. Si los pasos de un mismo mapa quedan unos en entrenamiento y otros en validación, la red se evalúa con mapas que ya vio y la cifra sale inflada.
- Medir la imitación solo con la exactitud por paso. Lo que importa es si el robot completa la tarea, y los errores se acumulan con el largo del camino.
- Decidir mirando los mapas ocultos. Se usan una sola vez, al final. Si los miras para elegir, ya no miden nada nuevo.
¿Lo lograste?
Al terminar este tema deberías poder hacer lo siguiente. Al lado, dónde lo practicaste.
- Describir un problema como agente, estados, acciones, recompensa y episodio, y explicar el factor de descuento γ (ejercicios 1 y 7, y el paso 6 de la actividad).
- Programar la iteración de valor y el Q-learning con ε-greedy, y leer la política resultante como flechas (ejercicios 2 y 3, y pasos 1 y 2 de la actividad).
- Explicar el dilema entre explorar y explotar y el efecto de α, γ y ε (ejercicios 3 y 4, y pasos 3 a 5 de la actividad).
- Enseñar a un robot imitando a un experto, con el mapa como tensor (3, 8, 8), y medir su tasa de llegada en mapas nuevos (ejercicio 5 y pasos 1, 5 y 7 del mini-proyecto).
- Reconocer el error que se acumula en la imitación y explicar la idea de DAgger (ejercicios 6 y 7, y pasos 3 a 6 del mini-proyecto).