SFT vs RLHF vs GRPO: Choosing an LLM Post-training Method
Compare SFT, RLHF, DPO and GRPO: training signals, data, compute and when to use each, with runnable DPO loss and GRPO advantage code plus TRL examples.
At a cricket academy in Indore, a young fast bowler learns in three phases. First, the coach bowls and the student copies the action, delivery by delivery.
Second, the coach watches pairs of the student's deliveries and simply says which one was better, because he cannot always explain why. Third, the student bowls overs at a single stump, a machine counts the hits, and each ball is judged against the average of that over.
Copying gets the basics right fast. Comparing teaches subtle things a demonstration cannot. Scoring against a target lets the student discover techniques the coach never showed.
Modern LLM post-training follows the same three phases.
What are SFT, RLHF and GRPO?
SFT (supervised fine-tuning), RLHF (reinforcement learning from human feedback) and GRPO (group relative policy optimization) are post-training methods that improve a pretrained LLM using, respectively, example answers to imitate, human preferences between answers, and automatically checked rewards compared within a group of the model's own attempts.
Mapping the academy: the coach's demonstrations are SFT data, the "this one was better" calls are preference pairs for RLHF or DPO, and the stump-hit machine is a reward function for GRPO. Judging each ball against that over's average is the "group relative" part of GRPO's name.
How LLMs are trained introduced each stage. This tutorial compares them side by side: what data each needs, how much compute, what can go wrong, and how to run them with Hugging Face TRL.
Three signals: copy this answer, prefer this answer, beat your own average.
SFT vs RLHF vs GRPO compared
| SFT | RLHF (PPO) / DPO | GRPO | |
|---|---|---|---|
| Training data | Prompt + ideal answer | Prompt + chosen + rejected answer | Prompts + a reward function |
| Signal | Every token of the reference | Which whole answer is better | Score of each sampled answer vs its group |
| Who provides it | Writers, logs, stronger models | Human raters or a judge model | Code: answer checker, unit tests, format rules |
| Model generates during training? | No | PPO: yes; DPO: no | Yes, many samples per prompt |
| Models in memory | 1 | PPO: up to 4; DPO: 2 | Policy, plus a reference if a KL penalty is used |
| Can exceed the data's quality? | Rarely | Somewhat | Yes, on verifiable tasks |
| Best for | Format, style, new skills, chat ability | Tone, helpfulness, safety, subtle quality | Maths, code, logic, structured tasks |
SFT is cheap and stable but can only imitate. Preference methods capture taste. GRPO lets the model find solutions better than any example you could write, as long as a program can tell right from wrong.
SFT: learning by imitation
In SFT the model reads a prompt and is trained to predict your reference answer token by token, with prompt tokens usually left out of the loss. It needs no reward model and no sampling, so it is the cheapest and most predictable method.
Its limit is that the model only sees perfect answers, never its own mistakes. If your references are mediocre, the model learns to be mediocre. Building good references is covered in creating an instruction fine-tuning dataset, and the low-memory way to run SFT is in fine-tuning LLMs with LoRA.
Quick check
Which method needs no human labels when the task has checkable answers?
GRPO scores the model's own samples with code, such as an answer checker or unit tests.
RLHF and DPO: learning from preferences
Classic RLHF trains a separate reward model on human comparisons, then uses the PPO algorithm to push the LLM toward high-reward answers. PPO needs the policy being trained, a frozen reference copy, the reward model and a value model, often all in GPU memory at once. It is powerful and notoriously fiddly.
DPO (Direct Preference Optimization) reaches a similar goal with one simple loss on the preference pairs. It compares how much the policy has raised the probability of the chosen answer, relative to a frozen reference, against how much it has raised the rejected one:
import math
def dpo_loss(pol_chosen, ref_chosen, pol_rejected, ref_rejected, beta=0.1):
"""Inputs are total log-probabilities of each answer under the policy and the frozen reference."""
chosen_gain = pol_chosen - ref_chosen # how much more likely the good answer became
rejected_gain = pol_rejected - ref_rejected # how much more likely the bad answer became
margin = beta * (chosen_gain - rejected_gain)
return -math.log(1 / (1 + math.exp(-margin))), margin
cases = {
"start of training (policy = reference)": (-42.0, -42.0, -40.0, -40.0),
"policy now prefers the chosen answer": (-38.0, -42.0, -46.0, -40.0),
"policy drifted toward the rejected one": (-44.0, -42.0, -37.0, -40.0),
}
for name, logps in cases.items():
for beta in (0.1, 0.5):
loss, margin = dpo_loss(*logps, beta=beta)
print(f"{name:<40} beta={beta}: margin={margin:+.2f} loss={loss:.3f}")At the start the loss is log 2, about 0.693, because the policy equals the reference. Training lowers it by widening the gap between chosen and rejected. The beta setting controls how sharply the loss reacts and, in practice, how far the model may drift from the reference. TRL's default is 0.1.
DPO needs only two models and no sampling, which made it the standard preference method for open models. Its weaknesses: it can favour longer answers if your chosen answers tend to be longer, and it learns only from fixed pairs.
Quick check
Why is DPO cheaper to run than classic RLHF with PPO?
DPO needs only the policy and a frozen reference, and learns from fixed chosen and rejected answers.
GRPO: learning from verifiable rewards
GRPO, introduced in DeepSeek's 2024 maths research and used widely for reasoning models since, drops the reward model and the value model.
For each prompt it samples a group of answers, scores each with a reward function, and computes each answer's advantage as its score minus the group mean, divided by the group's standard deviation. Above-average answers are reinforced; below-average ones are discouraged.
The reward function is ordinary code. Here is one for maths problems that rewards a correct final answer and a little for the right format:
import re
def reward(completion, answer):
score = 0.0
if re.search(r"<answer>.*?</answer>", completion, re.S):
score += 0.2 # followed the output format
found = re.search(r"<answer>\s*([-\d.]+)\s*</answer>", completion)
if found and float(found.group(1)) == answer:
score += 1.0 # correct final answer
return score
group = [ # 6 sampled completions for "A bus covers 120 km in 2.5 hours. Speed in km/h?"
"120 / 2.5 = 48 <answer>48</answer>",
"Speed is 50 <answer>50</answer>",
"120 / 2.5 = 48. The answer is 48.",
"<answer>48</answer>",
"2.5 * 120 = 300 <answer>300</answer>",
"Distance over time gives 48 km/h <answer> 48 </answer>",
]
for c in group:
print(f"{reward(c, 48):.1f} {c}")Turning those scores into advantages is a few lines of numpy. The second group shows GRPO's blind spot:
import numpy as np
def advantages(rewards, eps=1e-4):
r = np.array(rewards, dtype=float)
return (r - r.mean()) / (r.std() + eps)
groups = {
"mixed results": [1.2, 0.2, 0.0, 1.2, 0.2, 1.2],
"all wrong (too hard)": [0.2, 0.2, 0.2, 0.2, 0.2, 0.2],
"all right (too easy)": [1.2, 1.2, 1.2, 1.2, 1.2, 1.2],
}
for name, rewards in groups.items():
adv = advantages(rewards)
print(f"{name:<22} advantages={np.round(adv, 2)} learning signal={np.abs(adv).sum():.2f}")When every answer in a group gets the same score, all advantages are zero and that prompt teaches nothing. So GRPO training sets are chosen to be just hard enough: the model solves them sometimes. The group also replaces the value model that PPO needs, which is GRPO's main memory saving.
Quick check
In GRPO, what happens when all 8 answers to a prompt get the same reward?
Advantages are rewards relative to the group mean; identical rewards mean nothing to reinforce or discourage.
Choosing between SFT, RLHF and GRPO
Most real pipelines pass through more than one box, in this order.
Follow these steps for a project:
- Start with SFT whenever you can write or collect good answers. It teaches format and basic behaviour, and later methods work much better from an SFT starting point.
- Add DPO if reviewers keep preferring some answers over others for reasons that are hard to write down, such as tone or clarity.
- Add GRPO if the task has checkable answers and you want the model to get better than your examples, for example at multi-step calculations or code that passes tests.
- Evaluate after each stage on a held-out set, including general questions, to catch lost skills. Putting each checkpoint behind a Gradio demo on Spaces lets reviewers compare them by hand.
Running SFT, DPO and GRPO with Hugging Face TRL
TRL provides one trainer per method with the same overall shape. These snippets follow the current TRL documentation; they need a GPU and network access:
import re
from datasets import load_dataset
from trl import DPOConfig, DPOTrainer, GRPOConfig, GRPOTrainer
# DPO: rows with "prompt", "chosen" and "rejected"
prefs = load_dataset("json", data_files="preferences.jsonl", split="train")
dpo = DPOTrainer(model="your-username/admissions-sft", # start from your SFT model
args=DPOConfig(output_dir="admissions-dpo", beta=0.1),
train_dataset=prefs)
dpo.train()
# GRPO: rows with "prompt" and an extra "answer" column, passed to the reward function
def correct_answer(completions, answer, **kwargs):
rewards = []
for text, gold in zip(completions, answer):
m = re.search(r"<answer>\s*([-\d.]+)\s*</answer>", text)
rewards.append(1.0 if m and float(m.group(1)) == float(gold) else 0.0)
return rewards
problems = load_dataset("json", data_files="fee_problems.jsonl", split="train")
grpo = GRPOTrainer(model="your-username/admissions-sft",
reward_funcs=correct_answer,
args=GRPOConfig(output_dir="admissions-grpo", num_generations=8),
train_dataset=problems)
grpo.train()Two details worth knowing. The reward function receives every dataset column except the prompt as a keyword argument, which is how answer reaches it.
And recent TRL versions set the GRPO KL penalty beta to 0.0 by default, so no reference model is loaded; set it above zero if you want to keep the model closer to its starting point. Defaults change between releases, so check your installed version.
Common mistakes with post-training methods
- Skipping SFT. Preference and RL methods on a raw base model are unstable and slow to learn format.
- Reward hacking. A reward that only checks for
<answer>tags will be satisfied with tags and nonsense. Read samples every few hundred steps. - Unbalanced preference pairs. If chosen answers are always longer, DPO learns "longer is better".
- Prompts that are too easy or too hard for GRPO. Zero-variance groups give zero signal.
- No general evaluation. Narrow training can erode broad skills; test a few general questions too.
- Trusting a rising reward curve. It proves the model found what the reward pays for, not that it improved.
Key takeaways
- SFT imitates answers, RLHF and DPO learn from preferences, and GRPO learns from verifiable rewards.
- SFT is cheapest and comes first; DPO captures taste with two models; GRPO can exceed its training examples on checkable tasks.
- GRPO's advantage is reward minus group mean over group spread; identical rewards teach nothing.
- Every reward can be gamed, so read samples and evaluate broadly after each stage.
- Hugging Face TRL offers
SFTTrainer,DPOTrainerandGRPOTrainerwith a shared interface.
FAQ
Is GRPO better than RLHF?
For tasks where a program can check the answer, GRPO is often simpler and cheaper than PPO-based RLHF because it needs no reward model or value model. For subjective qualities such as tone or helpfulness, you still need preference data, through RLHF or DPO. Many models use both.
Is DPO the same as RLHF?
DPO solves the same problem as RLHF, aligning a model with human preferences, but without training a separate reward model or running reinforcement learning. It optimises a simple loss directly on chosen and rejected answer pairs. People often group it under "RLHF-style" preference tuning.
Do I need SFT before DPO or GRPO?
Almost always. SFT teaches the chat format and basic task behaviour, giving preference and RL methods a sensible starting point. Starting DPO or GRPO from a raw base model usually wastes compute on learning the format, and training is less stable.
Can I run GRPO on a single GPU?
Yes, for small models. Combining GRPO with LoRA or QLoRA and a model of around one to a few billion parameters fits on a single consumer or cloud GPU. Generation dominates the time, because the model writes several answers per prompt, so keep completions short while experimenting.
Can I learn LLM fine-tuning methods like SFT and DPO in Indore?
Debugshala offers a Generative AI course for career switchers and fresh graduates at its Old Palasia campus, taught in English and Hindi, with placement assistance and a free demo class. Since these methods are built on probability and Python, practise probability and Python MCQs on Debugshala Test too.
From the team behind this site
Go further with the Generative AI Course at Debugshala
These tutorials are written by Debugshala, a training and placement institute at Old Palasia, Indore. The classroom course adds live mentoring, real projects and interview preparation.
- Offline classes at Old Palasia, Indore
- Free demo class before you pay
- Non-IT, fresher and year-gap friendly
- Placement assistance
700+ students placed · 200+ hiring partners · 4.9★ Google rating