← Todo el material
Curso Intermedio 24 de agosto de 2026

Razonamiento y RL — Módulo 3: de Q-learning a Deep RL

Tercer módulo del Curso de Razonamiento y RL: cómo se aprende cuando no conoces el entorno y los estados son incontables. Q-learning tabular, por qué la tabla no escala, la red neuronal como aproximador de la función de valor, y las ideas que hicieron funcionar a DQN: experience replay y target network.

☰ Índice del contenido

En el módulo 2 resolvimos un MDP conocido: teníamos el mapa completo del entorno —las probabilidades de transición y las recompensas de cada estado— y con eso, aplicando la ecuación de Bellman una y otra vez, calculábamos el valor de cada estado y la política óptima. Era, en el fondo, un problema de aritmética: sabíamos todo y solo faltaba hacer las cuentas. Este módulo tira ese lujo a la basura. En el mundo real no conoces el entorno: no sabes qué pasa si aprietas ese botón hasta que lo aprietas, no tienes la tabla de probabilidades de un videojuego ni de un robot ni de un cliente. Solo puedes hacer una cosa: actuar, ver qué pasa, y aprender de lo que pasó. Eso es aprender por refuerzo de verdad, y el primer algoritmo que lo hace bien se llama Q-learning.

La tesis del módulo

El Q-learning aprende el valor de las acciones probando y ajustando por el error entre lo que esperaba y lo que pasó; cuando los estados son demasiados para una tabla, una red neuronal la reemplaza — eso, y no más, es “deep RL”. Todo lo demás (Atari, AlphaGo, los titulares) son consecuencias de esa única sustitución: cambiar una tabla de números por una red que la aproxima.

Aprender de una estimación con otra estimación

La idea central que separa el Q-learning del módulo anterior tiene nombre: aprendizaje por diferencia temporal (Temporal Difference, TD — actualizar una estimación usando otra estimación en lugar de esperar el resultado final). Suena abstracto, pero es lo que hace cualquiera que aprende sin manual.

Imagina que estás aprendiendo a estimar cuánto tardas en llegar al trabajo. Sales de casa creyendo que faltan 30 minutos. A los 10 minutos llegas a la autopista y la ves colapsada; en ese instante, sin haber llegado todavía, ya corriges tu estimación a 45 minutos. No esperaste a llegar para aprender: usaste una observación intermedia (la autopista mala) más tu nueva estimación (los 35 minutos que faltan) para ajustar la vieja. Eso es TD, y ese ajuste tiene nombre: el error TD (TD error — la diferencia entre lo que esperabas y lo que la nueva evidencia sugiere). Es la señal de aprendizaje de todo el método.

El contraste es con Monte Carlo (esperar hasta el final del episodio y recién ahí usar el resultado real total para actualizar). Monte Carlo es honesto pero lento: no aprendes nada hasta que la partida termina. En muchos problemas el episodio dura miles de pasos, o no termina nunca. TD aprende en cada paso, aprovechando que una estimación imperfecta de ahora es mejor que ninguna información hasta el final.

Monte CarloDiferencia temporal (TD)
Cuándo actualizaAl final del episodioEn cada paso
Qué usa como objetivoRetorno real total observadoRecompensa + valor estimado del siguiente estado
SesgoInsesgado (usa el retorno real)Sesgado (arrastra el error de su propia estimación)
VarianzaAlta (suma muchos pasos aleatorios)Baja (un solo paso de azar)
Episodios infinitosNo sirveFunciona

Ojo: el bootstrapping (aprender de tu propia estimación) es a la vez la fuerza y el peligro del TD. Si tu estimación del siguiente estado está muy mala, la propagas hacia atrás y contaminas todo. Que esto no explote es justo lo que las ideas de DQN, más abajo, se encargan de proteger.

Q-learning tabular: la regla, en palabras

El Q-learning aprende la función Q (action-value function — cuánto vale, a largo plazo, tomar la acción a estando en el estado s). En la versión tabular es literalmente una tabla: una casilla por cada combinación de estado y acción. Empiezas con la tabla en cero (no sabes nada) y la vas corrigiendo con esta regla, que es TD puro:

Q(s,a) ← Q(s,a) + α · [ r + γ · max Q(s',·) − Q(s,a) ]

           el corchete [ ... ] es el ERROR TD:
           lo nuevo que crees  −  lo que creías

Léela de derecha a izquierda dentro del corchete:

  • Q(s,a) es lo que creías que valía esa acción.
  • r + γ · max Q(s',·) es lo que ahora crees que vale, después de actuar: la recompensa r que de verdad recibiste, más el mejor valor posible del estado al que llegaste s', descontado por γ (gamma, el factor de descuento del módulo 2: cuánto pesa el futuro).
  • La resta de ambos es el error TD: cuánto te equivocaste.
  • α (alpha, el learning rate o tasa de aprendizaje) decide cuánto de esa corrección te crees. Con α chico avanzas de a poco y estable; con α grande avanzas rápido pero das tumbos.

Un ejemplo minúsculo. Un pasillo de tres casillas, la meta a la derecha da recompensa 1, γ = 0.9, α = 0.5. Estás en la casilla del medio, tu tabla dice Q(medio, derecha) = 0 (no sabes nada aún). Actúas: te mueves a la meta y recibes r = 1. La meta es terminal, así que max Q(s',·) = 0. El error TD es 1 + 0.9·0 − 0 = 1. Actualizas: Q(medio, derecha) ← 0 + 0.5·1 = 0.5. La próxima vez que pases por ahí, esa casilla ya “sabe” que ir a la derecha vale algo. Repite miles de veces y la tabla converge al valor real.

Un detalle que importa mucho: el Q-learning es off-policy (fuera de política — aprende el valor de la política óptima aunque durante el entrenamiento actúes de otra forma, por ejemplo explorando al azar). El max de la fórmula es la clave: al actualizar, siempre asume que en el siguiente estado tomarás la mejor acción, sin importar qué acción vayas a tomar de verdad para seguir explorando. Eso te deja explorar con libertad (probar acciones malas a propósito para descubrir el mapa) sin ensuciar lo que aprendes sobre la política óptima.

El muro: cuando la tabla es imposible

La tabla funciona mientras puedas listar los estados. En el pasillo de tres casillas hay tres estados; en el ajedrez hay más estados que átomos en el universo; en un videojuego de Atari el estado es la pantalla —una imagen de 210×160 píxeles a color—, y no hay dos partidas que muestren exactamente la misma imagen. No existe la tabla. No cabe, y aunque cupiera, nunca visitarías dos veces la misma casilla para aprender de ella.

Aquí entra la aproximación de funciones (function approximation — en vez de guardar un valor por estado, aprender una función que, dado cualquier estado, estime su valor). Y la máquina que estima funciones a partir de ejemplos, ajustándose por gradiente, ya la conoces: es la red neuronal del Curso de Redes. En vez de una casilla Q(s,a), una red toma el estado s (los píxeles) por la entrada y devuelve por la salida un valor Q por cada acción posible. Estados parecidos producen valores parecidos, y eso es exactamente lo que la tabla no podía hacer: generalizar a estados nunca vistos.

El error TD deja de ser un ajuste aritmético de una casilla y pasa a ser una función de pérdida (loss): la red se entrena para que su predicción Q(s,a) se acerque al objetivo r + γ·max Q(s',·), exactamente con el descenso de gradiente y el backpropagation que ya estudiaste. Ese es todo el salto conceptual. Deep RL es Q-learning con una red en lugar de la tabla.

DQN: dos ideas para que no explote

Aquí viene la trampa. Si tomas el Q-learning tabular y reemplazas la tabla por una red así de directo, no funciona: el entrenamiento oscila, diverge, la pérdida se va al infinito. En 2013–2015 el equipo de DeepMind (el paper de DQN, Deep Q-Network, el que aprendió a jugar decenas de juegos de Atari desde los píxeles) mostró que hacían falta dos parches para estabilizarlo. No son opcionales: son la razón por la que DQN funciona y el intento ingenuo no.

Idea 1 — Experience replay (repetición de experiencia). Un agente vive experiencias en orden: paso 1, paso 2, paso 3… y esos pasos consecutivos están fuertemente correlacionados (tres cuadros seguidos de un juego son casi idénticos). Entrenar una red con datos tan correlacionados y que además llegan en orden es veneno: la red se sobreajusta a lo que está viviendo ahora y olvida lo de antes. La solución es un replay buffer (una memoria circular donde se guarda cada transición (s, a, r, s')). Para entrenar, en vez de usar el último paso, se saca un minibatch al azar del buffer. Muestrear al azar rompe la correlación temporal y hace que cada actualización vea una mezcla variada de experiencias viejas y nuevas, como pide el entrenamiento supervisado.

Idea 2 — Target network (red objetivo). Vuelve a mirar la pérdida: entrenas la red para acercar Q(s,a) al objetivo r + γ·max Q(s',·). Pero ese objetivo también se calcula con la red. Entonces, cada vez que ajustas la red para acercarte al objetivo, el objetivo se mueve, porque depende de la misma red que acabas de cambiar. Es perseguir tu propia sombra: apuntas a un blanco que se corre justo cuando disparas. La solución es tener dos copias de la red: la red que entrenas (Q) y una copia congelada (la target network) que solo se usa para calcular el objetivo. La copia se mantiene fija durante muchos pasos y solo de vez en cuando se actualiza con los pesos de la red entrenada. Así el blanco se queda quieto el tiempo suficiente para que la red apunte bien.

ProblemaPor qué rompeIdea de DQN
Pasos consecutivos correlacionadosLa red se sobreajusta al presente y olvidaExperience replay: minibatch al azar del buffer
El objetivo depende de la red que se entrenaPersigues un blanco móvil, divergeTarget network: copia congelada para el objetivo

Un paso de entrenamiento de DQN

Esbozo mínimo pero realista en PyTorch. Es un solo paso de optimización: se asume que ya tienes un minibatch sacado del replay buffer. Las APIs (gather, max, torch.no_grad, mse_loss) son las estándar de la documentación oficial de PyTorch.

import torch
import torch.nn as nn
import torch.nn.functional as F

class RedQ(nn.Module):
    """Estima Q(s, ·): entra el estado, salen n_acciones valores Q."""
    def __init__(self, dim_estado: int, n_acciones: int):
        super().__init__()
        self.net = nn.Sequential(
            nn.Linear(dim_estado, 128), nn.ReLU(),
            nn.Linear(128, n_acciones),   # un valor Q por acción
        )

    def forward(self, s):
        return self.net(s)                # shape: (batch, n_acciones)


def paso_entrenamiento(q_red, target_red, optimizador, batch, gamma=0.99):
    # batch: tensores ya apilados de un minibatch del replay buffer
    s, a, r, s_sig, terminado = batch     # a: acciones (batch, 1) enteros

    # 1) Q(s,a) que la red PREDICE para la acción que se tomó.
    #    gather(1, a) elige, de los n valores por fila, el de la acción a.
    q_pred = q_red(s).gather(1, a).squeeze(1)          # (batch,)

    # 2) Objetivo TD con la TARGET NETWORK (copia congelada).
    #    no_grad: el objetivo NO propaga gradiente, es el "blanco fijo".
    with torch.no_grad():
        q_sig = target_red(s_sig).max(1).values        # max Q(s',·)
        objetivo = r + gamma * q_sig * (1 - terminado)  # 0 si terminó

    # 3) Pérdida = error TD al cuadrado (MSE). Ajusta q_pred hacia objetivo.
    perdida = F.mse_loss(q_pred, objetivo)

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


# La target network se sincroniza CADA N pasos, no en cada uno:
def sincronizar(q_red, target_red):
    target_red.load_state_dict(q_red.state_dict())

Tres líneas cargan toda la teoría del módulo. La 1) es la predicción; la 2), envuelta en torch.no_grad() y usando target_red, es el objetivo que no se mueve; la 3) es el error TD convertido en pérdida. El (1 - terminado) implementa lo que vimos en el ejemplo del pasillo: si el estado siguiente es terminal, no hay futuro que sumar, el objetivo es solo r.

El bucle completo de DQN


      ┌────────────┐  acción a   ┌────────────┐
      │   AGENTE   │ ──────────► │  ENTORNO   │
   ┌─► │  (red Q)   │             │            │
   │   └────────────┘             └──────┬─────┘
   │         s, r, s' y a                │ guarda
   │                                     ▼
   │                   ┌───────────────────────┐
   │                   │     REPLAY BUFFER     │
   │                   │     (s, a, r, s')     │
   │                   └───────────┬───────────┘
   │                               │ minibatch al azar
   │                               ▼
   │                   ┌───────────────────────┐
   │                   │    PASO DE ENTREN.    │
   │                   │    red Q  predice     │
   │                   │    target  da blanco  │
   │                   └───────────┬───────────┘
   │                               │ pérdida MSE
   │                               ▼
   │                   ┌───────────────────────┐
   │  target network:  │   ACTUALIZAR red Q    │
   └── cada N pasos ───┤                       │
                       └───────────────────────┘

El diagrama muestra las dos ideas trabajando juntas: la experiencia no va directa de entorno a red, pasa por el buffer (idea 1), y la red que da el blanco es una copia que solo se refresca cada N pasos (idea 2). Sin esos dos rodeos, la flecha de “actualizar” empujaría a la red a perseguirse a sí misma.

El límite: DQN no sirve para todo

DQN tiene dos supuestos incrustados en su diseño. Primero, acciones discretas: la red da un valor Q por acción y toma el max sobre ellas. Si las acciones son continuas —el ángulo de un volante, la fuerza de un motor, que puede ser cualquier número real— no hay un conjunto finito sobre el cual hacer max. Segundo, DQN aprende valores y de ahí deriva la política (elige la acción de mayor Q); nunca optimiza la política directamente.

Para acciones continuas, o cuando quieres ajustar la política de frente en vez de pasar por los valores, hace falta otra familia entera de métodos: los policy gradients, que son el módulo 4.

Value-based (DQN)Policy-based (policy gradients)
Qué aprendeLa función de valor Q(s,a)La política `π(a
Cómo elige la acciónargmax de los valores QMuestrea de la distribución que da la red
Acciones continuasNo (necesita max finito)Sí, natural
EstabilidadBuena con replay + targetMás ruidosa (alta varianza)
Ejemplo típicoAtari, juegos discretosRobótica, control continuo, RLHF

Errores comunes

  • Actualizar la target network en cada paso. Si la copia “congelada” se refresca a cada rato, deja de estar congelada y vuelves a perseguir el blanco móvil. Se sincroniza cada N pasos (miles, típicamente), a propósito.
  • Entrenar con los pasos en orden, sin buffer. Sin experience replay, la red ve datos correlacionados y en secuencia; se sobreajusta al presente y el entrenamiento diverge. El buffer y el muestreo al azar no son un truco de eficiencia, son estructurales.
  • Dejar que el gradiente fluya por el objetivo. Si olvidas el torch.no_grad() (o el .detach()) al calcular el blanco, la red aprende a mover el objetivo hacia su predicción en vez de al revés. El entrenamiento colapsa a soluciones triviales.
  • Confundir “deep RL” con un algoritmo nuevo. No lo es. Es Q-learning (o su primo policy-gradient) con una red como aproximador. Quien entiende el TD tabular entiende lo esencial de DQN.
  • Usar DQN para acciones continuas. El max sobre las acciones no existe si las acciones son un número real. Ese es el trabajo del módulo 4, no de este.
  • α (learning rate) demasiado grande. Con la tabla da tumbos; con la red, sumado al bootstrapping y al blanco móvil, es una de las causas más comunes de divergencia. En deep RL se usan learning rates chicos.

La frase para llevarse

“Deep RL no es magia nueva: es la misma regla de ‘ajusta por el error entre lo que esperabas y lo que pasó’, con una red neuronal donde antes había una tabla. Todo el ingenio de DQN es evitar que esa red persiga su propia sombra.”

Qué viene

Módulo 4: policy gradients. DQN aprende valores y de ahí saca la política; ahora vamos a hacer lo contrario —optimizar la política directamente, sin pasar por la función Q—. Es lo que hace falta cuando las acciones son continuas y, más importante para este curso, es la familia de la que sale el algoritmo que ajusta modelos de lenguaje por refuerzo. Veremos por qué derivar sobre una política estocástica tiene truco, qué es el “truco del reforzamiento” que lo hace posible, y por qué esta rama, más ruidosa que DQN, es la que terminó dominando el RL moderno de LLMs.

Material relacionado

Aprendizaje por refuerzoQ-learningDQNDeep RLRedes neuronales

Preguntas sobre este curso

Regístrate gratis para hacer preguntas y guardar tu progreso.

✉ Entérate de lo nuevo

Recibe un aviso cuando publique nuevos cursos, workshops o investigaciones. Sin spam.