Saltar al contenido
← AI Alignment: de RLHF a la interpretabilidad

Lección 13 de 16 · Lecturas complementarias · 25 min

DPO: tu modelo de lenguaje es secretamente un reward model

Derivamos paso a paso la pérdida de Direct Preference Optimization desde el objetivo de RL con KL, y la implementamos en PyTorch.


La pregunta

En la lección anterior vimos que RLHF hace dos cosas: ajusta un reward model con Bradley-Terry y después optimiza una política con PPO bajo una restricción KL. Rafailov et al. (2023) se preguntaron: si el objetivo de RL con KL tiene solución cerrada, ¿podemos usar esa solución para escribir la pérdida de preferencias directamente en términos de la política, sin reward model explícito y sin RL?

La respuesta es sí, y el resultado se llama DPO (Direct Preference Optimization).

Paso 1: el objetivo de RL restringido por KL

Partimos del mismo objetivo que RLHF, para un prompt xx fijo:

max⁡π  Ey∼π(⋅∣x)[r(x,y)]−β DKL(π(⋅∣x) ∥ πref(⋅∣x))\max_{\pi} \; \mathbb{E}_{y \sim \pi(\cdot \mid x)}\big[ r(x, y) \big] - \beta \, D_{\text{KL}}\big( \pi(\cdot \mid x) \,\|\, \pi_{\text{ref}}(\cdot \mid x) \big)

elegir el modelo π\pi que, para el prompt xx, dé respuestas yy con la mayor recompensa rr en promedio, sin alejarse demasiado del modelo de referencia πref\pi_{\text{ref}}. La KL mide ese alejamiento y β\beta dice cuánto pesa

Paso 2: la solución cerrada

Expandimos la KL y reorganizamos. Maximizar lo anterior equivale a minimizar:

Ey∼π[log⁡π(y∣x)πref(y∣x)−1βr(x,y)]=Ey∼π[log⁡π(y∣x)πref(y∣x)exp⁡ ⁣(1βr(x,y))]\mathbb{E}_{y \sim \pi}\left[ \log \frac{\pi(y \mid x)}{\pi_{\text{ref}}(y \mid x)} - \frac{1}{\beta} r(x, y) \right] = \mathbb{E}_{y \sim \pi}\left[ \log \frac{\pi(y \mid x)}{\pi_{\text{ref}}(y \mid x)\exp\!\big(\tfrac{1}{\beta} r(x, y)\big)} \right]

lo mismo, reescrito: el cociente mide cuánto más probable hace π\pi una respuesta que la referencia, y le restamos la recompensa. La segunda línea junta los dos términos en un solo logaritmo

Definimos la función de partición Z(x)=∑yπref(y∣x)exp⁡ ⁣(1βr(x,y))Z(x) = \sum_y \pi_{\text{ref}}(y \mid x) \exp\!\big(\tfrac{1}{\beta} r(x, y)\big) y la distribución normalizada:

π∗(y∣x)=1Z(x) πref(y∣x)exp⁡ ⁣(1βr(x,y))\pi^*(y \mid x) = \frac{1}{Z(x)} \, \pi_{\text{ref}}(y \mid x) \exp\!\left(\frac{1}{\beta} r(x, y)\right)

la mejor política: tomar la referencia y multiplicar cada respuesta por exp⁡(r/β)\exp(r/\beta), más peso a las que tienen más recompensa. Dividir por Z(x)Z(x) solo hace que todo sume 1

Sustituyendo, la expresión a minimizar queda:

Ey∼π[log⁡π(y∣x)π∗(y∣x)]−log⁡Z(x)=DKL(π ∥ π∗)−log⁡Z(x)\mathbb{E}_{y \sim \pi}\left[ \log \frac{\pi(y \mid x)}{\pi^*(y \mid x)} \right] - \log Z(x) = D_{\text{KL}}\big(\pi \,\|\, \pi^*\big) - \log Z(x)

minimizar esto es acercar π\pi a π∗\pi^* (la KL mide cuán distintas son); log⁡Z(x)\log Z(x) no depende de π\pi, así que no cambia cuál es la mejor

Como Z(x)Z(x) no depende de π\pi, y la KL es mínima (cero) cuando las distribuciones coinciden, la política óptima es exactamente π∗\pi^*. Es una reponderación de la referencia por exp⁡(r/β)\exp(r/\beta): las respuestas con más recompensa ganan probabilidad, con β\beta como temperatura.

¿Por qué no usamos esto directamente? Porque Z(x)Z(x) es una suma sobre todas las secuencias posibles: intratable.

Paso 3: invertir la relación

Tomamos logaritmo de la solución cerrada y despejamos la recompensa:

r(x,y)=βlog⁡π∗(y∣x)πref(y∣x)+βlog⁡Z(x)r(x, y) = \beta \log \frac{\pi^*(y \mid x)}{\pi_{\text{ref}}(y \mid x)} + \beta \log Z(x)

dado vuelta: la recompensa de una respuesta se lee en cuánto más probable la hace la política óptima que la referencia, más un término que depende solo del prompt

Esto dice: cualquier recompensa puede escribirse en términos de su política óptima, más un término que solo depende de xx.

Comprueba tu comprensión

¿Por qué no podemos simplemente calcular π*(y|x) = π_ref(y|x)·exp(r/β)/Z(x) y usarla como modelo?

Paso 4: la cancelación mágica

Ahora usamos el modelo de Bradley-Terry, que solo depende de diferencias de recompensa para el mismo xx:

P(yw≻yl∣x)=σ(r(x,yw)−r(x,yl))P(y_w \succ y_l \mid x) = \sigma\big( r(x, y_w) - r(x, y_l) \big)

la probabilidad de que una persona prefiera la respuesta ganadora ywy_w a la perdedora yly_l: la sigmoide σ\sigma de la diferencia de sus recompensas

Sustituimos la expresión del paso 3. El término βlog⁡Z(x)\beta \log Z(x) aparece en ambas recompensas y se cancela:

P(yw≻yl∣x)=σ(βlog⁡π∗(yw∣x)πref(yw∣x)−βlog⁡π∗(yl∣x)πref(yl∣x))P(y_w \succ y_l \mid x) = \sigma\left( \beta \log \frac{\pi^*(y_w \mid x)}{\pi_{\text{ref}}(y_w \mid x)} - \beta \log \frac{\pi^*(y_l \mid x)}{\pi_{\text{ref}}(y_l \mid x)} \right)

lo mismo, con cada recompensa escrita a partir de la política: el término βlog⁡Z(x)\beta \log Z(x) estaba en las dos y se canceló

Ya no hay nada intratable. La probabilidad de preferencia queda expresada solo en términos de la política y la referencia.

Paso 5: la pérdida de DPO

Reemplazamos π∗\pi^* por una política parametrizada πθ\pi_\theta y maximizamos la verosimilitud de las preferencias observadas:

LDPO(θ)=− E(x,yw,yl)∼D[log⁡σ(βlog⁡πθ(yw∣x)πref(yw∣x)−βlog⁡πθ(yl∣x)πref(yl∣x))]\mathcal{L}_{\text{DPO}}(\theta) = -\,\mathbb{E}_{(x, y_w, y_l) \sim \mathcal{D}}\left[ \log \sigma\left( \beta \log \frac{\pi_\theta(y_w \mid x)}{\pi_{\text{ref}}(y_w \mid x)} - \beta \log \frac{\pi_\theta(y_l \mid x)}{\pi_{\text{ref}}(y_l \mid x)} \right) \right]

la pérdida de DPO: para cada par del dataset, premia que el modelo suba la respuesta ganadora y baje la perdedora, siempre medido contra la referencia. El signo menos y el logaritmo la vuelven algo a minimizar

Compárala con la pérdida del reward model de la lección anterior: es la misma, con la recompensa reemplazada por la recompensa implícita

r^θ(x,y)=βlog⁡πθ(y∣x)πref(y∣x)\hat r_\theta(x, y) = \beta \log \frac{\pi_\theta(y \mid x)}{\pi_{\text{ref}}(y \mid x)}

la recompensa implícita: cuánto más probable hace el modelo una respuesta que la referencia, en logaritmo y escalado por β\beta

De ahí el subtítulo del paper: el modelo de lenguaje es el reward model.

Implementación

En la práctica, log⁡π(y∣x)\log \pi(y \mid x) es la suma de log-probabilidades de los tokens de la respuesta. Necesitamos forward passes de la política (con gradiente) y de la referencia (congelada, sin gradiente).

python
import torch
import torch.nn.functional as F

def sequence_logprob(model, input_ids, attention_mask, response_mask):
    """Suma de log p(token) sobre los tokens de la respuesta (no del prompt)."""
    logits = model(input_ids=input_ids, attention_mask=attention_mask).logits
    # el logit en la posición t predice el token t+1
    logits = logits[:, :-1, :]
    targets = input_ids[:, 1:]
    mask = response_mask[:, 1:].float()
    logps = torch.gather(F.log_softmax(logits, dim=-1), 2, targets.unsqueeze(-1)).squeeze(-1)
    return (logps * mask).sum(dim=-1)

def dpo_loss(policy, ref, batch, beta: float = 0.1):
    pi_w = sequence_logprob(policy, batch["chosen_ids"], batch["chosen_attn"], batch["chosen_resp_mask"])
    pi_l = sequence_logprob(policy, batch["rejected_ids"], batch["rejected_attn"], batch["rejected_resp_mask"])
    with torch.no_grad():
        ref_w = sequence_logprob(ref, batch["chosen_ids"], batch["chosen_attn"], batch["chosen_resp_mask"])
        ref_l = sequence_logprob(ref, batch["rejected_ids"], batch["rejected_attn"], batch["rejected_resp_mask"])

    # recompensas implícitas
    r_w = beta * (pi_w - ref_w)
    r_l = beta * (pi_l - ref_l)

    loss = -F.logsigmoid(r_w - r_l).mean()
    # métrica útil: % de pares donde la recompensa implícita ordena bien
    accuracy = (r_w > r_l).float().mean()
    return loss, accuracy

Observa lo que no hay: ni muestreo durante el entrenamiento, ni reward model separado, ni value network, ni clipping. Son dos modelos (uno congelado) y una pérdida de clasificación.

Comprueba tu comprensión

En la implementación de DPO, ¿por qué los log-probs del modelo de referencia se calculan dentro de torch.no_grad()?

¿Qué controla β?

β\beta es el mismo coeficiente de la restricción KL. Un β\beta grande mantiene la política cerca de la referencia (más conservador); uno chico permite desviarse más para ajustar las preferencias. Valores en el rango de 0.1 a 0.5 son comunes en la práctica, pero depende del dataset.

Limitaciones y críticas

  • Off-policy. DPO aprende de un dataset fijo de pares, generalmente muestreados de otro modelo. RLHF con PPO, en cambio, genera y evalúa respuestas de la política actual (on-policy). Varios trabajos posteriores reportan que la exploración on-policy sigue aportando, y surgieron variantes de "DPO iterativo/online" que regeneran pares.
  • Probabilidad de la respuesta preferida. La pérdida solo mira la diferencia de recompensas implícitas: puede bajar las probabilidades de ywy_w y yly_l al mismo tiempo, siempre que yly_l baje más. Esto se observó empíricamente y motivó variantes con términos adicionales.
  • Sobreajuste a preferencias deterministas. Si en el dataset ywy_w siempre gana, la pérdida empuja r^w−r^l→∞\hat r_w - \hat r_l \to \infty, lo que puede debilitar el efecto de la KL. IPO (Azar et al., 2023) analiza este problema y propone una pérdida alternativa.
  • No elimina Goodhart. El reward model sigue estando, solo que implícito. Si las preferencias del dataset tienen sesgos (por ejemplo, favorecen respuestas largas), DPO los aprende igual.

Comprueba tu comprensión

Durante el entrenamiento con DPO observas que la pérdida baja pero la log-probabilidad de las respuestas preferidas también baja. ¿Es posible?

¿Qué tal esta lección?

Sé el primero en calificarla

Entra para calificar

¿Terminaste la lección?

Márcala para sumar +50 XP y mantener tu racha.