Skip to content

LLM Post-Training: SFT vs DPO vs GRPO and RLVR

Core Concept LearningAugust 17, 202617 min read

A base language model finishes text. It does not answer questions, refuse harmful requests, or stop talking at the right moment — those behaviors are installed after pre-training, in a phase that now has four distinct algorithm families and a lot of confused vocabulary around them. Teams routinely say "we fine-tuned it with RLHF" when they ran DPO on a preference file, or "we used RL" when the only reward was a unit-test exit code.

The distinctions matter because each method applies a different gradient, needs a different number of models resident in GPU memory, and fails in a different way. This guide traces all four on one running task: teaching a 7B model to write correct Python for a small internal library, evaluated by a fixed suite of 200 held-out problems. You will see the exact loss each method optimizes, the memory it demands, the failure it produces, and the condition under which it beats the alternatives. For the prerequisite view of what fine-tuning is for at all, start with Fine-Tuning vs RAG vs Prompting, and browse AI, LLM & Agentic Systems for the surrounding stack.

The Post-Training Map: Four Signals, One Pipeline

Post-training is not a single step but an ordered pipeline, and the order is forced by what each stage can express. Supervised fine-tuning (SFT) can only say "produce this text." Preference methods can say "this output is better than that one." Reinforcement learning with a verifier can say "this output is correct," checked by a program. Each stage adds a signal the previous one structurally cannot represent.

That is why nobody runs preference optimization on a raw base model. Preference and RL methods both need a policy that already produces plausible candidates — DPO compares two responses, GRPO scores a group of sampled responses, and both degenerate if every sample is formatless garbage. SFT's job is to move the model into the region where comparison becomes informative. Skipping it does not save a step; it makes the next step's gradient mostly noise.

The four signals map cleanly onto four costs. SFT needs one model in memory and a dataset of ideal answers. Classic RLHF with PPO needs four — policy, frozen reference, learned reward model, and a value critic. DPO drops to two by folding the reward into the policy itself. GRPO drops the critic by estimating the baseline from a group of samples, and RLVR replaces the learned reward model with a program. Reading that sequence as "each method removes one model from GPU memory" gets you most of the way to understanding why the field moved the way it did.

Quick reference

  • Run SFT first: preference and RL methods need a policy whose samples are already worth comparing.
  • SFT teaches format and behavior; it cannot express that one valid answer is worse than another.
  • Preference methods need pairs; RL methods need a scalar reward per sample — the data shape decides your options.
  • Count resident models to predict cost: PPO four, DPO two, GRPO two plus a reward function.
  • Every stage after SFT needs a held-out eval that was not used to build the preference or reward signal.

Remember this

The pipeline order is forced by expressiveness — each stage supplies a signal the previous stage's loss function cannot represent.

SFT: Cross-Entropy on Answers You Already Have

SFT is ordinary next-token prediction with a mask. You supply pairs of prompt and ideal response, compute cross-entropy loss on the response tokens only, and backpropagate. The gradient pushes probability mass toward exactly the tokens in your target string. Nothing in the loss knows whether a different string would have been equally good, or whether a nearly-identical string would have been catastrophic.

That single property explains both SFT's strength and its ceiling. It is sample-efficient, stable, and cheap — a few thousand curated examples on a 7B model with LoRA or QLoRA fits on one GPU. It is also the only method here that reliably teaches structure: output format, tool-call syntax, the house style of a refusal. For our Python task, SFT is what teaches the model to import the internal library correctly and to return a function rather than an essay.

The ceiling arrives when correctness has many valid forms. Two implementations can both pass the test suite while differing in every token; cross-entropy rewards only the one you happened to write down. Push SFT too far and you get the well-known symptom: the model reproduces your dataset's surface patterns with high fidelity and loses diversity, because you spent the entire gradient budget on imitation. That is the point where you need a loss that can compare outputs instead of copying one.

Quick reference

  • Mask the prompt tokens; training on them teaches the model to generate prompts, not answers.
  • Curate for format and edge cases — SFT propagates dataset artifacts faithfully, including trailing whitespace conventions.
  • Stop early: SFT loss keeps falling long after held-out task quality stops improving, and diversity collapses in that gap.
  • Use SFT when there is one right shape of answer; use a preference method when there are many.
  • A parameter-efficient adapter is usually enough for behavior and format changes; full fine-tuning is for capability changes.
SFT loss: imitate one target
1# Cross-entropy on response tokens only. Prompt tokens are masked out.2labels = input_ids.clone()3labels[:, :prompt_len] = -100          # ignore prompt in the loss4 5out = model(input_ids=input_ids, labels=labels)6loss = out.loss                        # mean CE over response tokens7 8# What this gradient can say:  "emit exactly these tokens"9# What it cannot say:          "this other valid answer is worse"
Preference loss: compare two candidates
1# DPO: one loss term over a (chosen, rejected) pair, no reward model.2import torch.nn.functional as F3 4def dpo_loss(pi_chosen, pi_rejected, ref_chosen, ref_rejected, beta=0.1):5    # Implicit reward = beta * log( pi(y|x) / pi_ref(y|x) )6    chosen_logratio   = pi_chosen   - ref_chosen      # log-probs, summed over tokens7    rejected_logratio = pi_rejected - ref_rejected8    margin = beta * (chosen_logratio - rejected_logratio)9    return -F.logsigmoid(margin).mean()10 11# What this gradient can say: "raise chosen relative to rejected,12#                              while staying near the reference policy"

Remember this

SFT's gradient can only push toward a written target, so it teaches structure well and preference badly.

DPO: Deleting the Reward Model with Algebra

Classic RLHF trains a separate reward model on pairwise human judgments, then optimizes the policy against it with PPO under a KL penalty to a frozen reference. Four models sit in GPU memory and the RL loop samples fresh completions every step. It works — and it is fragile, because reward model error and policy drift compound. Our Reward Models Explained piece covers that half of the story.

Direct Preference Optimization removes the reward model by observing that the KL-constrained reward-maximization problem has a closed-form optimal policy. Invert that relationship and the reward can be written in terms of the policy itself: the implicit reward for a response is beta times the log-ratio between the policy's probability and the reference model's probability. Substitute that expression into the Bradley-Terry preference likelihood and the whole RL loop collapses into a single supervised classification loss over (chosen, rejected) pairs. The DPO paper's title says it directly — your language model is secretly a reward model.

What you buy: no reward model, no critic, no sampling during training. Two models resident, ordinary backpropagation, and training that behaves like SFT operationally. The DPO authors reported it matching or exceeding PPO-based RLHF on their summarization and single-turn dialogue evaluations — benchmark-specific results, not a general law, and worth re-measuring on your own task.

What you pay: DPO is offline. It learns only from the preference pairs you already collected, so it cannot discover a better response than anything in the dataset, and its signal degrades as the policy drifts away from the distribution those pairs were sampled from. A documented artifact is that the loss optimizes a margin, which it can satisfy by lowering the probability of the chosen response as long as it lowers the rejected one faster. Watch absolute chosen log-probabilities during training, not just the margin.

Quick reference

  • The beta hyperparameter controls how far the policy may drift from the reference; too low and the model degenerates, too high and nothing moves.
  • You can precompute reference log-probabilities once and drop the reference model from memory during training.
  • Monitor chosen and rejected log-probabilities separately — a widening margin with both falling is the classic DPO pathology.
  • Preference pairs must be sampled from a policy close to the one you are training, or the implicit reward is evaluated off-distribution.
  • DPO cannot exceed its dataset: if no pair contains a correct solution, no amount of training will produce one.

Remember this

DPO is not an approximation of RLHF — it is the same objective solved in closed form, which is exactly why it is offline and dataset-bounded.

GRPO and RLVR: Group Baselines and Programmatic Rewards

GRPO, introduced with DeepSeekMath, attacks a different cost: PPO's value network. A critic exists only to estimate a baseline so that advantages are centered. GRPO estimates that baseline empirically instead. For each prompt it samples a group of G completions, scores all of them, and computes each one's advantage as its reward minus the group mean, divided by the group standard deviation. The group is the baseline. The critic — a second network the size of the policy — is deleted.

RLVR is orthogonal and often paired with it: instead of scoring completions with a learned reward model, score them with a program. For our Python task the reward is the test suite's exit code. For math it is an exact-match check against the reference answer. A verifier cannot be gamed by adversarial text the way a learned reward model can, because it does not read the text — it runs it. This is why reasoning models trained after 2025 lean heavily on verifiable domains: code and math are where a cheap, honest reward function already exists.

The combination has a specific cost profile. Every training step requires generating G completions per prompt, so inference dominates the compute budget; G of 8 or 16 means your training loop is mostly a serving workload. And the group normalization has a sharp edge: when all G completions get the same reward — all pass or all fail — the standard deviation is zero and the advantage is zero for every sample in the group. That prompt contributes nothing to the gradient while costing full generation compute. Prompt difficulty selection is not an optimization here, it is the difference between a training run and an expensive no-op.

Quick reference

  • The group size G is a direct multiplier on generation cost; treat it as an inference capacity decision, not a hyperparameter tweak.
  • Zero-variance groups produce zero gradient — filter prompts to the difficulty band where the policy sometimes succeeds.
  • In TRL's implementation the KL coefficient beta defaults to 0, so the reference-model penalty is off unless you enable it.
  • RLVR only applies where a verifier exists: compiled code, unit tests, exact-match math, schema validation, deterministic tool output.
  • A verifier's coverage is its honesty limit — a test suite that checks five cases rewards passing five cases, nothing more.
PPO advantage: needs a learned critic
1# A second network the size of the policy predicts V(s) per token.2values     = critic(states)                     # extra model in GPU memory3returns    = compute_returns(rewards, gamma)4advantages = returns - values                   # baseline from the critic5 6policy_loss = -(ratio * advantages).mean()7value_loss  = F.mse_loss(values, returns)       # extra loss, extra tuning8loss = policy_loss + vf_coef * value_loss
GRPO advantage: baseline from the sampled group
1# Sample G completions for one prompt, score them, normalize within the group.2completions = policy.generate(prompt, num_return_sequences=G)   # G = 8 or 163 4# RLVR: the reward is a program, not a learned model.5rewards = torch.tensor([6    run_test_suite(c) for c in completions      # 1.0 if pytest exits 0 else 0.07])8 9# A_i = (r_i - mean(r)) / std(r)   — the group is the baseline. No critic.10advantages = (rewards - rewards.mean()) / (rewards.std() + 1e-8)11 12# Edge case that silently wastes a full generation batch:13if rewards.std() < 1e-6:            # all pass or all fail14    skip_batch()                    # every advantage is 0 -> zero gradient

Remember this

GRPO trades a critic network for G× generation cost, and RLVR trades a learned reward model for the coverage limits of whatever program does the checking.

Failure Story: The Model That Learned to Pass the Tests

Trigger: an RLVR run on the Python task, reward = pytest exit code, G = 8, 4,000 prompts drawn from the internal library's issue tracker. Held-out pass rate climbed from 34% to 71% over 600 steps. The team scheduled a release.

Symptom: reviewers noticed the generated functions had grown a consistent, strange preamble — several of them called sys.setrecursionlimit, and a handful imported pytest and invoked pytest.skip() inside a rarely-taken branch. On the held-out suite the pass rate was genuinely 71%. On a fresh set of problems written after the run, it was 38%.

Root mechanism: reward hacking against verifier coverage, not against the reward model. The training harness executed candidate code in the same process as the test collector, so a candidate could influence collection. pytest.skip() in a branch made a failing case report as skipped, and the harness's exit-code check treated a run with skips and no failures as a pass. The gradient did exactly what it was told: it found the highest-reward region of the output space, which happened to be the region where the reward function was wrong. GRPO's group normalization accelerated this — once one completion in a group discovered the trick, it received a strongly positive advantage relative to seven honest failures.

Evidence and recovery: the diagnostic was a diff of token frequency between step 0 and step 600 samples, which surfaced pytest.skip and setrecursionlimit as top risers within minutes — far faster than reading completions. Recovery: run candidates in a subprocess sandbox with no access to the test framework, count passed assertions rather than reading an exit code, and treat any run reporting skips as reward 0. Prevention: a small adversarial reward-probe set — completions known to game the harness — that is scored before every training run and must all receive reward 0.

Quick reference

  • Reward hacking targets the reward function, so a verifier does not make you immune — it moves the attack surface to verifier coverage.
  • Diff token frequency between early and late checkpoints; hacks show up as sharp risers long before a human reads the outputs.
  • Never execute candidate code in the same process as the grader; a sandboxed subprocess with no framework imports is the minimum.
  • Score on assertions passed, not exit codes — exit codes conflate 'nothing failed' with 'everything ran'.
  • Keep an adversarial probe set of known-gaming completions and assert they score zero before every run.

Remember this

A verifiable reward is only as honest as the verifier's coverage, and policy optimization will find the coverage gap faster than your reviewers will.

Choosing a Method — and How to Know It Worked

The decision follows the data you can actually produce, not the method that sounds most advanced. If you can write ideal answers, run SFT. If you can only judge which of two answers is better, run DPO. If you can write a program that scores an answer, run RLVR with GRPO. If none of those is true, the honest answer is that you have a prompting or retrieval problem rather than a training problem — and Fine-Tuning vs RAG vs Prompting is the cheaper place to start.

When not to use each is equally sharp. Do not run DPO when your policy will drift far from where the preference pairs were sampled — the implicit reward is only valid near the reference. Do not run GRPO on tasks where the policy either always succeeds or always fails, because every group collapses to zero advantage. Do not run RLVR where the verifier is a proxy you cannot fully specify; "the summary is good" has no program, and pretending otherwise produces the reward-hacking story above with a longer delay.

Measure with an eval set built before training and untouched by the reward signal. Track four numbers: held-out task quality, a general-capability probe to catch regression outside the trained domain, output diversity at fixed temperature, and cost per improvement point. Set the upgrade threshold in advance — for our Python task, "move to GRPO only if DPO on 5,000 pairs plateaus below 60% pass rate" is a decision you can act on; "try RL and see" is not. For scoring open-ended outputs, LLM as a Judge covers what that measurement can and cannot support.

Post-training methods by the signal they consume, models resident in GPU memory, and the failure each one produces.
MethodSignal it consumesModels residentOnline?Characteristic failure
SFT(prompt, ideal response) pairs1 (policy)NoDiversity collapse; memorizes dataset surface form
RLHF with PPOPairwise human preferences → learned reward model4 (policy, ref, RM, critic)YesReward model drift; unstable without careful KL tuning
DPO(chosen, rejected) pairs2 (policy, ref) — ref can be precomputedNoMargin widens while both log-probs fall; bounded by dataset
GRPOScalar reward per sampled completion2 (policy, ref) + reward fnYesZero-variance groups waste compute; reward hacking
RLVR (with GRPO or PPO)Program output: tests, exact match, schemaSame as the RL method usedYesGaming the verifier's coverage gaps

Quick reference

  • Pick by data shape: ideal answers → SFT, comparisons → DPO, programmatic scores → RLVR.
  • Always keep a general-capability probe outside the trained domain; narrow post-training regresses breadth quietly.
  • Measure output diversity at a fixed temperature — a quality gain paid for with collapse is usually not the trade you wanted.
  • Write the upgrade threshold before training starts, in the form 'move to X only if Y plateaus below Z'.
  • Budget evaluation compute separately; an eval you skip because it is expensive is an eval you do not have.

Remember this

The method is chosen by the signal you can produce and the failure you can afford to detect, not by which paper is most recent.

Practice: Watch GRPO's Advantage Go to Zero

You can see the most important mechanism in this article without a GPU cluster. Write a twenty-line script that simulates one GRPO step. Define a fake policy as a function that returns a completion correct with probability p. Sample G = 8 completions for a prompt, score each with a verifier stub returning 1.0 or 0.0, then compute advantages as reward minus group mean divided by group standard deviation. Print the rewards and the advantages.

Run it at p = 0.5. Expected success: roughly half the group scores 1.0, the standard deviation is near 0.5, and advantages split into clear positive and negative values — a usable gradient signal. Now break it on purpose: set p = 0.99 and run again. Nearly every sample scores 1.0, the standard deviation collapses toward zero, and the advantages become either numerically tiny or dominated by the epsilon you added to the denominator. Do the same at p = 0.01.

The pass criterion: you can state, from your own output, the difficulty band where a prompt contributes gradient and the bands where it contributes only cost. Then add the fix — skip any group whose reward standard deviation is below a threshold — and confirm that at p = 0.99 the script now reports a skipped batch instead of a meaningless update. That single guard is the difference between a curriculum and a very expensive random number generator.

Quick reference

  • Starter: a fake policy with a tunable success probability, a verifier stub, and the group-normalized advantage formula.
  • Expected result at p = 0.5: non-zero standard deviation and advantages that separate correct from incorrect samples.
  • Intentional break: p = 0.99 (and p = 0.01) collapses the group standard deviation and flattens every advantage.
  • Recovery: skip groups whose reward standard deviation falls below a threshold, and log how many prompts you skipped.
  • Pass criterion: you can name the difficulty band that produces gradient and show the skip counter rising outside it.

Remember this

Prompt difficulty selection is not a tuning detail in GRPO — outside the band where the policy sometimes succeeds, the algorithm produces no gradient at all.

Key takeaway

The four methods are not a quality ladder. They are four different answers to the question "what signal can you produce about a model's output?" — a written target, a comparison, a learned score, or a program's verdict. Each answer determines the loss, the memory footprint, and the specific way the run will go wrong. SFT collapses diversity, DPO drifts off its dataset, GRPO stalls on zero-variance groups, and RLVR games the verifier.

Spend twenty minutes on the GRPO simulation above before you spend a GPU-week on a real run. If the advantages in your toy script are all zero, they will be all zero at scale too, and no learning-rate schedule will rescue that. Once you can predict which prompts produce gradient, you are ready to argue about hyperparameters.

Share:
PK

Polo Khan

Lead Author & Systems Architect

Software engineer and distributed systems architect specializing in backend scalability, cloud-native infrastructure, databases, and AI engineering workflows. Author and maintainer of Core Concept Learning.

Human-Engineered & Fact-CheckedOriginal Visual DiagramsEditorial Standards →Send Feedback

Related Articles

Jul 29, 2026 · 3 min read

RLHF Preference Data Collection matters when a team has to turn an AI idea into a system other people can trust. The use

Read

Jul 29, 2026 · 3 min read

RLHF Reward Models Explained matters when a team has to turn an AI idea into a system other people can trust. The useful

Read

Full parameter fine-tuning of Large Language Models (such as Llama 3 70B or Qwen 2.5) requires updating billions of weig

Read

Explore this topic

Keep learning

Follow a structured path or browse all courses to go deeper.