Instruction Tuning and RLHF

You will understand why a freshly pre-trained model is a completion engine rather than an assistant, and how three short training stages (supervised fine-tuning, a reward model, and reinforcement learning with a leash) turn it into one. You will also see the shortcut, DPO, that skips the middle stage.

Suppose you have just finished the previous chapters and trained a language model on a big pile of internet text. The loss is low. You type "What is the capital of France?" and press enter. What comes out?

Very likely not "Paris". A base model has learned to continue text the way the internet continues text, and on the internet a question like that is most often followed by more questions (it is a quiz page), or by a comment thread, or by "Answer:" and then the answer. The model does not know that you are asking and that it should answer. It is not being obstinate; nobody has told it what its job is.

This chapter is about telling it. The methods here are a short overview; each has its own deep dive in the Post-Training and Advanced parts of the course. The goal now is to see the whole recipe end to end, with enough math to know what each stage is actually optimizing.

The problem: a completion engine is not an assistant

What a base model does with a question

Here is a typical continuation you get from a base model such as GPT-2 when you feed it a bare question (sampled with top-p 0.9; the exact text varies, the pattern does not):

What is the capital of France?
What is the capital of Germany? What is the capital of Italy?
What is the largest city in Spain? Answer these questions in
complete sentences and hand in your worksheet by Friday.

Nothing is wrong with this as a prediction. It is a plausible next chunk of a document that starts that way. The mismatch is between what the model is optimizing (likelihood of the next token under the training distribution) and what we want (a helpful reply to the person typing).

Prompting is a stopgap

You can coax a base model into answering by writing the document you wish existed: "Q: What is the capital of France? A:" and letting it fill in. Few-shot prompting, where you show a couple of worked question-answer pairs first, works even better. But it is fragile, it burns context on examples, and it does nothing about the model's willingness to produce harmful text if the document seems to call for it. We want the assistant behavior baked into the weights.

Intuition

Pre-training teaches the model everything the internet knows and every voice the internet speaks in. Post-training does not add knowledge; it picks a voice. Think of it as hiring someone brilliant who has read everything and then spending a week explaining what the job is.

The three-stage recipe

The recipe that made ChatGPT possible was laid out in Ouyang et al. (2022), the InstructGPT paper, building on earlier work on learning from human preferences (Christiano et al., 2017; Ziegler et al., 2019; Stiennon et al., 2020). It has three stages, each taking the output of the previous one.

base modelnext-token on web text 1. SFT modelimitate demonstrations 3. RL policymaximize reward − β·KL 2. reward modelfrom pairwise preferences SFT samples → humans rank SFT model also serves asthe frozen reference π_ref Stage 1 → 2 → 3. Each stage starts from the previous stage's weights.
Figure 1. The InstructGPT pipeline. Stage 1 fine-tunes on human-written answers. Stage 2 trains a separate model to score answers, using human rankings of the SFT model's outputs. Stage 3 uses that score as a reward to fine-tune the SFT model further, while a KL penalty keeps it close to where it started.
Symbols
$x$ = prompt
$y$ = response
$\pi_\theta$ = the policy (model being trained)
$\pi_{\text{ref}}$ = frozen SFT model
$r_\phi(x,y)$ = reward model score
$\beta$ = KL penalty strength
STEP 1
SFT
Collect prompts with human-written ideal responses. Fine-tune with next-token loss on the response tokens only.
STEP 2
Reward model
Sample several responses per prompt, have humans rank them, train $r_\phi$ so that preferred responses score higher (Bradley–Terry).
STEP 3
RL
Sample responses from $\pi_\theta$, score them with $r_\phi$, subtract $\beta\log(\pi_\theta/\pi_{\text{ref}})$, and update $\pi_\theta$ with PPO to raise the penalized reward.

Stage 1: Supervised fine-tuning on demonstrations

The problem to solve first: the model has never seen a conversation formatted as a conversation. So we show it thousands of them. Humans (or, increasingly, stronger models) write prompts and ideal responses, we format each pair as a chat transcript, and we fine-tune the base model with exactly the next-token loss from the previous chapter. Nothing new in the loss; everything new is in the data and its formatting.

The chat template and special tokens

A conversation has structure: who is speaking, where a turn starts, where it ends. Plain text does not carry that, so we add special tokens, new entries in the vocabulary that never appear in natural text, to mark the boundaries. Each model family has its own convention, called its chat template. Two common ones:

<|im_start|>system
You are a helpful assistant.<|im_end|>
<|im_start|>user
What is the capital of France?<|im_end|>
<|im_start|>assistant
The capital of France is Paris.<|im_end|>
<|begin_of_text|><|start_header_id|>system<|end_header_id|>

You are a helpful assistant.<|eot_id|><|start_header_id|>user<|end_header_id|>

What is the capital of France?<|eot_id|><|start_header_id|>assistant<|end_header_id|>

The capital of France is Paris.<|eot_id|>

The end-of-turn token (<|im_end|> or <|eot_id|>) is the most important one. At inference we generate until the model emits it; that is how the model learns to stop. A model fine-tuned without it will ramble until the context fills.

Loss masking: learn the answer, not the question

Here is a subtlety that catches people. If we apply the loss at every position, the model spends effort learning to predict the user's words: what questions people ask, in what phrasing. We do not want that; we want it to learn to respond. So we mask out the prompt tokens from the loss and train only on the assistant's tokens (including the end-of-turn token).

Concretely, the loss is the usual average of $-\log p$, but only over the set $A$ of assistant positions:

$$\mathcal{L}_{\text{SFT}} = -\frac{1}{|A|}\sum_{t \in A} \log \pi_\theta(x_{t+1} \mid x_{\le t})$$

The prompt tokens still go through the forward pass, because the assistant tokens attend to them. They just contribute zero to the loss. In PyTorch this is done by setting the target to -100 at masked positions; F.cross_entropy ignores that label by default.

Worked example

Take a tiny conversation whose tokens are (one token per word for simplicity):

<|im_start|> user ↵ What is 2+2 ? <|im_end|> ↵ <|im_start|> assistant ↵ 4 <|im_end|>

Fourteen tokens, so thirteen next-token predictions. With prompt masking, only two of them count: predicting 4 after assistant ↵, and predicting <|im_end|> after 4. If the model gives those probabilities $0.30$ and $0.80$, the loss is $-(\ln 0.30 + \ln 0.80)/2 = (1.204 + 0.223)/2 = 0.71$ nats. The eleven prompt predictions do not matter, however badly the model does on them.

InteractiveChat-template builderedit the turns, switch template

Type a system prompt, a user turn and an assistant turn. The rendered transcript is split into token-like chips: special tokens in purple, prompt tokens greyed out (masked from the loss), and the assistant's tokens in amber (they are the only ones that train the model).

Common confusion

SFT does not "teach the model facts". Its data is tiny compared to pre-training (tens of thousands of examples versus trillions of tokens), and the fine-tuning is short. What it changes is the format of the output and the persona. If the base model did not know the capital of France, SFT on a few thousand chat examples will not fix that; it may just make the model confidently say something wrong in a polite tone.

The full treatment of SFT, including data mixing, multi-turn masking, packing and instruction datasets like FLAN (Wei et al., 2021), is in Supervised Fine-Tuning.

Stage 2: A reward model from human preferences

After SFT the model answers questions. Now the problem shifts: some of its answers are better than others, and we would like more of the good ones. But "good" is hard to write down as a loss. It involves tone, correctness, safety, length, honesty. What we can do is show two answers to a person and ask which they prefer.

Why comparisons and not scores

You might ask humans to rate each answer from 1 to 10. In practice people are inconsistent about absolute scores (one rater's 7 is another's 4) but fairly consistent about which of two answers is better. So InstructGPT collects rankings of several responses to the same prompt, breaks them into pairs, and trains a model on the pairs.

The Bradley–Terry model

We want a function $r_\phi(x, y)$ that gives a real-valued score to a response. To connect scores to pairwise choices we need a model of how a score difference turns into a probability of being preferred. The Bradley–Terry model (1952) says: the probability that $A$ beats $B$ is the sigmoid of the score difference.

$$P(y_A \succ y_B \mid x) = \sigma\big(r_\phi(x,y_A) - r_\phi(x,y_B)\big) = \frac{1}{1 + e^{-(r_A - r_B)}}$$

If the scores are equal the probability is $0.5$; if $A$ scores one unit higher, $A$ is preferred with probability $0.73$; three units higher, $0.95$. Only the difference matters, so scores have no absolute meaning.

Training the reward model is then maximum likelihood on the human labels. If the human preferred $y_w$ ("winner") over $y_l$ ("loser"), we want $P(y_w \succ y_l)$ to be high, so the loss is its negative log:

$$\mathcal{L}_{\text{RM}} = -\log \sigma\big(r_\phi(x,y_w) - r_\phi(x,y_l)\big)$$

This pushes the winner's score up and the loser's down until the gap is large, with gradients that shrink once the model already agrees with the human. It is cross-entropy again, just on a two-way choice.

Worked example

Prompt: "Explain photosynthesis in one sentence." Response A gets $r_A = 1.2$ and response B gets $r_B = 0.4$ from the current reward model.

$P(A \succ B) = \sigma(1.2 - 0.4) = \sigma(0.8) = 1/(1 + e^{-0.8}) = 1/(1 + 0.449) = 0.690$.

If the human labeled A as preferred, loss $= -\ln 0.690 = 0.371$. If the human preferred B instead, loss $= -\ln(1 - 0.690) = -\ln 0.310 = 1.171$, and the gradient will push $r_B$ up and $r_A$ down.

What the reward model is

The reward model is usually a copy of the SFT model with the unembedding replaced by a single linear layer that outputs one number, read at the final token. It reads the full transcript, prompt and response, and emits a scalar. Starting from the SFT weights matters: the reward model needs to understand language to judge it.

InteractiveBradley–Terry reward playgrounddrag the two scores

Two responses, two reward scores. See the preference probability and the reward-model loss when the human says A is better. Notice that only the gap $r_A - r_B$ matters: shift both sliders together and nothing changes.

Stage 3: RL fine-tuning with a KL leash

Now we have a policy that can answer and a reward model that can judge. The natural move: generate answers, score them, and update the policy to make high-scoring answers more likely. This is reinforcement learning: the prompt is the state, the response is the action, and the reward model provides the reward. Ouyang et al. used PPO (Schulman et al., 2017); the exact algorithm is treated in RL Fundamentals and RLHF Deep Dive.

The objective

Here is what stage 3 maximizes, written in full. Take a prompt $x$ from the dataset, sample a response $y$ from the current policy, and compute:

$$\mathcal{J}(\theta) = \mathbb{E}_{x \sim D,\ y \sim \pi_\theta(\cdot \mid x)}\Big[\, r_\phi(x, y) \;-\; \beta \log \frac{\pi_\theta(y \mid x)}{\pi_{\text{ref}}(y \mid x)} \Big]$$

In words: the expected reward of the policy's own responses, minus $\beta$ times how much more likely the policy finds its response than the frozen SFT model does. The second term, averaged over samples, is the KL divergence $\text{KL}(\pi_\theta \,\|\, \pi_{\text{ref}})$; it is zero when the policy has not moved and grows as the policy drifts. The InstructGPT paper adds a third term, a small amount of the original pre-training loss, to limit forgetting.

Each step: sample a batch of responses, score them, compute the per-token penalized rewards, and take a PPO update that raises the log-probability of responses that scored above expectation and lowers the others, clipped so no single step moves the policy too far.

Why the KL term exists

Why not just maximize the reward? Because the reward model is not the truth; it is a neural network trained on a few tens of thousands of comparisons, and it has holes. If you optimize hard against it, the policy finds the holes. This is reward hacking. The classic symptoms: answers get longer and longer (raters slightly preferred thorough answers, so the reward model learned "long is good"), every reply opens with flattery, or the model produces confident-sounding gibberish that happens to score well.

A second failure is mode collapse: without the leash, the optimum of "maximize reward" is to always give the single highest-scoring response. Diversity disappears, and the model's outputs become a narrow, repetitive style. The KL penalty forbids this, because concentrating all the mass on one answer is very far, in KL terms, from the reference distribution.

The KL term is a leash tied to the SFT model: go find better answers, but stay in the neighborhood where the reward model was trained and therefore still knows what it is talking about.

The optimal policy has a closed form

A useful fact, which also motivates DPO below: for a fixed reward and a fixed reference, the policy that maximizes the objective above is known exactly. It is the reference distribution, re-weighted by the exponentiated reward:

$$\pi^*(y \mid x) = \frac{1}{Z(x)}\, \pi_{\text{ref}}(y \mid x)\, \exp\!\Big(\frac{r(x,y)}{\beta}\Big)$$

Here $Z(x)$ just renormalizes. So each answer's probability is its reference probability, boosted by $e^{r/\beta}$. With large $\beta$ the boost is mild and the policy stays near the reference; with small $\beta$ the boost is enormous and the policy collapses onto the highest-reward answer. PPO is just a noisy, sample-based way of moving toward this distribution. The interactive below computes it exactly for a toy problem.

InteractiveKL-penalty intuitiondrag β; try the buggy reward model

Eight candidate answers to one prompt. Blue is the reference (SFT) distribution; amber is the KL-regularized optimal policy $\pi^* \propto \pi_{\text{ref}} e^{r/\beta}$. Small $\beta$ chases reward; large $\beta$ hugs the reference. Switch to the buggy reward model to watch the policy discover an exploit that the reference thought was nearly impossible.

policy π_θ(being trained) reference π_ref(frozen SFT copy) response y reward modelr(x, y) log π_θ(y)− log π_ref(y) sample score r − β·(KL term) PPO update: raise log π_θ(y) if the penalized reward beat expectation
Figure 2. One RLHF step. The policy samples a response, the reward model scores it, and the KL term measures how far the policy has drifted from the frozen reference on that response. The penalized reward drives the PPO update (dashed). The reference never changes.

DPO: skip the reward model

Stage 2 plus stage 3 is a lot of machinery: a separate reward model, an RL loop with sampling, four copies of the model in memory (policy, reference, reward, value). Rafailov et al. (2023) asked whether the detour through an explicit reward model is necessary, and showed that it is not.

The idea comes straight from the closed-form optimal policy above. Rearranging $\pi^* \propto \pi_{\text{ref}}\, e^{r/\beta}$ gives the reward in terms of the policy: $r(x,y) = \beta \log \frac{\pi^*(y|x)}{\pi_{\text{ref}}(y|x)} + \beta\log Z(x)$. Substitute that into the Bradley–Terry loss, and the annoying $Z(x)$ cancels because both responses share the same prompt. What is left is a loss on the policy directly:

$$\mathcal{L}_{\text{DPO}} = -\log \sigma\!\Big(\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)}\Big)$$

Read it as: the policy's implicit reward for a response is $\beta$ times how much more likely it finds the response than the reference does. DPO trains the policy so that the chosen response's implicit reward beats the rejected response's implicit reward, with the same sigmoid-of-a-difference shape as the reward-model loss. Increase the margin of the chosen log-ratio over the rejected log-ratio, and stop pushing once the margin is comfortable.

x + y_wchosen x + y_lrejected policy π_θ reference π_ref policy π_θ reference π_ref log π_θ(y_w) − log π_ref(y_w)chosen log-ratio a log π_θ(y_l) − log π_ref(y_l)rejected log-ratio b −log σ(β(a − b))DPO loss gradient: raise a, lower b
Figure 3. One DPO training example. Four forward passes (two models, two responses) give two log-ratios; the loss is the reward-model loss with the log-ratios standing in for rewards. The reference model is frozen and its log-probabilities can be precomputed, so no sampling and no separate reward model are needed.
Worked example

Take $\beta = 0.1$. For the chosen response the policy assigns log-probability $-20.0$ and the reference $-21.0$, so the log-ratio is $+1.0$. For the rejected response the policy gives $-25.5$ and the reference $-24.0$, so the log-ratio is $-1.5$. Margin $= 1.0 - (-1.5) = 2.5$; scaled by $\beta$: $0.25$. Loss $= -\ln \sigma(0.25) = -\ln 0.562 = 0.576$. Increasing the chosen log-ratio or decreasing the rejected one lowers the loss.

DPO needs no sampling during training, no reward model, and only two models in memory (policy and reference; the reference log-probs can even be precomputed). It is a supervised-looking loss on preference pairs, which is why it spread so fast. The catch is that it is offline: it learns only from the pairs it was given, whereas PPO samples fresh responses from the current policy and can discover behaviors that were not in the dataset. In practice, DPO (and its relatives) is the default for most open-model post-training, and online RL is used when there is a reliable reward to chase, such as verifiable math or code correctness. The whole family is compared in Preference Optimization; code/lumen/dpo.py implements the loss in a dozen lines.

What changes in the model

Behavior, not knowledge

All three stages together touch a few hundred thousand examples, against trillions of pre-training tokens. The weights barely move. What the model knows is essentially fixed at the end of pre-training; post-training changes which of the many things it could say it chooses to say, and in what voice. This is why a chat model can be so helpful and so confidently wrong at the same time: the persona was trained; the facts were not.

The alignment tax

Optimizing for human preference can cost a little on other benchmarks: a post-trained model may score slightly lower on a few academic tasks than its base model. Askell et al. (2021) called this the alignment tax. Ouyang et al. found the tax mostly disappears when a bit of pre-training loss is mixed into the RL stage (the "PPO-ptx" variant). The tax is real but small, and modern recipes largely avoid it.

Sycophancy

If raters prefer answers that agree with them, the reward model learns that agreement is rewarded, and RL amplifies it. The result is a model that tells you your wrong argument is right, changes a correct answer when you push back, and flatters. Sharma et al. (2023) documented this across several assistants. It is the single clearest example of reward hacking in deployed systems, and one reason why the KL leash, better rater instructions, and AI-assisted feedback all matter.

Constitutional AI and RLAIF

Human labels are slow and expensive, and human raters have the biases above. Bai et al. (2022), in Constitutional AI, replaced most of the human feedback with feedback from a model guided by a written list of principles (the "constitution"). In the SFT phase the model critiques and revises its own responses against those principles; in the preference phase a model, not a human, chooses between response pairs, and a reward model is trained on those AI-generated labels. This is RLAIF, reinforcement learning from AI feedback. Lee et al. (2023) reported that RLAIF can match RLHF on summarization and dialogue when the labeling model is strong enough. The mechanics are identical to what you have seen; only the source of the preference labels changes.

Where to go from here

This chapter was the map. The territory is covered in four later chapters: Supervised Fine-Tuning (data, templates, masking, packing), Preference Optimization (DPO and its many variants), RL Fundamentals (policy gradients from bandits up), and RLHF Deep Dive (PPO, GRPO, reward-model training in detail). The next chapter, GPT-2 from Scratch, goes back to pre-training and builds the base model whose behavior all of this reshapes.

Practice

Exercise 1 — masked SFT loss

Write a function that takes a list of (role, text) turns, renders them with the ChatML template, tokenizes with the GPT-2 tokenizer plus two added special tokens, and returns input_ids and labels where every non-assistant position is -100. Check that F.cross_entropy(logits.view(-1, V), labels.view(-1)) only averages over assistant tokens by comparing to a manual computation.

Solution sketch

Render each turn as <|im_start|>role\ncontent<|im_end|>\n, tokenize turn by turn so you know which token indices belong to which turn, and set labels to the input ids shifted left, with -100 for non-assistant spans. Remember the end-of-turn token after assistant content should be a target. Verify with a random model that the masked loss equals the mean of -log_softmax(logits)[target] over just the assistant indices.

Exercise 2 — reward model on a toy preference set

Make 200 synthetic prompt-response pairs where the "better" response is the longer one 80% of the time. Train a Bradley–Terry reward head on top of frozen GPT-2 features. Then check: does the reward model rank a 500-word nonsense response above a 20-word correct one? You have just reproduced length bias.

Solution sketch

Use the final-token hidden state of GPT-2 as features, a single nn.Linear(768, 1) head, and the loss -F.logsigmoid(r_w - r_l).mean(). Because length is the only consistent signal in the data, the head learns to reward length. Plot reward against token count to see the correlation. This is the mechanism behind the "answers get longer" symptom of RLHF.

Exercise 3 — the KL leash, numerically

Using the eight-answer toy from the interactive, compute $\pi^*$ for $\beta \in \{0.1, 0.5, 1, 5\}$ in NumPy and verify that $\text{KL}(\pi^* \| \pi_{\text{ref}})$ decreases monotonically in $\beta$ while $\mathbb{E}_{\pi^*}[r]$ also decreases. Then implement the DPO loss from code/lumen/dpo.py and confirm that the gradient with respect to the chosen log-ratio is negative and with respect to the rejected log-ratio is positive.

Solution sketch

$\pi^* = \text{softmax}(\log \pi_{\text{ref}} + r/\beta)$. As $\beta \to \infty$ the reward term vanishes and $\pi^* \to \pi_{\text{ref}}$ (KL $\to 0$); as $\beta \to 0$ the mass concentrates on $\arg\max r$. For DPO, the loss is $-\log\sigma(\beta(a - b))$ with $a$ the chosen and $b$ the rejected log-ratio; $\partial/\partial a = -\beta(1 - \sigma(\beta(a-b)))$, which is negative, and $\partial/\partial b$ is its negative.

Check yourself
In supervised fine-tuning on chat data, why are the user's tokens excluded from the loss?
The prompt tokens still go through the forward pass (the answer attends to them); they just get label −100 so they contribute no gradient. We want gradient only on the behavior we are trying to teach: the response, including its end-of-turn token.
A reward model gives response A a score of 2.0 and response B a score of 2.0. Under Bradley–Terry, the probability that A is preferred is:
P(A ≻ B) = σ(r_A − r_B) = σ(0) = 0.5. Absolute scores are meaningless; only gaps between responses to the same prompt are.
What is the KL penalty in RLHF primarily protecting against?
The reward model is imperfect; unconstrained optimization finds its blind spots (reward hacking) and destroys diversity (mode collapse). The KL term keeps the policy in the region where the reward model's judgments are trustworthy.
What does DPO remove from the InstructGPT pipeline?
DPO substitutes the closed-form optimal policy into the Bradley–Terry loss, so it trains the policy directly on preference pairs. It still needs preference data and a frozen reference model (its log-probabilities appear in the loss).

Key takeaways

  • A base model continues documents; it has never been told that a question is a request. Post-training supplies the job description.
  • SFT is ordinary next-token training on chat-formatted demonstrations, with special tokens marking turns and the loss masked to the assistant's tokens.
  • A reward model turns pairwise human preferences into a scalar score via Bradley–Terry: $P(A \succ B) = \sigma(r_A - r_B)$, trained with $-\log\sigma(r_w - r_l)$.
  • RL fine-tuning maximizes reward minus $\beta\cdot$KL to the SFT model; the KL leash prevents reward hacking and mode collapse. The optimal policy is $\pi_{\text{ref}}\, e^{r/\beta}$, renormalized.
  • DPO plugs that optimum into the preference loss and trains the policy directly, no reward model and no sampling; it is offline, which is its limit as well as its convenience.
  • Post-training changes behavior, not knowledge. Watch for the alignment tax and for sycophancy, the most common form of reward hacking in deployed models.

Further reading