Part 3 · Chapter 15

Learning from preferences

When there is no right answer to copy, learn from which answer people liked more.

Where we are

Chapter 14 turned the base model into something that answers in turns, by copying demonstrations: supervised fine-tuning with the same −ln p loss as pretraining, billed only on assistant tokens. That works exactly as far as you can write down the answer you want. For most of what makes an assistant good (tone, honesty, when to hedge, when to refuse, how long to be) nobody can write the ideal answer, but almost anyone can say which of two answers is better. This chapter is about turning that judgement into gradient. It sits on the map as the second stage of post-training; Chapter 16 extends the same machinery to rewards that can be checked rather than judged, and Chapter 17 asks what the judgements should be.

The question this chapter answers: how does "response A is better than response B" become a change in θ, and what goes wrong when you push that too hard?

Picture this

A restaurant with a new chef. You cannot hand the chef a recipe for "food our customers love", because you do not have one. What you can do is this: every evening, send out two versions of a dish to the same table and ask which they preferred. Thousands of tables, thousands of pairs.

From those votes you build a critic: a maître d' who has tasted everything and can now predict, for any new plate, how the tables would score it. Then the chef cooks against the critic. Make a dish, get a score, adjust, repeat, far faster than waiting for real tables.

Two things go wrong, and both are the heart of this chapter. First, the critic learned from a finite set of votes and has blind spots; a chef who chases the critic's score hard enough will find them, and start cooking dishes the critic adores and the tables hate. Second, a chef who drifts too far from what they were trained to cook becomes unrecognisable, and the critic's opinions of dishes nobody voted on are worthless. So you keep the chef on a leash: score minus a penalty for straying from the original menu.

And there is a shortcut. If the leash is fixed in advance, you do not need a separate critic at all. You can compare two dishes directly against how much the chef has drifted on each, and it turns out to be the same lesson. That shortcut is called DPO.

Map it
In the pictureIn the machineThe word we will use
Which of two plates the table preferredA prompt with a chosen and a rejected responsepreference pair (x, y_w, y_l)
"They prefer this one 70/30"Preference probability as a sigmoid of a score differenceBradley–Terry model
The maître d' who predicts the voteA network scoring (prompt, response) with one number, trained on pairsreward model r(x, y)
The chef being coachedThe model whose θ is being updatedpolicy π_θ
The original menuA frozen copy of the model before this stagereference π_ref
The leashA penalty on how far the policy's distribution has moved from the referenceKL penalty, coefficient β
Cook, score, adjustSample from the policy, score with the reward model, update by policy gradientRLHF with PPO
The chef finding the critic's blind spotsThe policy exploiting reward-model errors; proxy up, true quality downreward hacking, over-optimisation
Skipping the critic, comparing plates directlyA loss on pairs that uses the policy's own log-probabilities as the scoreDPO (direct preference optimisation)

15.1What a preference is

Start with the data, because the data is the whole idea. A rater sees one prompt and two responses, and picks one. That is a preference pair: (x, y_w, y_l) for prompt, winner, loser. Nothing else is recorded in the basic form: no score, no explanation, no "the right answer". Just which.

Why pairs and not scores? Because people are bad at absolute scales and good at comparisons. Ask ten raters to score a response from 1 to 10 and you get ten calibrations. Ask them which of two is better and they mostly agree. Comparisons are also cheap: a rater can compare two Dispatch responses to a pager alert in seconds, without knowing what the right runbook is. And a comparison carries information even when both responses are bad, which is most of them early on.

To turn pairs into something a model can be trained on, you need a way to say what a pair means. The standard model, older than any neural network, is Bradley–Terry: every response has a hidden score, and the probability that one beats another is a sigmoid of the score difference.

Math box · Bradley–Terry
p(y_w ≻ y_l | x)  =  σ( r(x, y_w) − r(x, y_l) )        σ(z) = 1 / (1 + e^(−z)), the same curve as one softmax entry over two options

equal scores      →  p = 0.5        a coin flip
r_w − r_l = 1     →  p = 0.73
r_w − r_l = 3     →  p = 0.95

Only differences matter; adding a constant to every score changes nothing. Fitting the scores to a pile of comparisons is a maximum-likelihood problem: choose r to make the observed winners as probable as possible, which is exactly −ln σ(r_w − r_l) summed over pairs, the same shape of bill as Chapter 1's −ln p. Its gradient is −(1 − p) on the winner's score and +(1 − p) on the loser's: push them apart in proportion to how surprising the vote was.

Static view of the widget. Four Dispatch responses and ten votes. Fitting gives scores A 1.17, B 0.51, C −0.51, D −1.17, so p(A beats B) = 0.66 and p(C beats D) = 0.66: equal gaps, equal odds. Adding a vote for D over A pulls D up and A down and shrinks every gap.
$ python code/ch15/bradley_terry.py
fitted scores: {'A': 1.17, 'B': 0.51, 'C': -0.51, 'D': -1.17}
p(A beats B) = 0.66   p(C beats D) = 0.66
mean log-likelihood of the comparisons: -0.515 (uniform would be -0.693 )

Where the votes come from

Three sources, all used by published pipelines public:

Two details about the data that determine everything downstream. First, comparisons are most informative when the two responses come from the current policy and differ in ways that matter; pairs where one response is obviously broken teach nothing after the first round. Second, whatever the raters reward, they will get more of: length, confidence, flattery, formatting. Every known pathology of assistant behaviour has a preference dataset behind it.

15.2The reward model

Bradley–Terry with a table of scores only works for responses you have votes on. The point is to score responses nobody voted on: the ones the policy will produce during training. So replace the table with a function: a copy of the language model with the unembedding removed and a single output number added, reading (x, y) and producing r(x, y). Train it on the pairs with the Bradley–Terry loss:

L_RM = −ln σ( r_φ(x, y_w) − r_φ(x, y_l) )

Everything from Chapter 5 applies unchanged: the loss has a slope, the slope backpropagates through the whole transformer, and after a few thousand steps the model's final hidden state at the last token is a vector whose projection is "how much would a rater like this". The reward model is a language model that has been taught to read like a rater.

x + y_w (chosen)tokens x + y_l (rejected)tokens transformer φsame blocks as Chapter 4W_U removed scalar head[C] → 1 number r_w = 1.8 r_l = 0.6 loss = −ln σ(r_w − r_l)= −ln σ(1.2) = 0.26 gradient: push r_w up and r_l down by (1 − σ) = 0.23, through every block
What is a reward model, structurally? The same transformer with the vocabulary head swapped for a single-number head, fed both responses of a pair and trained to score the chosen one higher. Backpropagation runs through the whole network exactly as in Chapter 5; only the bill at the top has changed.

It has the weaknesses of a model trained on finite data. It has seen comparisons in a particular distribution of responses and generalises unreliably outside it. It learns surface correlates of preference (longer, more confident, more bullet points) as readily as the substance. And it can be probed by anything that generates responses and reads its score, which is precisely what the next step does.

Scale note. Llama 3's reward model was trained on top of the pretrained checkpoint with the pairs collected each round, and was used both for rejection sampling and as a filter, not for PPO public. InstructGPT trained a 6B reward model to guide 175B policies public. Closed labs do not say what size their reward models are or how many they use unknown.

15.3RLHF with PPO: cook, score, adjust

With a reward model in hand, the obvious move is to make the policy produce responses that score highly. This is reinforcement learning in the plain sense: the policy acts (generates a response), the environment scores it (the reward model), and the policy is updated to make high-scoring actions more likely. The objective every published pipeline optimises has two terms:

Math box · the RLHF objective
maximise over θ:    E_{x ~ prompts, y ~ π_θ(·|x)} [ r_φ(x, y) ]  −  β · KL( π_θ(·|x) ‖ π_ref(·|x) )

first term:   average reward of what the policy generates              (the critic's score)
second term:  how far the policy's distribution has moved from the reference, per prompt   (the leash)
β:            the price of straying, typically 0.01–0.1 in published work

KL divergence between two distributions over responses is the average, under the policy, of ln π_θ(y|x) − ln π_ref(y|x): how many extra nats the policy assigns to what it now says, compared with what it used to say. Zero when nothing has changed; growing as the policy concentrates on responses the reference found unlikely. In practice it is estimated per token of the sampled response and subtracted from the reward, so the "shaped" reward the algorithm sees is r − β(ln π_θ − ln π_ref).

Why the leash? Two reasons, both about the reward model's limits. Away from the reference distribution the reward model's scores are extrapolations it was never trained on; the KL term keeps the policy where the scores mean something. And the reference is the SFT model, which already knows how to write; without the leash the policy can trade fluency for score and produce text that is high-reward and unreadable.

The algorithm that does the maximising is almost always PPO (proximal policy optimisation) public. You do not need its internals to reason about frontier post-training, but you do need to see what one step costs, because that cost shapes what labs do.

Static view of the widget. Four models: policy (trained), reference (frozen), reward model (frozen), value model (trained). One step: the policy decodes a response; the reward model scores it 1.8; the reference gives the KL term 0.24; the value model's estimate 1.2 is subtracted to give an advantage of +0.36; PPO raises the log-probability of the response in proportion, with a clipped ratio so the step stays small.

Count what one sample costs. A full decode loop from the policy (Chapter 7: one forward pass per token, memory-bound). A forward pass of the reward model over the result. A forward pass of the reference for the KL term. A forward pass of a fourth model, the value model, which predicts the expected reward from the prompt so that the update can be scaled by "better or worse than expected" (the advantage) rather than by raw reward. Then a backward pass through the policy and one through the value model. Four models in memory, of which two are being trained with full optimiser state (Chapter 5: 16 bytes per parameter each). For a 70B policy that is over two terabytes before activations, plus generation at serving speed for every sample. RLHF with PPO is the most expensive thing in post-training by a wide margin, and it is why the shortcut in the next section was adopted so quickly.

Why PPO specifically, rather than the raw policy gradient? Because a policy gradient step of the wrong size can destroy the policy in one update, and language models are large enough that you cannot afford to find out by trying. PPO computes the ratio of the new policy's probability of the sampled response to the old policy's, and clips it to a band around 1, so no single step can move any response's probability by more than a set fraction. It is a trust region done cheaply. Chapter 16 introduces a variant, GRPO, that drops the value model.

15.4Reward hacking and over-optimisation

Now the chef finds the critic's blind spots. The policy is being optimised against a learned function, and optimisation finds errors in learned functions the way water finds cracks. The reward model gives slightly higher scores to longer responses, because raters slightly preferred them; the policy becomes verbose. The reward model has never seen a response that says "I've verified this carefully" followed by nonsense, so it scores the phrase highly; the policy learns the phrase. Every such crack is a place where the proxy reward keeps rising while the thing it was meant to measure falls.

Static view of the widget. As KL from the reference grows, the reward model's score (orange) rises monotonically while the rating by real people (green) rises, peaks near KL 10–20 nats for a medium-quality reward model, and then falls. A reward model trained on more data pushes the peak further out and higher. Stopping at KL 20 with a weak reward model is past its peak; with a strong one it is still climbing.

The shape of those curves was measured systematically by Gao, Schulman, and Hilton in 2022, using a large "gold" reward model as a stand-in for humans and smaller proxies trained on its labels public: gold reward as a function of KL follows a rise-then-fall whose peak moves right and up with reward-model size and data, and PPO over-optimises faster per nat of KL than rejection sampling does. The practical lessons every pipeline applies:

Reward hacking is not a bug in an implementation. It is what optimisation against an imperfect objective does, and every method in this chapter and the next is an arrangement for optimising less hard, or against a better objective, or with a shorter leash. Chapter 17 returns to it as the central problem of alignment: the reward is always a proxy for what you actually wanted.

15.5DPO: skipping the critic

Look again at the RLHF objective. Reward minus a KL leash, with a fixed β. In 2023 Rafailov and colleagues noticed that this objective has a closed-form optimum public: the best policy is the reference, reweighted by the exponentiated reward,

π*(y|x) ∝ π_ref(y|x) · exp( r(x, y) / β )

Turn that around. If you know the optimal policy and the reference, you can recover the reward that produced it: r(x, y) = β · ln( π*(y|x) / π_ref(y|x) ), up to a per-prompt constant that cancels in comparisons. So the policy itself is a reward model in disguise: how much more likely it makes a response than the reference did, times β, is a score. Substitute that score into the Bradley–Terry loss, and you get a loss on preference pairs that mentions no reward model at all:

Math box · the DPO loss
L_DPO(θ)  =  −ln σ(  β · [ ln π_θ(y_w|x) − ln π_ref(y_w|x) ]  −  β · [ ln π_θ(y_l|x) − ln π_ref(y_l|x) ]  )
                     └─── how much the chosen got more likely ───┘     └── how much the rejected got more likely ──┘

margin  =  β · (shift_chosen − shift_rejected)          loss = −ln σ(margin)

gradient:  −β · σ(−margin) · [ ∇ ln π_θ(y_w|x) − ∇ ln π_θ(y_l|x) ]
           push the chosen up and the rejected down, weighted by how wrong the current ranking is

Each ln π(y|x) is the sum of per-token log-probabilities of the response given the prompt, computed with one forward pass under teacher forcing (Chapter 7), the same way SFT computes its loss. Two forward passes of the policy (chosen, rejected), two of the frozen reference (which can be precomputed once), one backward pass. No sampling, no reward model, no value model.

By hand

One pair. The prompt is a Postbox pager alert; the chosen response gives three ordered checks, the rejected one says "restart the workers". Under the current policy and the frozen reference, the summed log-probabilities are:

                       log π_θ      log π_ref     shift = θ − ref
chosen   y_w           −12.0        −12.5           +0.5     (policy already finds it a little more likely than the reference did)
rejected y_l           −13.0        −12.2           −0.8     (policy finds it less likely)

β = 0.1
margin   = 0.1 × ( +0.5 − (−0.8) ) = 0.1 × 1.3  = 0.130
σ(0.130) = 0.5325                                   the model's implied belief that chosen ≻ rejected
loss     = −ln 0.5325                = 0.630
push     = β · σ(−0.130) = 0.1 × 0.4675 = 0.0468   the weight on ∇ln π_θ(y_w) − ∇ln π_θ(y_l)

for comparison, before any training (θ = ref): margin 0, loss ln 2 = 0.693, push 0.05
$ python code/ch15/dpo_by_hand.py
shift chosen   = +0.50   (log π_θ − log π_ref)
shift rejected = -0.80
margin         = β·(shift_chosen − shift_rejected) = 0.1·1.30 = 0.130
σ(margin)      = 0.5325   ← implied p(chosen ≻ rejected)
loss           = −ln σ(margin) = 0.6303
gradient weight= β·σ(−margin) = 0.0468   (how hard this pair pushes)

at the start, θ = ref: margin 0, loss = ln 2 = 0.6931
margin 0.5: loss 0.4741, push weight 0.0378
margin 1.0: loss 0.3133, push weight 0.0269
margin 2.0: loss 0.1269, push weight 0.0119
margin 4.0: loss 0.0181, push weight 0.0018

Read the last four lines. As the margin grows the push fades: once the model ranks a pair confidently, that pair stops moving θ. This is the sigmoid's saturation, the same property that made p − onehot vanish for confident correct predictions in Chapter 5. It is also why DPO's β is a leash: the shifts are measured in nats relative to the reference, and a small β means a large shift is needed before a pair counts as confidently ranked, so the policy keeps moving.

Notice too what the margin does not reward: making the chosen response likely in absolute terms. Both log-probabilities can fall, and the loss still drops as long as the rejected one falls faster. Published analyses confirm that DPO often lowers the probability of both responses public, which is one reason SFT on chosen responses usually precedes it.

Static view of the widget. Loss −ln σ(margin) against margin, with the pair from the by-hand example marked at margin 0.13, loss 0.63. Dragging the chosen shift up to +2.0 with β = 0.1 gives margin 0.28 and loss 0.57; raising β to 0.5 at the same shifts gives margin 1.4 and loss 0.22.
RLHF with PPO policy π_θ decode y RM π_ref: KL value V PPO update from r − β·KL − V 4 models · 2 trained · a decode loop per sample on-policy: learns from its own samples DPO pair (x, y_w, y_l) policy π_θ π_ref (frozen) ln π on both −ln σ(β·margin) 2 models · 1 trained · forward passes only off-policy on a fixed set; on-policy across rounds
What is different in the room? PPO keeps four models and a generation loop alive; DPO keeps two and needs only teacher-forced forward passes. The leash (β) and the direction of the push are the same in both.

What DPO gives up

DPO learns only from the pairs it is given. PPO generates its own samples and learns from what the reward model says about them, which means it explores responses that no rater ever saw and can discover behaviours the pairs do not contain. That distinction has a name, and it matters more than the algorithms do:

The compromise most published pipelines settle on is iterated DPO: sample from the current policy, have raters (or a reward model, or a judge) compare the samples, run DPO on the new pairs, repeat. Each round is off-policy within itself and on-policy across rounds. Llama 3 did six rounds of exactly this, with rejection sampling to build the SFT set and DPO on pairs from the latest checkpoints public.

The family

Once the trick was seen, variants followed, each changing what the loss asks for public:

MethodChangesWhy
DPO−ln σ(β·margin)the original; matches Bradley–Terry
IPO(margin − 1/(2β))² instead of the log-sigmoidthe sigmoid never saturates on noisy labels; a squared target stops pushing at a fixed margin
KTOloss on single responses labelled good or bad, no pairsthumbs-up/down data is far more plentiful than pairs
ORPOadds an odds-ratio preference term to the SFT loss, no reference modelone stage instead of two, half the memory
SimPOlength-normalised log-probability as the reward, no referenceremoves the length bias DPO inherits from summing token log-probs

The differences are real but second-order. All of them are "push chosen up, rejected down, with some leash", and all inherit the same dependence on the quality and distribution of the pairs.

15.6What published pipelines actually do

Three documented recipes, so the abstractions have referents public:

PipelineStagesData scaleNotes
InstructGPT (2022)SFT → reward model → PPO13k SFT prompts, 33k comparison prompts, 31k RL promptsthe reference recipe; 1.3B RLHF model preferred over 175B base
Llama 3 (2024)reward model → rejection sampling → SFT → DPO, six roundsmillions of human comparisons plus synthetic data across roundsno PPO; DPO with the reference reset each round; masks formatting tokens in the DPO loss
Tülu 3 (2024, open)SFT → DPO → RL with verifiable rewards≈1M SFT, ≈270k preference pairs, all releasedthe fully reproducible recipe; Chapter 16 picks up its last stage
Closed frontier labsthe same stages are described in outline; specifics, sizes, and roundsunknown
policy_kround k sample K per xon-policy score with RM_k+ human comparisons best → SFT setbest vs worst → pairs SFT, DPOref := policy_k policy_k+1 retrain RM_k+1 on the new comparisons; go again (Llama 3: six rounds)
Why rounds? Each round's samples come from the newest policy, so the comparisons and the reward model stay current with what the model actually produces. The reference is reset each round so the leash measures drift within the round, not from the original SFT model.

Two patterns stand out. First, the reward model survives even where PPO does not: Llama 3 uses it for rejection sampling and filtering, because a scorer is useful for selecting data whether or not you run RL against it. Second, everyone iterates. The reason is in §15.4: a round of optimisation moves the policy to where the previous round's comparisons are stale, and the fix is new comparisons.

15.7Beacon's numbers

QuantityLlama 3 (405B post-training)Evidence
Preference rounds6public
Preference optimiserDPO, β = 0.1, learning rate 10⁻⁵public
Reward model userejection sampling and data filtering, not PPOpublic
Comparisons per roundhundreds of thousands, human and synthetic, multi-turnpublic (order of magnitude)
Closed frontier modelssame stages in outline; whether PPO, DPO, or both; β; roundsunknown
Back of the envelope

What does one DPO step cost versus one PPO step, for a 405B policy? Count forward and backward passes per training example, in units of "one forward pass of the policy over one response" (Chapter 5: backward ≈ 2× forward).

DPO, one pair (chosen + rejected, ≈ 500 tokens each)
  policy forward on both        2 F
  reference forward (cacheable) 2 F   → precompute once per dataset, ≈ 0 per epoch after that
  policy backward               4 F
  total                         ≈ 6 F  (≈ 8 F including reference on the first epoch)
  models in memory: policy with optimiser state (16 B/param) + reference (2 B/param)  ≈ 7.3 TB

PPO, one sample (≈ 500 tokens)
  policy DECODE of 500 tokens   500 sequential steps, each reading all weights: memory-bound, ≈ 10–50× the wall-clock of one parallel forward
  reward model forward          1 F
  reference forward             1 F
  value model forward           1 F
  policy backward + value backward   4 F
  total arithmetic              ≈ 7 F + the decode loop
  models in memory: policy + value with optimiser (32 B/param) + reference + reward (4 B/param)  ≈ 14.6 TB

  ⇒ PPO needs about twice the memory and, because of the decode loop, several times the wall-clock per example.

This is why a lab with a fixed post-training budget runs many rounds of DPO instead of one run of PPO, and why the decode loop's efficiency (Chapter 19) turns out to matter for training as much as for serving. It is also why Chapter 16's methods, which need on-policy samples, invest in making generation cheap.

Break it

Remove the KL leash (β = 0). The policy optimises the reward model's score with nothing holding it near the reference. Within a few hundred steps it finds the cracks: responses become long, repetitive, full of whatever tokens the reward model overvalues, and the reward model's score keeps climbing as human ratings collapse. Published runs without the penalty degenerate to unreadable text public. The leash is not a regulariser you can tune away; it is what keeps the critic's opinions meaningful.

Train the reward model once and never refresh it. The first round works. By the second, the policy produces responses unlike anything the reward model was trained on, and its scores are extrapolations. Optimisation against extrapolations is over-optimisation by construction. Every published pipeline retrains or re-collects each round for this reason.

Use absolute scores instead of pairs. Rater calibration varies from person to person and day to day; a 7 from one rater is a 4 from another. The reward model learns rater identity instead of quality. Pairs cancel the calibration: the same rater judged both responses at the same moment. Where scores are used at all, they are usually converted to pairs first.

Run DPO for many epochs on a fixed dataset. The margins grow until every pair is confidently ranked, the push fades to zero, and the policy has moved far from the reference toward whatever separates chosen from rejected in that particular dataset, including its accidents (length, phrasing, the raters' tics). Held-out preference accuracy peaks after one to two epochs and then falls public. Pairs are consumed, not studied.

Collect pairs only from an old model and never from the policy being trained. Pure off-policy. The policy learns to rank those pairs correctly, which says nothing about the responses it now actually generates; its own failure modes are never compared, so never corrected. Improvement stalls after the first round. On-policy samples are what make later rounds worth running.

Rebuild the model

Say it back. When you cannot write the answer you want, you can still say which of two answers is better, so the data becomes pairs: prompt, chosen, rejected. Bradley–Terry turns pairs into a scale: the probability of preferring one response over another is a sigmoid of a score difference, and fitting scores to votes is a −ln σ loss with the same push-apart gradient as every other bill in this book. A reward model is that scale made into a function: a transformer with a scalar head, trained on pairs, that reads any response like a rater would. RLHF then generates responses from the policy, scores them, subtracts a KL leash so the policy stays where the scores mean something, and updates by PPO in clipped steps; it costs four models, two of them training, and a full decode loop per sample. Push it too hard and the policy finds the reward model's blind spots: proxy reward rises, real preference falls, and the KL at which that happens is set by the reward model's quality. DPO removes the reward model by noting that the leashed objective's optimum makes the policy's own log-probability ratio against the reference a reward; its loss is −ln σ of β times the difference in those ratios between chosen and rejected, computed with forward passes and no sampling. DPO on fixed data is off-policy and learns only what the pairs contain; PPO is on-policy and can exceed the data at the cost of exploiting the critic. Labs iterate: sample from the current policy, compare, optimise, repeat, refreshing the reward model as they go. Beacon's published relative ran six such rounds of DPO at β = 0.1 with rejection sampling in between.

promptsx sample pairsfrom the current policy ratehumans / AI / RM push apart, on a leashPPO + RM or DPO, both with β·KL new policy π_θcheck on held-out humans next round: resample, re-rate, reset the reference (Llama 3: six times) the leash is what keeps the critic's scores meaningful; the rounds are what keep the critic current
What is the whole chapter in one line? Sample, compare, push chosen up and rejected down on a KL leash, check with real people, repeat. The reward model is optional; the leash and the rounds are not.
Exercises
  1. By hand. Redo the DPO example with the rejected response's shift changed to +0.9 (the policy has made the rejected response more likely than the reference did). Compute the margin, σ, the loss, and the push weight. Then set β = 0.5 and recompute. In one sentence, why does the push weight rise in the first change and fall in the second?
  2. Calculation. A lab has budget for 2 × 10⁶ "policy-forward-equivalents" of compute for post-training a 70B model. Using the back-of-envelope costs, how many DPO pairs can it train on, and how many PPO samples, if a PPO sample's decode loop costs the equivalent of 20 forward passes? If human comparisons cost $2 each and the lab has a $500k rating budget, which is the binding constraint for the DPO route, compute or data? What about for PPO, where the reward model replaces the rater after the first 250k pairs?
  3. Code. Extend bradley_terry.py: add a fifth response E that beats everything in 3 votes but loses to D once. Print the fitted scores. Then simulate a "reward hacker": a response F that the votes rate above E but whose only feature is length, and show how the fitted scale rewards it. Finally, write a function dpo_loss(logp_theta_w, logp_ref_w, logp_theta_l, logp_ref_l, beta) and reproduce the table of losses and push weights from dpo_by_hand.py.
Further reading