Alignment moderno: DPO, KTO, ORPO y SimPO — el sumiller que aprende sin recibir reward model
Este post es la continuación natural del fine-tuning continuo en producción, que cubre el ciclo operativo (Postgres + queries SQL + hot-swap) que alimenta a estos métodos con datos reales. Aquí entramos al dentro de cada uno: qué optimiza cada loss, qué hipótesis hace, y por qué eligen una u otra.
TL;DR
RLHF clásico —el de los papers de InstructGPT— está prácticamente extinto en producción. El motivo no es ideológico: es que en 2023 Rafailov y otros demostraron que el reward model no tiene por qué existir como objeto separado. Con un cambio de variable elegante, la política óptima se puede entrenar directamente desde pares de preferencia, sin pasar por reward y sin RL. Eso es DPO. Desde ahí la familia se ha ramificado en cuatro métodos que conviven en 2026: DPO cuando tienes pares (chosen, rejected), KTO cuando sólo tienes señal binaria 👍/👎, ORPO cuando quieres SFT y preferencias en la misma pasada para ahorrar memoria, y SimPO cuando quieres eliminar también el modelo de referencia y normalizar por longitud. Este post explica qué hace exactamente cada loss, lo prueba con un ejemplo numérico end-to-end, da la tabla de decisión real entre los cuatro y desmonta los tres sesgos que matan el método en producción cuando nadie los vigila.
Estás aquí: TUNE
El pipeline LLMOps de seis etapas sitúa Tune entre Data y Eval. Dentro de Tune conviven tres modalidades: SFT (supervised fine-tuning), preference optimization (lo que cubre este post) y agent training / RFT. Lo que sigue es el dentro de la segunda modalidad.
La analogía: el sumiller que entrena el paladar sin libro de teoría
Imagina que quieres formar a un sumiller. Tienes dos caminos. El primero es enseñarle teoría enológica: variedades de uva, terruños, métodos de vinificación, tipos de barrica. Le das tarjetas con descripciones canónicas de vinos y le pides que las memorice. Eso es SFT: pares (prompt, respuesta ideal). Funciona como educación general, pero el sumiller que sale de ahí no distingue dos riojas excelentes entre sí.
El segundo camino es el comparador ciego. Le pones dos copas idénticas opacas. Le dices “este es mejor que este”. No le explicas por qué. Repites el ejercicio mil veces, con mil pares distintos. Al cabo de un tiempo, el sumiller no necesita que se lo digas: tiene el paladar formado. No ha aprendido teoría enológica, ha aprendido a discriminar.
DPO, KTO, ORPO y SimPO son cuatro variantes del segundo camino. Las cuatro entrenan al modelo a discriminar, no a memorizar. Las diferencias entre ellas son:
- DPO: dos copas en cada catación, el sumiller siempre sabe cuál es la “buena” y cuál es la “mala”.
- KTO: una sola copa cada vez, sólo se le dice “esto te gustaría” o “esto no te gustaría”. Sin pares.
- ORPO: la catación incluye también una pequeña clase teórica embebida (SFT en paralelo) para no olvidar el catálogo.
- SimPO: como DPO pero el sumiller no compara contra “lo que tu maestro habría dicho” (modelo de referencia); compara directamente las dos copas, normalizando por la cantidad de líquido en cada una.
La analogía no es decorativa: el resto del post es esa misma idea expresada matemáticamente.
Por qué existe DPO: el truco de Rafailov
Para entender DPO conviene recorrer en treinta segundos lo que reemplaza. RLHF clásico, el de InstructGPT, tiene tres fases:
Fase 1 – SFT. Entrenas el modelo sobre (prompt, respuesta ideal). Sale π_ref: la política de referencia. Es el modelo “educado”.
Fase 2 – Reward model. Sobre el mismo modelo (otra cabeza), entrenas un regresor: dado (prompt, chosen, rejected), aprende a dar score más alto al chosen. Sale r_φ(x, y).
Fase 3 – PPO. Tomas π_ref como punto de partida y entrenas otra copia π_θ para que maximice r_φ(x, π_θ(x)) con una penalización KL para no alejarse demasiado de π_ref. Eso requiere generar rollouts (decode on-policy a cada paso), tener los tres modelos en memoria (π_θ, π_ref, r_φ), y un setup de RL clásico —inestable, sensible a hiperparámetros y famoso por sus problemas de reproducibilidad—.
La observación de Rafailov fue: la fase 3 tiene solución cerrada. Si planteas el problema de optimización exacto que resuelve PPO
$$\max_{\pi_\theta} ; \mathbb{E}{x \sim D, , y \sim \pi\theta(\cdot|x)} \big[ r_\phi(x,y) \big] - \beta , \mathrm{KL}\big(\pi_\theta(\cdot|x) ,|, \pi_\mathrm{ref}(\cdot|x)\big)$$
resulta que la política óptima tiene la forma
$$\pi^{*}(y|x) = \frac{1}{Z(x)} , \pi_\mathrm{ref}(y|x) , \exp!\left( \tfrac{1}{\beta} r_\phi(x,y) \right)$$
y de ahí se despeja el reward implícito:
$$r_\phi(x,y) = \beta \log \frac{\pi^{*}(y|x)}{\pi_\mathrm{ref}(y|x)} + \beta \log Z(x).$$
El segundo término es una función sólo de x y se cancela cuando comparas dos respuestas al mismo prompt. El reward no necesita aprenderse: está implícito en la ratio de log-probs entre el modelo entrenado y el de referencia. Si plugueas eso en el modelo de Bradley-Terry para preferencias (la fórmula que dice “la probabilidad de que yw sea preferido a yl es σ(r(x,yw) - r(x,yl))”), sale la loss de DPO:
$$\mathcal{L}\mathrm{DPO}(\pi\theta;\pi_\mathrm{ref}) = -,\mathbb{E}{(x, y_w, y_l) \sim D} \log \sigma!\Big( \beta \big[ \log \tfrac{\pi\theta(y_w|x)}{\pi_\mathrm{ref}(y_w|x)} - \log \tfrac{\pi_\theta(y_l|x)}{\pi_\mathrm{ref}(y_l|x)} \big] \Big).$$
Eso es DPO entero. No hay reward model, no hay RL, no hay rollouts. Sólo log-probs sobre datos estáticos.
DPO con números reales
La fórmula intimida menos cuando se evalúa con un ejemplo. Imagina un par del dataset:
x= “Explica qué es un KVM switch”.y_w= respuesta correcta (chosen).y_l= respuesta confusa (rejected).
Después de un forward pass tenemos cuatro números (sumas de log-probs por token, signo negativo porque cada log p_token ≤ 0):
| Cantidad | Valor |
|---|---|
log π_θ(y_w | x) | −45.2 |
log π_θ(y_l | x) | −52.1 |
log π_ref(y_w | x) | −47.3 |
log π_ref(y_l | x) | −50.8 |
Las “ratios” son la mejora del modelo entrenado respecto al de referencia para cada respuesta:
- Para el
y_w:−45.2 − (−47.3) = +2.1→ el modelo entrenado le da más probabilidad que el de referencia. Bien. - Para el
y_l:−52.1 − (−50.8) = −1.3→ el modelo entrenado le da menos probabilidad. También bien.
Con β = 0.1 (valor típico) el “margen” interior del logaritmo es:
$$m = \beta \cdot (2.1 - (-1.3)) = 0.1 \cdot 3.4 = 0.34$$
Y la loss:
$$\mathcal{L}_\mathrm{DPO} = -\log \sigma(0.34) = -\log(0.584) \approx 0.538.$$
La intuición se ve directamente: cuanto más sube la log-prob del chosen y más baja la del rejected (en relación a π_ref), más positivo es m, más alto el sigmoide y más baja la loss. Si el margen es negativo (el modelo se equivoca), σ(m) < 0.5 y la loss explota hacia arriba. El gradiente empuja al modelo a aumentar π_θ(y_w|x) y bajar π_θ(y_l|x).
El papel de β: es la temperatura del alineamiento. Si β es pequeño, el modelo se permite alejarse mucho de π_ref; si es grande, el KL pesa mucho y el modelo casi no se mueve. Valor típico en 2026: 0.05–0.3, con 0.1 como punto de partida.
KTO: cuando sólo tienes 👍/👎
DPO necesita pares. En la práctica, eso casi nunca lo da el producto: lo que da el producto es feedback binario (un thumbs up o un thumbs down, una conversión o un abandono). KTO —Kahneman-Tversky Optimization, Ethayarajh et al. 2024— resuelve exactamente ese caso.
La intuición viene de la teoría de las perspectivas de Kahneman y Tversky: los humanos somos más sensibles a las pérdidas que a las ganancias de la misma magnitud (loss aversion: una pérdida de 100 € duele más que ganar 100 €). KTO traslada eso al loss:
$$\mathcal{L}\mathrm{KTO}(x, y) = \begin{cases} \lambda_d \big[ 1 - \sigma!\big(\beta \cdot ( h\theta(x,y) - z_0 ) \big) \big] & \text{si } y \text{ es deseable},\ \lambda_u \big[ 1 - \sigma!\big(\beta \cdot ( z_0 - h_\theta(x,y) ) \big) \big] & \text{si } y \text{ es indeseable}, \end{cases}$$
donde h_θ(x,y) = log(π_θ(y|x) / π_ref(y|x)) es exactamente la misma ratio que aparecía en DPO, z_0 es una estimación de la divergencia KL del batch (sirve como “punto neutro”) y λ_d, λ_u son los pesos de deseable / indeseable.
El punto crítico: KTO no necesita pares. Cada ejemplo es (prompt, respuesta, label binario). Esto encaja con la telemetría real de producto. La regla práctica habitual es λ_u > λ_d (ej. 1.0 vs 0.33) cuando la base de datos tiene más 👍 que 👎, para que la señal negativa no se diluya.
KTO funciona especialmente bien en dos escenarios:
- Productos con UX de feedback explícito (chatbots con 👍/👎): cada thumbs es un ejemplo KTO directo, no hace falta sintetizar pares.
- Datasets desbalanceados (mucho más 👍 que 👎, o al revés): los pesos
λ_d,λ_ulo gestionan explícitamente.
ORPO: SFT y preferencias en una sola pasada
DPO asume que ya has hecho SFT. Entrenas dos fases: primero SFT para conseguir π_ref, luego DPO sobre π_ref. Dos pases por los datos, dos optimizaciones, dos modelos en memoria.
ORPO —Odds Ratio Preference Optimization, Hong et al. 2024— fusiona ambas fases. La loss combina dos términos:
$$\mathcal{L}\mathrm{ORPO} = \mathcal{L}\mathrm{SFT}(y_w) + \lambda \cdot \mathcal{L}_\mathrm{OR}(y_w, y_l)$$
El primer término es el SFT clásico sobre la respuesta chosen (cross-entropy negativa). El segundo es el odds ratio entre chosen y rejected:
$$\mathcal{L}\mathrm{OR} = -\log \sigma!\Big( \log \tfrac{\mathrm{odds}\theta(y_w|x)}{\mathrm{odds}\theta(y_l|x)} \Big), \quad \text{con } \mathrm{odds}\theta(y|x) = \tfrac{P_\theta(y|x)}{1 - P_\theta(y|x)}.$$
Lo que importa: no hay π_ref. ORPO entrena un solo modelo, en una sola pasada, sin cargar la política de referencia en memoria. Sobre el papel suena bien y en la práctica funciona: un Llama 3 8B alineado con ORPO sobre 5k pares tarda ~3 horas en 4×H100 y queda en VRAM con QLoRA agresivo en una sola RTX 4090.
El parámetro λ es el peso del término preference. Típico: 0.1–0.3. Si λ es muy alto, el modelo aprende a discriminar pero olvida el SFT (catastrophic forgetting); si es muy bajo, el alignment apenas se nota.
SimPO: ¿de verdad necesitas modelo de referencia?
SimPO —Simple Preference Optimization, Meng et al. 2024— lleva la pregunta de ORPO un paso más lejos: si ORPO se libera de π_ref para el SFT+preference combinado, ¿por qué no liberarse de π_ref también en el caso DPO puro?
La loss de SimPO:
$$\mathcal{L}\mathrm{SimPO} = -\log \sigma!\Big( \tfrac{\beta}{|y_w|} \log \pi\theta(y_w|x) - \tfrac{\beta}{|y_l|} \log \pi_\theta(y_l|x) - \gamma \Big).$$
Dos cambios respecto a DPO:
- No hay
π_ref: directamente se comparan log-probs absolutas del modelo entrenado. - Length-normalization: cada log-prob se divide por la longitud de su respuesta
|y|. Esto es clave porque sin normalizar, las respuestas largas tienden a tener log-prob total más baja (cada token aporta sulog p < 0), creando un sesgo artificial. - Margen explícito
γ: la loss es baja si la diferencia de log-probs normalizadas superaγ. Típico:γ = 0.5–1.5.
Con β = 2.0, γ = 1.0, |y_w| = 120 tokens, |y_l| = 100 tokens y las log-probs anteriores:
$$m = \tfrac{2.0}{120} \cdot (-45.2) - \tfrac{2.0}{100} \cdot (-52.1) - 1.0 = -0.753 + 1.042 - 1.0 = -0.711.$$
$$\mathcal{L}_\mathrm{SimPO} = -\log \sigma(-0.711) \approx 1.11.$$
Loss más alta que DPO en el mismo punto: SimPO tarda más en converger, pero usa la mitad de memoria (un solo modelo en VRAM) y elimina la dependencia de π_ref. Es la opción dominante cuando la memoria es el cuello de botella.
Tabla de decisión: cuál usar y cuándo
| Señal disponible | Memoria disponible | SFT previo | Método recomendado | Justificación |
|---|---|---|---|---|
Pares (chosen, rejected) | Alta (≥ 80 GB GPU) | Sí | DPO | Baseline más establecido, mejor reproducibilidad |
Pares (chosen, rejected) | Baja (24–48 GB GPU) | Sí | SimPO | Elimina π_ref → ~50 % menos VRAM |
Pares (chosen, rejected) | Cualquiera | No | ORPO | SFT y preferencias en una pasada |
| Señal binaria 👍/👎 sin pares | Alta | Sí | KTO | El único método nativo para datos no-emparejados |
| Señal binaria + pocos pares | Alta | Sí | KTO con sub-batch DPO | Combinación documentada en TRL 0.13 |
| Trayectorias multistep (tool use) | Muy alta | Sí | RLHF/RFT puro | Los métodos preference-pair no capturan la dinámica |
Magnitudes típicas de dataset:
| Método | Mínimo viable | Sweet spot | Plateau |
|---|---|---|---|
| DPO | 1 000 pares | 5 000–20 000 | > 50 000 |
| SimPO | 2 000 pares | 5 000–20 000 | > 50 000 |
| ORPO | 3 000 pares (incluye SFT) | 10 000–30 000 | > 80 000 |
| KTO | 5 000 ejemplos binarios | 20 000–80 000 | > 200 000 |
KTO necesita típicamente 3-4× más volumen que DPO porque la señal binaria es más débil que la comparativa. La compensación es que la señal binaria es la que naturalmente produce un producto en producción.
Los tres sesgos que rompen el método
Los cuatro métodos comparten un problema: están entrenando sobre proxies de calidad, no sobre calidad. Esos proxies tienen sesgos sistemáticos que el modelo puede explotar trivialmente.
Length bias
Documentado en el paper original de DPO y en literatura posterior. Las respuestas largas tienden a ser preferidas por humanos —probablemente porque parecen “más completas”—. Si el dataset de pares hereda ese sesgo, el modelo aprende que alargar la respuesta es lo que se premia, no que mejor contenido es lo que se premia. Resultado: tras 2–3 epochs el modelo escupe verborrea.
Mitigaciones:
- DPO: filtrado del dataset eliminando pares donde
|y_w| > 1.3 · |y_l|(regla del 30 %). - SimPO: la length-normalization en la loss lo arregla por construcción.
- ORPO / KTO: filtrado del dataset o regularización auxiliar de longitud (DPOP, R-DPO).
La gráfica muestra el patrón habitual: sin mitigación, en 3 epochs un Llama 3 8B con DPO puede pasar de respuestas de ~150 tokens a respuestas de ~280 tokens, sin que mejore la calidad evaluada por humanos. SimPO mantiene la longitud aproximadamente estable.
Position bias (en la curación del dataset)
Si los pares se generan automáticamente con un LLM judge (cubierto en detalle en el siguiente post de esta serie), hay un sesgo conocido: los jueces prefieren la primera respuesta que ven cuando las dos son comparables. Si todos los pares del dataset tienen el chosen siempre en posición A y el rejected en posición B, el modelo no aprende preferencia: aprende un artefacto del proceso de curación.
Mitigación: shuffle aleatorio de orden en la query al judge y promediar dos pasadas con orden invertido (vista en herramientas como Promptfoo y Inspect AI por defecto).
Distribution shift entre datos y π_ref
DPO, KTO y SimPO comparan implícitamente el modelo entrenado contra una distribución. Si los datos de preferencia provienen de un modelo (otro LLM generando candidatos) muy distinto de π_ref, el modelo entrenado puede explorar regiones donde π_ref tiene probabilidad casi cero, dando ratios numéricamente inestables (log de cantidades muy pequeñas). En la práctica esto se traduce en explosiones de loss, gradientes NaN o regresión silenciosa.
Mitigación: generar los candidatos del dataset con el propio π_ref siempre que sea posible (rejection sampling sobre π_ref, con un judge externo eligiendo el chosen). Esa es la prescripción canónica de RLHF on-policy aplicada al setting offline.
Implicaciones en hardware on-premise
Las cifras siguientes son indicativas para un escenario típico de mayo 2026: Llama 3.1 8B Instruct como π_ref, dataset de 5 000–20 000 pares, QLoRA (NF4) con LoRA rank 16 sobre todos los proyectores del bloque transformer (q,k,v,o,gate,up,down), batch size efectivo 16, 1–3 epochs.
En una RTX 4090 (24 GB)
| Método | VRAM pico | Tiempo / epoch (5k pares) | Notas |
|---|---|---|---|
| DPO | ~22 GB | 50–80 min | Necesita π_ref en VRAM aunque cuantizada FP8/INT8 |
| SimPO | ~14 GB | 45–70 min | Sin π_ref — la opción natural en 4090 |
| ORPO | ~16 GB | 60–90 min | Sin π_ref — viable holgadamente |
| KTO | ~22 GB | 90–150 min (10k binarios) | Misma VRAM que DPO, más datos por epoch |
La 4090 (24 GB, Ada Lovelace, sin NVLink) es perfectamente viable para Llama 8B con QLoRA si se elige el método con cabeza. Para 13B la elección entre SimPO/ORPO ya no es preferencia, es requisito.
En un cluster genérico 4×H100 SXM (320 GB, NVLink)
| Método | Modelo viable | Tiempo / epoch (10k pares) | Notas |
|---|---|---|---|
| DPO | Llama 3 70B (4-bit) | 60–90 min | Tensor parallel = 4, sigue holgado |
| SimPO | Llama 3 70B (BF16) | 50–75 min | Cabe BF16 entero gracias a no tener π_ref |
| ORPO | Llama 3 70B (BF16) | 70–100 min | Similar a SimPO en consumo |
| KTO | Llama 3 70B (4-bit) | 100–140 min | Datasets mayores compensados por paralelismo |
En un cluster NVLink la diferencia operativa entre métodos se difumina: todos caben. La elección vuelve a ser sobre qué tipo de señal tienes, no sobre presupuesto.
Lo que no hemos cubierto (próximos artículos)
- LoRA y QLoRA fundamentos: la matemática del adapter de bajo rango que sostiene todo lo anterior — por qué cabe un 70B en 24 GB.
- LLM-as-judge fundamentos: cómo se construye el judge que genera los pares chosen/rejected sin sesgo de posición ni de verbosidad. El siguiente post de esta tanda lo cubre.
- Online DPO y iterative on-policy: estado del arte en investigación 2026 (Fast-Slow Chasing, RLOO, iterative preference learning) y por qué todavía no es producción.
- Distillation y synthetic preference data: cuándo merece la pena generar pares con un modelo grande para entrenar uno pequeño.
Ver también
- Fine-tuning continuo en producción — el ciclo operativo (Postgres, queries SQL, hot-swap multi-LoRA) que alimenta de pares a los métodos de este post.
- Retrain: cerrar el bucle — cómo las señales de producción se convierten en el dataset de preferencia.
- Evals para LLMs: la capa después del tracing — la batería de evaluadores que decide si el adapter alineado se promociona a producción.
- LLM-as-judge: el corrector de oposiciones — el mecanismo que genera los pares
(chosen, rejected)consumidos aquí. Calibración del judge con Cohen’s kappa y los cuatro sesgos que invalidan los pares si no se vigilan.
Referencias
- Rafailov, R., Sharma, A., Mitchell, E., Ermon, S., Manning, C. D., Finn, C. Direct Preference Optimization: Your Language Model is Secretly a Reward Model (NeurIPS 2023).
- Ethayarajh, K., Xu, W., Muennighoff, N., Jurafsky, D., Kiela, D. KTO: Model Alignment as Prospect Theoretic Optimization (ICML 2024).
- Hong, J., Lee, N., Thorne, J. ORPO: Monolithic Preference Optimization without Reference Model (EMNLP 2024).
- Meng, Y., Xia, M., Chen, D. SimPO: Simple Preference Optimization with a Reference-Free Reward (NeurIPS 2024).
- HuggingFace TRL 0.13 — implementaciones de referencia: https://huggingface.co/docs/trl.
- Tunstall, L. et al. The Alignment Handbook — recetas reproducibles: https://github.com/huggingface/alignment-handbook.
- Park, R. et al. Disentangling Length from Quality in Direct Preference Optimization (R-DPO, ACL 2024).