ml-models / Language models / Preference optimization: RLHF and DPO advanced

Preference optimization

A fine-tuned language model can follow instructions, but nothing in next-token training says which of two good-looking answers people actually prefer. Preference optimization trains on those judgments directly. This page builds the pieces in order: a reward model fitted to pairwise preferences with the Bradley–Terry model, RLHF with PPO and a KL penalty, the closed-form solution that lets DPO skip the reward model, the IPO, KTO and GRPO variants, and reward hacking, with every number computed and every PyTorch link pinned.

On this page
  1. Problem
  2. Intuition
  3. Mechanics
  4. Reward models from pairwise preferences
  5. RLHF: PPO with a KL penalty
  6. DPO: the closed-form optimum, turned around
  7. Variants: IPO, KTO and GRPO
  8. Reward hacking
  9. Worked example
  10. Fitting the reward model
  11. The KL-regularized optimum
  12. Turning β down: reward hacking
  13. DPO reaches the same policy
  14. A unanimous pair: DPO against IPO
  15. Per-token KL rewards in RLHF
  16. GRPO's group advantages and the k3 estimator
  17. Implementation
  18. Tradeoffs
  19. Connections
  20. Read first
  21. Read next
  22. References

Problem

Supervised fine-tuning imitates demonstrations: it raises the probability of whatever a human wrote. That works for format and tone, but it cannot express "this answer is better than that one", it treats every token of a demonstration as equally right, and good demonstrations are slow to write. Judging is cheaper than writing: a person can compare two answers in seconds, even for tasks they could not have answered well themselves.

Preference optimization turns comparisons into a training signal. The data is a set of triples (prompt x, preferred response yw, rejected response yl). The goal is a policy πθ that produces responses people prefer, without drifting so far from the fine-tuned model that it forgets how to write or finds a loophole in the signal.

Intuition

Think of a judge at a cooking contest who never gives scores, only says which of two dishes is better. From enough of those verdicts you can recover a score for every dish: a dish that beats strong dishes must be strong. That is the reward model. Then you train the cook to make dishes the score likes, while keeping them close to the cook's own style, so the cook improves instead of inventing something the judge has never tasted and the score cannot rate.

RLHF does those two steps literally: fit a score, then run reinforcement learning against it with a leash. DPO notices that the best leashed policy has a formula, and that the formula can be turned around so that the policy itself is the score. One classification-style loss on the pairs then does both steps at once.

Two routes from preference pairs to a tuned policy An SFT model generates candidate responses and people compare them, producing preference pairs. The RLHF route fits a reward model to the pairs, then optimizes the policy with PPO against that reward minus a KL penalty to the frozen reference model. The DPO route applies one loss to the pairs using the policy and the frozen reference directly. Both end at a tuned policy. SFT model π_SFT = π_ref preference pairs (x, y_w, y_l) people compare reward model r_φ Bradley–Terry loss PPO on policy r_φ − β·log π/π_ref RLHF: two stages, sampling DPO loss on π_θ and frozen π_ref −log σ(β·(log-ratio_w − log-ratio_l)) DPO: one stage, no sampling same optimum (in theory)

Both routes start from the same supervised model, which also serves as the frozen reference πref. RLHF learns a separate reward and then samples from the policy to optimize it; DPO fits the policy to the pairs directly. The worked example below shows the two reaching the same policy.

Mechanics

Reward models from pairwise preferences

The Bradley–Terry model says each item has a hidden strength, and the chance that i beats j depends only on the difference. Written with a reward r instead of a strength, the probability is the sigmoid of the reward gap:

P(yw ≻ yl | x) = σ(r(x, yw) − r(x, yl)) = exp rw / (exp rw + exp rl)

A reward model rφ is usually the fine-tuned language model with its vocabulary head replaced by a single linear output, read at the last token of the response. It is trained by maximum likelihood on the comparisons, which is binary cross-entropy on the reward gap with the label "the preferred one won":

LRM(φ) = −E(x, yw, yl) log σ(rφ(x, yw) − rφ(x, yl))

Only differences matter, so adding a constant to every reward changes nothing; InstructGPT normalizes the reward model so that the demonstrations score zero on average before reinforcement learning. InstructGPT also had labelers rank between K = 4 and K = 9 responses per prompt, which gives C(K, 2) comparisons from one prompt, and trained on all comparisons from a prompt together as one batch element, scaling the loss by 1/C(K, 2): treating them as independent samples made the reward model overfit, since each response appears in K − 1 of them.

RLHF: PPO with a KL penalty

With a reward model in hand, the policy is trained to maximize reward while staying close to the reference policy πref, the supervised model it started from:

maxπ Ex, y∼π[ rφ(x, y) ] − β · KL(π(·|x) ‖ πref(·|x))

In practice the KL term is folded into the reward. Each sampled response is scored once by rφ at its end, and every token pays −β · log(π(yt|·) / πref(yt|·)); summed over the response this is a one-sample estimate of the sequence KL. The resulting per-token rewards go to PPO, with a value head estimating advantages and the clipped ratio keeping each update small. InstructGPT also added a pretraining term, "PPO-ptx", that mixes ordinary language-modeling gradients on pretraining data into the PPO update to reduce regressions on public benchmarks.

The KL term does two jobs. It keeps the policy in the region where the reward model was trained, since the reward model has only seen responses from something like πref, and it stops the policy collapsing onto a single high-reward response: without it, the optimum of E[r] is a point mass on the arg max.

DPO: the closed-form optimum, turned around

For a fixed prompt, the KL-regularized objective has an exact solution. Write the objective as −β times a KL to a tilted distribution plus a constant, and the maximizer is that distribution:

π*(y|x) = πref(y|x) · exp(r(x, y) / β) / Z(x),   Z(x) = Σy πref(y|x) · exp(r(x, y) / β)

Z(x) sums over every possible response, so this formula cannot be used to sample; that is why RLHF needs PPO. But it can be solved for the reward. Take logs:

r(x, y) = β · log(π*(y|x) / πref(y|x)) + β · log Z(x)

Substitute this into Bradley–Terry. The β log Z(x) term is the same for yw and yl, so it cancels in the difference, and the preference probability depends only on the policy and the reference:

P(yw ≻ yl | x) = σ(β · log(π*(yw|x) / πref(yw|x)) − β · log(π*(yl|x) / πref(yl|x)))

Now replace π* with the trainable πθ and maximize the likelihood of the observed preferences. That is Direct Preference Optimization:

LDPO(θ) = −E log σ(β · log(πθ(yw|x) / πref(yw|x)) − β · log(πθ(yl|x) / πref(yl|x)))

The quantity r̂θ(x, y) = β · log(πθ(y|x) / πref(y|x)) is the policy's implicit reward; the paper's title says it: your language model is secretly a reward model. The loss is the reward-model loss with r̂θ in place of rφ, so fitting it fits a reward model whose optimal policy is πθ itself. Its gradient is

∇LDPO = −β · E[ σ(r̂θ(yl) − r̂θ(yw)) · (∇ log πθ(yw|x) − ∇ log πθ(yl|x)) ]

It pushes up the preferred response and down the rejected one, weighted by how wrong the implicit reward currently is: pairs the model already orders correctly by a wide margin contribute almost nothing. The paper reports that dropping the weight and just pushing the pair apart degenerates the model. Every log π(y|x) is a sum of token log-probabilities, the same quantity pretraining maximizes, so DPO needs four forward passes per pair (policy and reference, on both responses) and no sampling.

Variants: IPO, KTO and GRPO

IPO (Azar et al.) starts from a weakness in DPO's derivation. If a pair is always won by the same response, Bradley–Terry says the reward gap is infinite, and DPO keeps widening the log-ratio margin h = log(πθ(yw)/πref(yw)) − log(πθ(yl)/πref(yl)) forever, so the KL regularization stops binding on finite data. IPO regresses the margin to a fixed target instead:

LIPO(θ) = E (hθ(x, yw, yl) − 1/(2τ))²

where τ plays the role of β. The worked example shows both behaviours on one unanimous pair.

KTO (Ethayarajh et al.) drops the pairs. It needs only a label per response, desirable or undesirable, which is easier to collect, for example from thumbs-up and thumbs-down. Its loss is built on the value function of Kahneman and Tversky's prospect theory: the implicit reward β · log(πθ/πref) of each response is compared to a reference point estimated from the KL between policy and reference, and gains and losses are weighted separately, which lets the loss be tuned when desirable and undesirable examples are imbalanced.

GRPO (Group Relative Policy Optimization, from DeepSeekMath) keeps the reinforcement learning but removes PPO's value network. For each prompt it samples a group of G responses, scores each, and uses the group-normalized score as every token's advantage:

Âi = (ri − mean(r1..G)) / std(r1..G)

The clipped PPO ratio objective is unchanged. Instead of subtracting a KL penalty from the reward, GRPO adds a KL term directly to the loss, estimated per token with the unbiased, always non-negative estimator k3 = πref/πθ − log(πref/πθ) − 1. With a rule-based reward, such as checking a math answer, GRPO needs neither a value model nor a learned reward model.

Reward hacking

A reward model is a proxy fitted to a finite set of judgments, and the policy is an optimizer pointed at it. As optimization pushes the policy away from πref, it finds responses the proxy over-rates: longer answers, confident tone, flattering agreement, formatting the labelers happened to like. This is Goodhart's law. Gao, Schulman and Hilton measured it by training policies against a proxy reward model and scoring them with a larger "gold" reward model: as the KL from the initial policy grows, the proxy reward keeps rising while the gold reward rises, peaks and falls, and larger reward models peak later. The worked example below reproduces the shape in miniature.

The defenses are the ones already on this page plus some process: the KL coefficient, early stopping on a held-out judgment, larger and better reward models, fresh comparisons on the current policy's outputs, ensembles of reward models, and penalties for known biases such as length. DPO is not immune: its implicit reward is fitted to the same biased judgments, and its optimum is the same policy.

ComponentShape/ParamsMeaningSource
F.logsigmoid elementwise; margin (B,) → (B,) log σ(z) computed stably; the reward-model, DPO and KTO losses are −logsigmoid of a margin. functional.py 2049-2058
F.binary_cross_entropy_with_logits input (B,), target (B,) of ones The same reward-model loss written as classification, with the reward gap as the logit; also accepts soft targets when labelers disagree. functional.py 3634-3701
F.log_softmax logits (B, T, V) over dim −1 Token log-probabilities for the policy and the reference; their sums over the response tokens are log π(y|x). functional.py 2293-2324
torch.gather (B, T, V) with index (B, T, 1) → (B, T, 1) Picks the log-probability of each actual next token out of the vocabulary. _torch_docs.py 4814-4850
F.kl_div input log q, target p; reduction batchmean A full-distribution KL between policy and reference token distributions, an alternative to the sampled log-ratio estimate. functional.py 3401-3475
F.cross_entropy logits (N, V), targets (N,) The supervised fine-tuning loss that produces πref, and the pretraining term in PPO-ptx. functional.py 3478-3569
Why does the reward model see two responses at once, instead of being trained to predict a 1-to-10 score?

People are inconsistent about absolute scores, from each other and from one day to the next, but much more consistent about which of two answers is better. Bradley–Terry only asks for those relative judgments, and because only differences enter the loss, any per-labeler offset in what counts as "good" cancels out.

Worked example

One prompt, "Why is the sky blue?", and four candidate responses, small enough to solve exactly. The reference policy is a probability over whole responses, πref = (0.40, 0.25, 0.10, 0.25). Each pair was compared ten times, and the counts are invented to carry a known flaw: labelers somewhat prefer the longer answers, so the padded response C, which contains a factual error, wins more often than it should. A hidden "true" reward, (1.0, 1.5, −0.5, −1.5), stands in for the gold judge.

ResponseDescriptionπrefTrue reward
Ashort and correct0.401.0
Blong, correct, well organized0.251.5
Clong, padded, one factual error0.10−0.5
Dshort and wrong0.25−1.5

Fitting the reward model

The table gives each row's wins against each column out of ten comparisons, and next to it the probability the fitted Bradley–Terry model assigns. Fitting is maximum likelihood, here by 500 rounds of the classic minorize–maximize update, with rewards centered to sum to zero.

Wins / fitted P(row ≻ column)ABCD
A – 4/10 · 0.44 4/10 · 0.41 9/10 · 0.84
B 6/10 · 0.56 – 4/10 · 0.47 9/10 · 0.87
C 6/10 · 0.59 6/10 · 0.53 – 8/10 · 0.88
D 1/10 · 0.16 1/10 · 0.13 2/10 · 0.12 –

The fitted rewards are r = (0.28, 0.51, 0.63, −1.41) for A, B, C, D. The proxy ranks C first; the true reward ranks B first. Four numbers cannot match twelve observed rates exactly: the fit gives each response exactly as many expected wins as it observed, which is the maximum-likelihood condition, and spreads the rest. The average loss per comparison is 0.5384 nats, against ln 2 = 0.6931 for all-zero rewards. Adding 3 to every reward gives 0.5384, unchanged, because only gaps enter the loss.

For the pair B over D: the gap is 0.508 − (−1.410) = 1.917, so P = σ(1.917) = 0.8718 and that comparison's loss is −log 0.8718 = 0.1371.

The KL-regularized optimum

With β = 0.5, the optimal policy reweights the reference by exp(r/β) and renormalizes:

π* ∝ πref · exp(r / 0.5) = (0.3976, 0.3944, 0.1995, 0.0085)

It moves mass from the short wrong answer D to B and C, keeps A roughly where it was, and sits at KL(π* ‖ πref) = 0.2864 nats. Its proxy reward is 0.423 and its true reward 0.877, up from the reference's 0.350.

Turning β down: reward hacking

The same closed form for a range of β shows what a weaker leash does. The proxy reward and the KL rise every time β falls, because that is exactly what the objective trades. The true reward does not.

βPolicy over A, B, C, DKL (nats)Proxy rewardTrue reward
8.0(0.41, 0.27, 0.11, 0.21)0.0050.0220.446
4.0(0.43, 0.28, 0.12, 0.17)0.0170.0880.530
2.0(0.44, 0.31, 0.13, 0.12)0.0560.1940.661
1.0(0.44, 0.35, 0.16, 0.05)0.1510.3260.811
0.5(0.40, 0.39, 0.20, 0.01)0.2860.4230.877
0.25(0.28, 0.44, 0.28, 0.00)0.4370.4760.797
0.1(0.06, 0.41, 0.53, 0.00)0.9590.5550.412
0.05(0.00, 0.19, 0.81, 0.00)1.6140.602−0.112
Proxy and true reward against KL from the reference As β falls from 8.0 to 0.05, the optimal policy's KL from the reference grows from 0.005 to 1.61 nats. The proxy reward rises at every step, from 0.022 to 0.602. The true reward rises to 0.877 at β = 0.5 and then falls to −0.112, below the reference policy's 0.35. −0.2 0.0 0.2 0.4 0.6 0.8 1.0 0.0 0.5 1.0 1.5 KL(π ‖ π_ref), nats reference true reward β=1.0 β=0.5 β=0.25 β=0.1 β=0.05 proxy reward (fitted) true reward

The Goodhart curve in miniature. Each point is the exact optimum for one β. Past β = 0.5 the policy keeps buying proxy reward by moving toward C, the padded answer the labelers over-rated, and by β = 0.05 it is worse than where it started.

DPO reaches the same policy

Now skip the reward model. Parameterize the policy by four logits, start them at log πref so that πθ = πref, and run plain gradient descent with learning rate 0.5 on the DPO loss averaged over all 60 comparisons, β = 0.5.

StepDPO lossπθImplicit reward β·log(πθ/πref)
00.6931(0.4000, 0.2500, 0.1000, 0.2500)(0.00, 0.00, 0.00, 0.00)
10.6874(0.4040, 0.2546, 0.1023, 0.2392)(0.00, 0.01, 0.01, −0.02)
20.6820(0.4076, 0.2590, 0.1045, 0.2289)(0.01, 0.02, 0.02, −0.04)
50.6669(0.4170, 0.2713, 0.1107, 0.2010)(0.02, 0.04, 0.05, −0.11)
200.6141(0.4386, 0.3146, 0.1348, 0.1120)(0.05, 0.11, 0.15, −0.40)
1000.5464(0.4181, 0.3778, 0.1819, 0.0222)(0.02, 0.21, 0.30, −1.21)
10000.5384(0.3976, 0.3944, 0.1995, 0.0085)(0.00, 0.23, 0.35, −1.69)

At step 0 every margin is zero, so each comparison's loss is −log σ(0) = 0.6931 and its gradient weight σ(0) = 0.50. By step 1000 the loss is 0.5384, the reward model's loss, and the policy matches the RLHF optimum π* to within 2e-06 in every entry. The implicit rewards are the fitted rewards shifted by a constant: −0.003 vs 0.277, −1.689 vs −1.410. The shift is β log Z, the term that cancelled in the derivation.

For the pair B over D the trained margin is β·h = 1.917, so the pair's loss is 0.1372, the reward model's 0.1371 for the same pair, and its gradient weight has dropped to σ(−1.917) = 0.128.

A unanimous pair: DPO against IPO

Take one pair that the preferred response always wins and train only the margin h (β = 0.5 for DPO, τ = 0.25 for IPO, learning rate 0.25). DPO's loss −log σ(βh) never reaches zero, so its gradient never vanishes and h grows without bound, a little slower each decade. IPO's squared loss has its minimum at 1/(2τ) = 2.0 and stops there.

StepDPO margin hDPO lossIPO margin hIPO loss
10.060.67761.0001.0000
100.580.55801.9980.0000
1003.430.16512.0000.0000
10008.170.01672.0000.0000
1000012.860.00162.0000.0000

A margin of 12.9 means the policy has made the winner e12.9 times more likely relative to the loser than the reference did, from ten agreeing votes. In practice DPO is trained for one or a few epochs, which limits this, and the IPO paper argues the regularized target is the more principled fix.

Per-token KL rewards in RLHF

In the PPO stage the penalty is applied token by token. For a three-token response scored 1.2 by the reward model with β = 0.1:

Tokenlog πlog πreflog ratioReward at this token
Rayleigh−1.204−1.6090.405−0.0405
scattering−0.223−0.3570.134−0.0134
.−0.105−0.051−0.0541.2054

Each token pays −0.1 × its log ratio, and the last also gets the reward model's score. The sequence log ratio is −1.532 − (−2.017) = 0.485, so the episode's return is 1.2 − 0.1 × 0.485 = 1.1515. A token the policy likes less than the reference, here the full stop, earns a small bonus.

GRPO's group advantages and the k3 estimator

Six sampled answers to one math problem are checked by a rule: rewards (1, 0, 0, 1, 0, 0). The group mean is 0.3333 and the standard deviation 0.4714, so the correct answers get advantage 1.414 and the wrong ones −0.707, on every one of their tokens. If all six were right, or all wrong, every advantage would be zero and the prompt would teach nothing.

Ratio πref/πθk1 = −log ratiok3 = ratio − log ratio − 1
0.50.69310.1931
0.90.10540.0054
1.00.00000.0000
1.1−0.09530.0047
2.0−0.69310.3069

For tokens sampled from πθ both estimators average to KL(πθ ‖ πref), but k1 is negative whenever the reference likes a token more than the policy, so a single-sample penalty can reward drift. k3 is never negative and is zero only when the two agree.

How DPO weights a pair as its margin grows The DPO loss −log σ(m) and its gradient weight σ(−m), plotted against the scaled margin m = β·h from −4 to 6. At m = 0 the loss is ln 2 and the weight is 0.5. Pairs ordered the wrong way have weight near 1; pairs ordered correctly by a wide margin have weight near 0. The pair B over D sits at m = 1.92 after training. -4 -2 0 2 4 6 scaled margin m = β·h 0 1 2 3 4 pair B ≻ D loss −log σ(m) gradient weight σ(−m)

The DPO loss is the reward-model loss on the implicit reward gap, so it has the same shape: a pair ordered the wrong way gets nearly full weight, a pair already ordered by a wide margin gets almost none. The loss only flattens toward zero as m grows, which is why a unanimous pair keeps pushing.

Implementation

import torch
import torch.nn.functional as F

def response_logp(model, input_ids, response_mask):
    # model returns logits (B, T, V); response_mask is 1 on response tokens, 0 on the prompt and padding
    logits = model(input_ids)[:, :-1].float()
    targets = input_ids[:, 1:].unsqueeze(-1)
    token_logp = F.log_softmax(logits, dim=-1).gather(-1, targets).squeeze(-1)
    return (token_logp * response_mask[:, 1:]).sum(-1)          # log pi(y|x), shape (B,)

def reward_model_loss(reward_model, chosen, rejected):
    gap = reward_model(**chosen) - reward_model(**rejected)       # one scalar per sequence
    return -F.logsigmoid(gap).mean()

def dpo_loss(policy, reference, chosen, rejected, beta=0.1):
    pi_w, pi_l = response_logp(policy, **chosen), response_logp(policy, **rejected)
    with torch.no_grad():
        ref_w, ref_l = response_logp(reference, **chosen), response_logp(reference, **rejected)
    reward_w, reward_l = beta * (pi_w - ref_w), beta * (pi_l - ref_l)   # implicit rewards
    loss = -F.logsigmoid(reward_w - reward_l).mean()
    accuracy = (reward_w > reward_l).float().mean()
    return loss, accuracy

def ipo_loss(pi_w, pi_l, ref_w, ref_l, tau=0.1):
    h = (pi_w - ref_w) - (pi_l - ref_l)
    return ((h - 1 / (2 * tau)) ** 2).mean()

def grpo_advantages(rewards, eps=1e-6):                         # rewards: (prompts, G)
    return (rewards - rewards.mean(-1, keepdim=True)) / (rewards.std(-1, keepdim=True) + eps)

def k3(logp, ref_logp):                                         # per token, sampled from the policy
    log_ratio = ref_logp - logp
    return torch.exp(log_ratio) - log_ratio - 1

The reference model is a frozen copy of the starting policy, so DPO holds two models in memory; its log-probabilities can be computed once over the dataset and stored, since they never change. Sum log-probabilities only over response tokens: including the prompt adds the same constant to both sides of each ratio and does nothing but cost precision, and averaging instead of summing changes the objective. Implementations differ on the standard deviation in GRPO (PyTorch's std divides by n − 1 by default; the worked example above uses the population value) and on how token losses are averaged across responses of different lengths. Track the implicit-reward accuracy and margins during DPO, and the KL and reward during PPO: a KL that climbs while held-out human or gold-model preference stalls is the reward-hacking signal.

Tradeoffs

MethodDataModels in memorySamples during trainingWeak spots
RLHF (reward model + PPO)pairs or rankingspolicy, reference, reward model, value modelyes, on-policymany hyperparameters, unstable, expensive; the reward model can be reused and inspected
DPOpairspolicy, reference (or stored reference log-probs)no, offlineoverfits unanimous or noisy pairs; can lower the likelihood of both responses; limited to the data's responses
IPOpairsas DPOnoa target margin to tune; same offline limits
KTOsingle responses labelled good or badas DPOnoweaker signal per example than a pair; desirable/undesirable weights to tune
GRPOprompts plus a reward function or modelpolicy, reference, reward if learnedyes, a group per promptprompts that are all-right or all-wrong give no signal; needs a reward that is hard to game
  • Online or offline. PPO and GRPO learn from the current policy's own samples, so they can correct mistakes the dataset never showed; DPO, IPO and KTO only reweight responses already in the data. Iterated DPO, with fresh pairs from the current policy each round, closes part of that gap.
  • β sets the leash. Small β lets the policy move far, which the sweep above shows can buy proxy reward at the expense of real quality; large β changes little. It is the main hyperparameter in every method here.
  • The data decides what "preferred" means. Labeler instructions, the people chosen and their biases toward length or confidence all end up in the reward. No loss function fixes a preference dataset that rewards the wrong thing.
A DPO run shows rising reward accuracy and margins, but the log-probability of the chosen responses is falling. Is something broken?

Not necessarily. The loss only sees the difference of log ratios, so it can be satisfied by pushing the rejected response down faster than the chosen one falls. Probability mass leaves both and goes to responses in neither, which can be good or bad. Watch quality on held-out prompts, and consider a larger β, fewer epochs, or adding a supervised term on the chosen responses.

Why can't you skip the KL term and just maximize the reward model's score?

The unregularized optimum puts all probability on whatever response the reward model scores highest, and the reward model is only accurate near the responses it was trained on. The policy finds the reward model's mistakes, as in the β = 0.05 row of the sweep, where proxy reward is highest and true reward lowest. The KL term also makes DPO possible: without it there is no closed-form optimum to invert.

Connections

Read first

Read next

No page builds on this one yet.

This page continues fine-tuning, which produces the reference policy, and reinforcement learning, which builds policy gradients and PPO's clipped ratio. The reward model is logistic regression on a reward gap, trained with cross-entropy, and every log π(y|x) is the quantity pretraining maximizes for a decoder-only model. The KL penalty is the entropy and KL divergence page put to work.

References