← Todo el material
Curso Intermedio 24 de agosto de 2026

Razonamiento y RL — Módulo 4: policy gradients y REINFORCE

Cuarto módulo del Curso de Razonamiento y RL: optimizar la política directamente en vez de pasar por los valores. La intuición del gradiente de política, el algoritmo REINFORCE, el truco del log-probabilidad, el problema de la varianza alta y por qué esta familia es la base del RLHF.

☰ Índice del contenido

En el módulo 3 montamos DQN: una red que aprende el valor de cada acción en cada estado y luego elige la de mayor valor. La política —qué hacer— era un subproducto: primero estimabas cuánto vale cada movida, después leías el máximo. Funciona de maravilla cuando las acciones son pocas y discretas (arriba, abajo, izquierda, derecha). Pero ese esquema se rompe apenas el problema crece: si hay miles de acciones posibles, o si la acción es un número continuo (un ángulo, una fuerza), calcular el valor de cada una y tomar el máximo deja de ser viable. Y —lo que a nosotros más nos importa— la “acción” de un LLM es generar una secuencia de tokens: el espacio de acciones es de un tamaño astronómico. Ahí no hay tabla de valores que valga. Este módulo da el giro que va a acompañarnos hasta el final del curso: dejar de estimar valores y ajustar la política directamente.

La tesis del módulo

En vez de estimar cuánto vale cada acción y elegir la mejor, ajusta directamente los parámetros de la política para que suba la probabilidad de las acciones que salieron bien y baje la de las que salieron mal. Ese gradiente —subir la probabilidad de lo que funcionó, ponderado por cuánto funcionó— es, literalmente, el motor del RLHF. Un modelo de lenguaje alineado con refuerzo es policy gradient corriendo sobre secuencias de tokens.

El cambio de mentalidad: value-based vs policy-based

En los métodos value-based (basados en valor: DQN, Q-learning) el objeto que aprendes es una función de valor, y la política sale de ella indirectamente (“elige el máximo”). En los métodos policy-based (basados en política) el objeto que aprendes es la política misma: una función parametrizada π(a|s) que, dado un estado, entrega directamente una distribución de probabilidad sobre las acciones. Los parámetros de esa función —los pesos de una red neuronal— se llaman θ (theta), y por eso la política se escribe π_θ.

La ventaja no es solo elegancia. Una política que entrega probabilidades es estocástica (aleatoria de forma controlada) por diseño: no dice “haz siempre esto”, dice “haz esto con 70% de probabilidad, aquello con 30%”. Eso resuelve de un plumazo dos problemas que en DQN eran incómodos: la exploración (una política estocástica ya explora sola, sin necesidad de trucos como el ε-greedy del módulo 3) y las acciones continuas (una red puede entregar los parámetros de una distribución continua directamente).

La intuición central: subir la log-probabilidad de lo bueno

Antes de una sola fórmula, la idea en palabras. Corres la política y dejas que juegue una partida entera —eso se llama un rollout (una trayectoria completa: estados, acciones y recompensas desde el inicio hasta el final). Cuando termina, miras el resultado. Si a la trayectoria le fue bien (recompensa total alta), quieres que la política sea más probable de repetir las acciones que tomó. Si le fue mal, quieres que sean menos probables. Y no todo por igual: mientras mejor le fue, más fuerte empujas.

Eso es todo el algoritmo, en una frase: empuja hacia arriba la probabilidad de las acciones de las trayectorias buenas, y hacia abajo la de las malas, con una fuerza proporcional a lo buena o mala que fue la recompensa. No necesitas saber cuál era la acción óptima —no la conoces—; solo necesitas que las cosas que salieron bien pesen más la próxima vez.

El teorema del gradiente de política (policy gradient theorem) es la formalización de esa frase. Dice que el gradiente del rendimiento esperado J (cuánta recompensa promedio da la política) respecto a los parámetros θ se puede escribir como una esperanza —un promedio sobre trayectorias— que sabemos estimar con muestras:

∇θ J(θ) = E[ ∇θ log πθ(a|s) · R ]

Léela de derecha a izquierda: R es el retorno (la recompensa de la trayectoria); ∇log π(a|s) es la dirección en el espacio de parámetros que hace más probable la acción a; el producto los combina. Promediado sobre muchas muestras, ese producto apunta exactamente hacia donde hay que mover θ para que las buenas acciones suban. Subes por el gradiente (ascenso de gradiente, porque maximizamos, no minimizamos) y la política mejora.

El log-probability trick: por qué aparece el log

La pregunta natural es de dónde salió ese logaritmo. Queremos derivar una esperanza sobre trayectorias respecto a θ, pero θ está metido en la propia distribución sobre la que promediamos —no puedes meter la derivada dentro de una esperanza cuya distribución depende de θ así como así. El log-probability trick (también llamado score function estimator o truco REINFORCE) es la identidad de cálculo que lo desbloquea:

∇θ πθ = πθ · ∇θ log πθ

Es simplemente la regla de la derivada del logaritmo despejada (∇log f = ∇f / f). Su gracia práctica es doble. Primero, convierte el gradiente de una probabilidad en algo que se puede escribir como una esperanza bajo la propia política —justo lo que muestreamos al hacer rollouts—, así que el gradiente se estima promediando sobre las trayectorias que ya generaste. Segundo, en el código no tienes que derivar nada a mano: pides la log-probabilidad de la acción que tomaste, la multiplicas por el retorno, y dejas que la diferenciación automática de PyTorch calcule ∇log π por ti.

Ojo: el retorno R se trata como una constante dentro del gradiente. No propagas gradiente a través de la recompensa —la recompensa es un número que el entorno te dio, no una función diferenciable de θ. El gradiente fluye solo por log π(a|s). Confundir esto es el error #1 de quien implementa REINFORCE por primera vez: si dejas que R arrastre gradiente, estás optimizando otra cosa.

Otra consecuencia importante del truco: como solo necesitamos poder evaluar log π(a|s) de una acción muestreada, la política puede ser discreta (una distribución categórica sobre acciones, como en un juego) o continua (una gaussiana sobre un valor real, como el ángulo de un volante). El mismo algoritmo cubre ambos casos sin cambiar de forma. DQN no podía hacer eso.

REINFORCE: el algoritmo completo

REINFORCE (Williams, 1992) es el policy gradient más puro: aplica la fórmula de arriba tal cual, con el retorno completo de la trayectoria como ponderación. El bucle tiene tres pasos:

Repetir para cada episodio:
  1. ROLLOUT:  correr la política π_θ hasta terminar el
               episodio, guardando (estado, acción, recompensa)
               de cada paso.
  2. RETORNOS: para cada paso t, calcular el retorno G_t =
               suma de recompensas futuras descontadas por γ.
  3. GRADIENTE: acumular  -Σ_t  log π_θ(a_t | s_t) · G_t
               y dar un paso de ascenso (en código: minimizar
               el negativo, que es un descenso normal).

El retorno descontado G_t es la suma de todas las recompensas desde el paso t hasta el final, cada una multiplicada por γ (gamma, el factor de descuento entre 0 y 1 que hace valer menos las recompensas lejanas —lo vimos en el módulo 2). Se usa G_t y no la recompensa inmediata porque una acción puede tener consecuencias que solo se cobran mucho después.

Ahora un paso de REINFORCE en PyTorch, mínimo pero completo:

import torch
import torch.nn as nn
from torch.distributions import Categorical

class Politica(nn.Module):
    """Red que mapea un estado a una distribución sobre acciones."""
    def __init__(self, dim_estado, n_acciones):
        super().__init__()
        self.red = nn.Sequential(
            nn.Linear(dim_estado, 128), nn.ReLU(),
            nn.Linear(128, n_acciones),
        )

    def forward(self, estado):
        # logits crudos; la distribución los normaliza con softmax
        return self.red(estado)


def muestrear_accion(politica, estado):
    """Muestrea una acción y devuelve también su log-probabilidad,
    que es lo único que necesitamos para el gradiente."""
    logits = politica(estado)
    dist = Categorical(logits=logits)   # distribución categórica
    accion = dist.sample()              # exploración: viene gratis
    return accion.item(), dist.log_prob(accion)


def paso_reinforce(optimizador, log_probs, recompensas, gamma=0.99):
    """Un paso de actualización tras un episodio completo.
    `log_probs`   : lista de log π(a_t|s_t), una por paso (con grad).
    `recompensas` : lista de r_t del episodio."""
    # 1. Retornos descontados G_t, de atrás hacia adelante
    G, retornos = 0.0, []
    for r in reversed(recompensas):
        G = r + gamma * G
        retornos.insert(0, G)
    retornos = torch.tensor(retornos)

    # 2. Normalizar los retornos: baseline barata que baja la varianza
    #    (ver la sección siguiente). NO es opcional en la práctica.
    retornos = (retornos - retornos.mean()) / (retornos.std() + 1e-8)

    # 3. Pérdida = - Σ log π(a_t|s_t) · G_t   (negativo = ascenso)
    #    G_t va SIN gradiente: es un peso escalar, no una variable.
    perdida = torch.stack(
        [-lp * Gt for lp, Gt in zip(log_probs, retornos)]
    ).sum()

    optimizador.zero_grad()
    perdida.backward()      # autograd calcula ∇log π por nosotros
    optimizador.step()
    return perdida.item()

Fíjate en lo poco que hay. No hay red de valor, no hay replay buffer, no hay red objetivo (las tres piezas que DQN necesitaba en el módulo 3). Solo: muestrear con la política, guardar las log-probs, y al final del episodio empujar cada una por su retorno. La Categorical de PyTorch hace el trabajo del .log_prob() y del muestreo; autograd hace el gradiente.

El problema de la varianza

REINFORCE es correcto pero, en su forma pura, ruidoso e ineficiente. La razón es estructural, no un bug: el gradiente se estima con muestras de trayectorias completas, y esas trayectorias son muy variables. Dos partidas de la misma política pueden dar retornos totalmente distintos por pura suerte del muestreo. Como el gradiente es un promedio de pocas muestras muy dispersas, apunta hacia lados distintos cada vez. El entrenamiento avanza a los tumbos y necesita muchísimos episodios.

Hay un problema más fino escondido ahí. REINFORCE atribuye el retorno de toda la trayectoria a cada una de sus acciones. Si jugaste una partida buena, todas las acciones de esa partida suben —incluso las malas que tomaste en el camino, salvadas por las buenas que vinieron después. El algoritmo confía en que, con suficientes muestras, las acciones malas aparecerán también en trayectorias malas y se cancelará el ruido. “Con suficientes muestras” es justamente el problema: suficientes son demasiadas.

Un número lo hace tangible. Imagina un juego donde el retorno de cualquier partida ronda 500, con oscilaciones de ±50 según la suerte. Todos los retornos son grandes y positivos, así que REINFORCE empuja hacia arriba la probabilidad de todas las acciones —las buenas y las mediocres— y solo las distingue por un margen relativo minúsculo (500 contra 520). La señal útil (esta acción fue un poco mejor que aquella) va montada sobre un pedestal enorme de 500 que no dice nada. El gradiente se gasta casi entero empujando el pedestal; la parte que discrimina es ruido comparada con él. Restar una referencia cercana a 500 borra el pedestal y deja solo la diferencia, que es lo único que informa.

La solución es sorprendentemente simple: restarle al retorno una línea base (baseline), una referencia b(s) que no dependa de la acción. Se puede demostrar que restar una baseline no cambia el gradiente en promedio (sigue siendo insesgado) pero sí reduce su varianza. La ponderación deja de ser “qué tan buena fue la trayectoria” y pasa a ser “qué tanto mejor de lo esperado fue esta acción”:

∇θ J = E[ ∇θ log πθ(a|s) · (R − b(s)) ]

La baseline más barata es la que ya usamos en el código: restar la media de los retornos del batch y dividir por su desviación. La baseline buena es estimar b(s) con una red aparte que aprende el valor esperado del estado —y ahí, cuando b(s) se vuelve una función de valor V(s), la cantidad (R − V(s)) tiene nombre propio: ventaja (advantage), cuánto mejor resultó la acción comparada con lo que el estado prometía en promedio.

Cuidado: esa idea —una red de política empujada por la ventaja, y una red de valor que estima la baseline— es exactamente el actor-critic del módulo 5. No es un tema nuevo: es REINFORCE con la baseline convertida en un aprendiz de pleno derecho. Si entendiste por qué la baseline baja la varianza, ya entendiste lo esencial del actor-critic.

Las tres familias, lado a lado

Value-based (DQN)Policy-based (REINFORCE)Actor-critic (mód. 5)
Qué aprendeValor Q(s,a) de cada acciónLa política π(a|s) directaPolítica y valor a la vez
La políticaIndirecta (arg max de Q)Es el objeto que se aprendeEl “actor” es la política
Acciones continuasDifícil (max sobre continuo)Natural (gaussiana)Natural
ExploraciónTruco externo (ε-greedy)Viene sola (es estocástica)Viene sola
Varianza / muestrasBaja varianza, más estableVarianza alta, ineficienteVarianza controlada
SesgoSesgado (bootstrap)InsesgadoCompromiso sesgo/varianza

Léela como una escalera. DQN es estable pero rígido con las acciones. REINFORCE es flexible pero ruidoso. Actor-critic toma lo mejor de ambos: la flexibilidad de la política y la estabilidad de tener un crítico que reduce la varianza. Por eso el curso va en este orden.

Por qué esto ES el RLHF de un LLM

Aquí está el motivo por el que dejamos DQN atrás. Traduce el vocabulario de RL al de un modelo de lenguaje y no cambia nada:

  • La política π_θ es el modelo de lenguaje. Sus parámetros θ son los pesos del modelo.
  • El estado es el prompt más los tokens generados hasta ahora.
  • La acción es el siguiente token (o, mirando la trayectoria entera, la respuesta completa).
  • La trayectoria es la generación completa: del prompt a la respuesta.
  • La recompensa no viene de un entorno de juego: la da un modelo de recompensa (reward model, una red entrenada con comparaciones humanas para puntuar qué tan buena es una respuesta) o un verificador (un chequeo automático: ¿el código compila?, ¿la respuesta matemática es correcta?).

Con ese diccionario, entrenar un LLM con RLHF es un policy gradient sobre secuencias. Generas respuestas (rollout), un modelo de recompensa las puntúa (recompensa), y subes la log-probabilidad de los tokens de las respuestas bien puntuadas y bajas la de las mal puntuadas —exactamente la fórmula ∇log π · (R − baseline) de este módulo, con la respuesta como acción y el reward model como entorno. El algoritmo que usa la industria en la práctica, PPO, es una versión cuidada de este policy gradient con salvaguardas para que la política no se aleje demasiado de una actualización a la otra; lo veremos en el módulo 5, y el RLHF completo en el módulo 6. Pero el corazón —el motor— es lo que acabas de ver.

Por eso este módulo es la bisagra del curso. Todo lo anterior (bandidos, MDPs, Q-learning) construyó la intuición; de aquí en adelante, cada pieza que agreguemos es para que este mismo gradiente funcione a la escala de un modelo de lenguaje.

El bucle de policy gradient

        ┌──────────────────────────────┐
        │ politica pi (la red)         │
        └───────────────┬──────────────┘
                        │ muestrear
                        ▼
        ┌──────────────────────────────┐
        │ trayectorias (rollouts):     │
        │ estados, acciones, final     │
        └───────────────┬──────────────┘
                        │ el entorno o el reward
                        │ model puntua
                        ▼
        ┌──────────────────────────────┐
        │ recompensa R (o la ventaja   │
        │ R menos la baseline)         │
        └───────────────┬──────────────┘
                        │ gradiente de log-prob
                        │ por (R - baseline)
                        ▼
        ┌──────────────────────────────┐
        │ paso de ascenso: subir la    │
        │ prob de lo bueno, bajar la   │
        │ de lo malo                   │
        └───────────────┬──────────────┘
                        │ theta actualizado
                        └──────────────► vuelve
                          arriba con la red mejor

El ciclo es el mismo trate de un robot que aprende a caminar o de un LLM que aprende a responder mejor: muestrear con la política, dejar que el mundo (o el reward model) puntúe, y empujar los parámetros hacia lo que salió bien. Cambia quién da la recompensa; el motor no cambia.

Errores comunes

  • Dejar que el retorno arrastre gradiente. R (o la ventaja) es un peso escalar constante dentro del gradiente. Si en el código no lo separas del grafo de autograd, estás optimizando una cantidad equivocada. En PyTorch: el retorno va como tensor sin requires_grad, y el gradiente fluye solo por log_prob.
  • Olvidar el signo negativo. Queremos maximizar el rendimiento (ascenso de gradiente), pero los optimizadores minimizan. La pérdida es -log π · R. Sin el menos, tu política aprende a hacer lo peor posible, sistemáticamente.
  • Correr REINFORCE puro sin baseline y frustrarse. Sin baseline la varianza es tan alta que parece que no aprende. Normalizar los retornos del batch es una línea de código y cambia el resultado por completo. No es un lujo.
  • Confundir la política estocástica con una debilidad. El muestreo no es imprecisión que haya que quitar: es la exploración. Colapsar demasiado pronto a una política casi determinista mata el aprendizaje. La entropía de la política es algo que se cuida, no que se elimina.
  • Reutilizar trayectorias viejas como si nada. REINFORCE es on-policy: el gradiente asume que las trayectorias vienen de la política actual. En cuanto actualizas θ, los rollouts anteriores dejan de ser válidos sin corrección. (El manejo correcto de eso es, otra vez, parte de lo que PPO agrega.)
  • Esperar la eficiencia de datos de DQN. Policy gradient puro gasta muchas más muestras que un método value-based con replay buffer. Esa es la moneda de cambio por la flexibilidad; la baseline y el actor-critic recuperan parte, pero no la borran.

La frase para llevarse

“DQN pregunta cuánto vale cada acción; policy gradient pregunta qué tan probable la hago la próxima vez. Ese segundo verbo —hacer más probable lo que funcionó— es el mismo que usa un LLM cuando aprende a responder mejor. Aprender la política directamente no es una técnica más: es el puente entre los juegos y el lenguaje.”

Qué viene

Módulo 5: actor-critic y PPO. Ya viste que la baseline baja la varianza y que, cuando la baseline se vuelve una red que estima el valor del estado, aparece la ventaja. El siguiente módulo convierte esa baseline en un aprendiz de pleno derecho —el crítico— que corre en paralelo al actor (la política). Y sobre esa base montamos PPO (Proximal Policy Optimization), el algoritmo que hace estable el policy gradient limitando cuánto puede cambiar la política en cada paso: el que de verdad se usa para alinear modelos de lenguaje. Con eso en la mano, el módulo 6 abre el RLHF por dentro y verás que no hay magia nueva, solo estas piezas ensambladas a escala.

Material relacionado

Aprendizaje por refuerzoPolicy GradientREINFORCERLHFRL

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.