Nathan Lambert
Course on RLHF and post-training. Chapter 8 on Direct Alignment Algorithms.
The Direct Preference Optimization paper (Rafailov et al., 2023) was a breakthrough in the accessibility of RLHF and post-training research. Some context:

We will derive Direct Preference Optimization (DPO) from scratch, then look at how it is used in practice.
The promise of DPO:
The plan, in four steps:
Rafailov et al., 2023 — “Your Language Model is Secretly a Reward Model” (Rafailov et al., 2023).
Classic RLHF is three moving parts:
DPO collapses steps 2 and 3 into one supervised-style loss.
The key realization we will prove:
The optimal RLHF policy and the reward model are two views of the same object. If we know one, we know the other in closed form.
So we can train the policy directly on preferences.

The whole derivation lands on two objects.
Optimal policy — the RLHF solution in closed form:
DPO loss — what you actually train:
In practice, that loss is just a few lines:
pi_logratios = policy_chosen_logps - policy_rejected_logps
ref_logratios = reference_chosen_logps - reference_rejected_logps
logits = pi_logratios - ref_logratios
losses = -F.logsigmoid(beta * logits)
Everything between here and the implementation is why this is the right loss.
We want to find the \pi that solves this equation! But, without RL.
Pick up where we left off and fold the bracket into a single log-ratio, using \tfrac{1}{\beta} r = \log e^{\,r/\beta}:
We are minimizing \min_{\pi}\ \mathbb{E}_{y\sim\pi}\Big[\, \log\frac{\pi(y\mid x)}{\pi_{\text{ref}}(y\mid x)\,e^{\,r(x,y)/\beta}} \,\Big].
Why do we want \pi to match that denominator?
We are minimizing \min_{\pi}\ \mathbb{E}_{y\sim\pi}\Big[\, \log\frac{\pi(y\mid x)}{\pi_{\text{ref}}(y\mid x)\,e^{\,r(x,y)/\beta}} \,\Big].
Why do we want \pi to match that denominator? Because \mathbb{E}_{y\sim\pi}\big[\log\tfrac{\pi}{q}\big] is a KL divergence \mathcal{D}_{\text{KL}}(\pi\,\|\,q) — it is \ge 0, and equals 0 only when \pi = q. So the minimizer is whatever distribution q sits in the denominator.
We are minimizing \min_{\pi}\ \mathbb{E}_{y\sim\pi}\Big[\, \log\frac{\pi(y\mid x)}{\pi_{\text{ref}}(y\mid x)\,e^{\,r(x,y)/\beta}} \,\Big].
Why do we want \pi to match that denominator? Because \mathbb{E}_{y\sim\pi}\big[\log\tfrac{\pi}{q}\big] is a KL divergence \mathcal{D}_{\text{KL}}(\pi\,\|\,q) — it is \ge 0, and equals 0 only when \pi = q. So the minimizer is whatever distribution q sits in the denominator.
The catch: our denominator \pi_{\text{ref}}\,e^{r/\beta} is not a distribution — summed over y it does not equal 1.
We are minimizing \min_{\pi}\ \mathbb{E}_{y\sim\pi}\Big[\, \log\frac{\pi(y\mid x)}{\pi_{\text{ref}}(y\mid x)\,e^{\,r(x,y)/\beta}} \,\Big].
Why do we want \pi to match that denominator? Because \mathbb{E}_{y\sim\pi}\big[\log\tfrac{\pi}{q}\big] is a KL divergence \mathcal{D}_{\text{KL}}(\pi\,\|\,q) — it is \ge 0, and equals 0 only when \pi = q. So the minimizer is whatever distribution q sits in the denominator.
The catch: our denominator \pi_{\text{ref}}\,e^{r/\beta} is not a distribution — summed over y it does not equal 1. We normalize it with the partition function:
Fold \tfrac{1}{\beta} r = \log e^{\,r/\beta} into the denominator of the first term in the objective (again, log rules) and name it q(y\mid x) = \tfrac{1}{Z(x)}\,\pi_{\text{ref}}(y\mid x)\,e^{\,r(x,y)/\beta} — a valid distribution over y. The objective is:
\log Z(x) does not depend on y, so pull it out of the inner expectation:
The inner expectation is exactly a KL divergence, \mathbb{E}_{y\sim\pi}\big[\log\tfrac{\pi}{q}\big] = \mathcal{D}_{\text{KL}}(\pi\,\|\,q):
Where we landed – the objective is now a KL plus a \pi-independent constant:
A preference between two responses is a softmax over their rewards:
Now substitute the implicit reward r^{*}(x,y) = \beta \log \tfrac{\pi^{*}(y\mid x)}{\pi_{\text{ref}}(y\mid x)} + \beta \log Z(x).
New here? See Lecture 2 and Chapter 5: Reward Modeling for the Bradley-Terry model.
Write \Delta_i = \beta \log \tfrac{\pi^{*}(y_i\mid x)}{\pi_{\text{ref}}(y_i\mid x)}, so the cancelled form is p^{*} = \dfrac{e^{\Delta_1}}{e^{\Delta_1} + e^{\Delta_2}}. Multiply numerator and denominator by e^{-\Delta_1}:
With \sigma(z) = \tfrac{1}{1+e^{-z}}, this is a sigmoid (\Delta_i = \beta \log \tfrac{\pi^{*}(y_i\mid x)}{\pi_{\text{ref}}(y_i\mid x)}):
Minimize the negative log-likelihood of the observed preferences (y_c \succ y_r) – this is making the probability more likely:
Plug in the sigmoid form of p, with the trainable policy \pi_{\theta} as the implicit reward:
This is directly differentiable — no reward model, no sampling, no RL loop.
Start by taking the gradient of the previous loss function.
Let u = \big(\beta \log \tfrac{\pi_{\theta}(y_c\mid x)}{\pi_{\text{ref}}(y_c\mid x)} - \beta \log \tfrac{\pi_{\theta}(y_r\mid x)}{\pi_{\text{ref}}(y_r\mid x)}\big) — the term inside \sigma.
Chain rule, starting with \tfrac{d}{dz}\log\sigma(z) = \tfrac{\sigma'(z)}{\sigma(z)} as the inner operation:
Substitute \sigma'(u) = \sigma(u)\big(1-\sigma(u)\big) and cancel \sigma(u):
The reflection identity 1-\sigma(u) = \sigma(-u) flips the argument, giving the compact form:
Now differentiate u, where -u = \beta\log\tfrac{\pi_{\theta}(y_r\mid x)}{\pi_{\text{ref}}(y_r\mid x)} - \beta\log\tfrac{\pi_{\theta}(y_c\mid x)}{\pi_{\text{ref}}(y_c\mid x)}. Only \pi_{\theta} depends on \theta — \pi_{\text{ref}} is frozen, so its \log terms drop:
Substitute \nabla_{\theta} u and write \sigma(-u) out in full:
The reward model never had to be built — it was hiding inside the policy the whole time.
The DPO loss only cares about the margin between the chosen and rejected log-ratios — not their absolute values. So the model can lower the loss by pushing the rejected probability down faster than the chosen, even while the chosen probability also falls.
Mediated through the partition function Z(x) in the derivation.

In a real run: Olmo 1B DPO — the chosen/rejected reward margin widens, yet the chosen log-prob itself can still drift down.
\beta sets the strength of the KL constraint relative to reward maximization:
Crucially, DPO’s final KL distance is static: it steps directly to the optimal solution implied by the dataset and the chosen \beta. Online RL instead takes steps based on freshly sampled batches and a per-sample KL penalty. Some RL runs even include dynamically adjusted KL controllers.
Each variant tweaks the loss to fix a limitation — often a one-line change. I started calling all the variants Direct Alignment Algorithms (DAAs). Two to start:
Two more that drop the reference model entirely:
The algorithm matters far less than the base model and the data. Still, many papers continued to make minor algorithmic tweaks. Many more exist than were on these slides.
No generation during training, no separate reward model — the heart of the loss is a few lines:
# log-prob gaps for policy and frozen reference
pi_logratios = policy_chosen_logps - policy_rejected_logps
ref_logratios = reference_chosen_logps - reference_rejected_logps
# positive when policy shifts mass toward the chosen completion
logits = pi_logratios - ref_logratios
losses = -F.logsigmoid(beta * logits)
Tip: \pi_{\text{ref}} is frozen, so precompute and cache its log-probs to cut peak memory ~50%. Reference code: code/direct_alignment/.
These algorithms need feedback data, not necessarily human feedback data — AI feedback works just as well.
DPO and other DAAs
PPO / policy gradient is online
If so many models have used DPO well and it’s so simple, why does it seem like it comes up so infrequently – especially at the frontier?
How I see things: