Group Relative Policy Optimization (GRPO) is a reinforcement-learning algorithm for language models that samples a group of completions for each prompt, scores them, and uses each completion's reward relative to the rest of its group as the advantage in a PPO-style clipped update. There is no learned value network. In the post-training stack it sits after supervised fine-tuning (or, in "zero" recipes, directly on a base model) and is the default optimiser for reinforcement learning with verifiable rewards: maths answers that can be checked, code that must pass tests, SQL that must return the right rows. It is also used with learned reward models, which is how it was first introduced.
Where GRPO came from and what it fixed#
GRPO was introduced by Zhihong Shao, Peiyi Wang, Qihao Zhu and colleagues at DeepSeek in DeepSeekMath (Shao et al., 2024). The paper's main contribution was a 120B-token maths pre-training corpus, but its RL section proposed a modification of PPO (Schulman et al., 2017) aimed squarely at memory. Standard RLHF with PPO keeps four networks in play: the policy being trained, a frozen reference copy for the KL penalty, a reward model, and a critic (value function) that is usually initialised from the reward model and trained alongside the policy. The critic is as large as the policy, needs its own gradients and optimiser state, and is hard to train well for language, where a reward typically arrives only at the last token of a long completion.
GRPO's observation is that you do not need a learned estimate of the expected reward if you can just measure it. Sample completions for the same prompt, and their mean reward is a Monte Carlo estimate of the value of that prompt under the current policy. Subtracting it from each completion's reward gives an advantage; dividing by the group standard deviation puts every prompt on a common scale. In DeepSeekMath, GRPO trained on roughly 144K GSM8K and MATH questions lifted DeepSeekMath-Instruct 7B from 82.9% to 88.2% on GSM8K and from 46.8% to 51.7% on MATH. A year later DeepSeek-R1 (DeepSeek-AI, 2025) used GRPO with rule-based rewards to train R1-Zero directly from a base model, and that result is what made GRPO the reference algorithm for reasoning RL.
The objective, symbol by symbol#
For a prompt drawn from the training distribution, sample completions from the policy that generated the batch, . Each completion is a token sequence of length with tokens . A reward function gives a scalar per completion. The per-token probability ratio between the policy being optimised, , and the sampling policy is
With outcome rewards, every token of completion gets the same advantage, the reward standardised within its group:
The GRPO objective from Shao et al. (2024), which is maximised, is
Here is the clipping range (0.2 is standard), the KL coefficient, and a frozen copy of the starting policy. The KL term is not computed exactly over the vocabulary. GRPO uses the per-token estimator known as from Schulman's note on approximating KL divergence:
It is non-negative for every sample and unbiased for the true KL when tokens come from . Unlike PPO-RLHF, which folds a KL penalty into the reward, GRPO adds it directly to the loss so it does not contaminate the advantage.
Why a group mean is a valid baseline
The policy-gradient theorem says for any baseline that does not depend on the sampled action, because . The best simple baseline is the expected reward , which is what a PPO critic tries to learn. The group mean is an unbiased estimate of built from fresh samples. Strictly, including itself in the mean introduces a small bias that shrinks the gradient by a factor of ; the leave-one-out baseline in RLOO (Ahmadian et al., 2024) removes it. In practice the difference is a constant rescaling absorbed by the learning rate.
The std division is the part that is not a baseline. It multiplies each prompt's gradient by , which for binary rewards with success fraction is . That weights prompts the model almost always fails (or almost always solves) more heavily than prompts near 50%. Liu et al. (2025) call this a question-level difficulty bias and remove it in Dr. GRPO, together with the factor, which they show favours long wrong answers.
GRPO next to PPO, RLOO and DAPO
The differences are concentrated in two places: how the advantage is computed, and how token losses are averaged.
| Method | Advantage for completion i | Loss aggregation | Extra networks |
|---|---|---|---|
| PPO (RLHF) | GAE from a learned critic, per token | mean over tokens in batch | critic, reward model, reference |
| RLOO | per sequence | reward model, reference | |
| GRPO | reference (if ), RM or verifier | ||
| Dr. GRPO | sum over tokens, divided by a constant | same as GRPO | |
| DAPO | (token level) | verifier only, no KL |
Read side by side, GRPO is PPO with the critic replaced by Monte Carlo, RLOO is GRPO without the std division or clipping, and DAPO is GRPO with four engineering fixes for long chain-of-thought training.
What the gradient looks like
Ignore clipping (it is inactive on the first update of each batch, where ) and set . Then the gradient of the objective for one group is
Every token in a completion that beat its group average has its log-probability pushed up, every token in a below-average completion is pushed down, and the step per token is . Two consequences follow directly. Tokens shared by good and bad completions (the problem restatement, the formatting) receive opposing pushes that roughly cancel, so the net signal concentrates on where completions differ. And because , a group in which every reward is equal contributes exactly nothing.
Worked example: one group by hand#
Take completions of a maths problem with a binary verifier. Two are correct: . The mean is . The population standard deviation is , so
The two correct completions get pushed up three times harder than each wrong one gets pushed down, and the advantages sum to zero (). Many implementations compute the standard deviation with Bessel's correction, as torch.std does by default; then and the advantages become and . Running these numbers in numpy reproduces both sets exactly.
Now suppose a correct completion is 200 tokens long and a wrong one 800 tokens. Under the aggregation the per-token weight is for the correct answer and for the wrong one. A long wrong answer is penalised per token about twelve times more gently than a short right answer is rewarded. That asymmetry is the length bias Dr. GRPO targets: when the model is wrong, being wrong at length is cheap.
Finally, the clip. Say after one inner gradient step the policy has raised a token in a correct completion from probability 0.50 to 0.65, so . With and , the surrogate is , the clipped branch, which has zero gradient. That token stops contributing until the next batch. If instead the token were in a wrong completion with and its probability had dropped to , the surrogate is again the clipped branch, and the push down stops.
The algorithm, step by step#
for step in range(num_steps):
prompts = sample_batch(dataset, B) # B prompts
with no_grad():
groups = [policy_old.generate(q, n=G, temperature=1.0) for q in prompts]
rewards = [[reward_fn(q, o) for o in g] for q, g in zip(prompts, groups)]
adv = [(r - mean(r)) / (std(r) + 1e-4) for r in rewards] # one scalar per completion
logp_old = policy_old.token_logprobs(prompts, groups)
logp_ref = ref.token_logprobs(prompts, groups) if beta > 0 else None
for epoch in range(mu): # mu = 1 is common
for mb in minibatches(prompts, groups, adv, logp_old, logp_ref):
logp = policy.token_logprobs(mb)
ratio = exp(logp - mb.logp_old)
surr = minimum(ratio * mb.adv, clip(ratio, 1 - eps, 1 + eps) * mb.adv)
kl = exp(mb.logp_ref - logp) - (mb.logp_ref - logp) - 1 if beta > 0 else 0
per_token = surr - beta * kl
loss = -mean_over_sequences(mean_over_tokens(per_token, mb.mask))
loss.backward(); optimizer.step(); optimizer.zero_grad()
policy_old.load_state_dict(policy.state_dict()) # sync generator weights
The loop has two phases with very different costs. Generation produces completions, typically with an inference engine such as vLLM holding a copy of the weights. Training then makes passes over those completions. With and a single minibatch the ratio is exactly 1, the clip never activates, and GRPO reduces to a REINFORCE estimator with a group baseline. Clipping only matters when you take several minibatch steps per batch, which is how most large runs amortise generation cost.
Data it needs
GRPO needs prompts, not completions. Each record is a prompt plus whatever the reward function needs to score an answer: a reference final answer for maths, unit tests for code, a schema and expected rows for SQL. A few thousand prompts is enough for a narrow task; reasoning runs use tens of thousands (DAPO-Math-17K has 17K, DeepSeekMath used about 144K). What matters more than count is the pass-rate distribution under the starting policy. Prompts the model solves 0% or 100% of the time produce zero-variance groups and contribute nothing; a useful set has a broad spread between, say, 10% and 90%. Measure it before training by sampling 8 to 16 completions per prompt.
Hyperparameters that matter#
| Parameter | Typical start | What it does and how to tune |
|---|---|---|
| Group size | 8 to 16 (DeepSeekMath used 64) | Variance of the baseline vs prompt coverage. Increase if most groups are zero-variance on hard prompts. |
| Learning rate | 1e-6 full FT; 1e-5 to 5e-5 LoRA | The single most sensitive knob. DeepSeekMath and DAPO both used 1e-6 with full fine-tuning. |
| (KL) | 0 to 0.04 | 0.04 in DeepSeekMath. Many reasoning recipes set it to 0; keep it when the reward is a learned model you can hack. |
| (clip) | 0.2 | Only matters with several minibatch steps per batch. DAPO raises the upper bound to 0.28. |
| (inner epochs) | 1 | More epochs reuse expensive rollouts but drift further off-policy; watch the clip fraction. |
| Sampling temperature | 1.0 | Lower temperature reduces group diversity and raises the zero-variance rate. |
| Max completion length | task-dependent | Truncated completions get reward 0 and look like failures; leave headroom. |
| Prompts per step | 64 to 512 | Larger batches smooth the gradient; DeepSeekMath used a batch of 1024. |
Tune in this order: get the reward function right on a held-out sample, pick and temperature so that fewer than half the groups are zero-variance, then sweep the learning rate over a factor of 3 in each direction for a few hundred steps. Only then touch and . Open-source trainers have also moved the defaults: TRL's GRPOTrainer now defaults to and token-level (DAPO-style) aggregation, citing Open-Reasoner-Zero (Hu et al., 2025) for the finding that the KL term is not essential. Check which loss your library is actually computing before comparing runs to a paper.
Compute and memory#
For full fine-tuning in mixed precision with Adam, the trainable policy costs about 16 bytes per parameter (bf16 weights and gradients plus fp32 master weights and two moments). A frozen bf16 reference adds 2 bytes per parameter. The generation engine holds another bf16 copy plus its KV cache. A rough rule for a policy with parameters:
For a 7B model that is roughly 112 GB of training state, 14 GB for the reference and 14 GB plus cache for generation, before activations, so a single 8-GPU node of 80 GB cards is comfortable. PPO with a same-size critic and reward model would add about 126 GB more. With LoRA the policy state shrinks to roughly the 2-byte frozen weights plus a small adapter, and the reference is free (disable the adapter to get it).
Time is dominated by generation. Each step generates completions; at , and a mean length of 1,000 tokens that is about a million tokens generated autoregressively per step, and those same million tokens then go through a forward pass for the old and reference log-probabilities and a forward and backward pass for the update. An SFT step on 128 examples of similar length processes an eighth as many tokens and never decodes. In practice a GRPO step costs several times an SFT step and a full GRPO run costs one to two orders of magnitude more than a DPO run on a comparable dataset, because DPO never samples.
A toy run: what the group baseline buys#
To see the mechanism without an LLM, we built a tabular model: 256 "prompts", each a softmax over 10 possible answers with one correct, rewarded if correct and otherwise (the convention DAPO uses). Logits start random so initial pass rates vary; the mean is 17.2%. The script is seeded and every number below is its output.
First, gradient quality on a single prompt with success probability . We draw 20,000 groups and measure the cosine between each group's gradient estimate and the true gradient of expected reward (a scale-free measure, so the std division does not flatter GRPO).
| Estimator | G = 4 | G = 8 | G = 16 |
|---|---|---|---|
| No baseline (REINFORCE on raw ) | 0.609 | 0.739 | 0.842 |
| Group mean baseline | 0.517 | 0.784 | 0.941 |
| GRPO (mean and std) | 0.517 | 0.784 | 0.941 |
| Zero-variance groups | 40.8% | 16.6% | 3.0% |
Three things show up. At and the group baseline gives a better-aimed gradient than raw REINFORCE. At it is worse, because 40.8% of groups are all-fail and contribute a zero vector, while REINFORCE still learns something from pushing down sampled wrong answers. And the std division changes nothing about direction within one prompt: it is purely a per-prompt step size. We also checked the 0/1 reward convention: there REINFORCE without a baseline scored 0.834 at , better than the group baseline, because failures carry zero reward and therefore no noise. Baselines matter most when rewards have an offset, which is the usual case once format bonuses or rewards enter.
Second, training. With 32 prompts per step, , 80 steps, and the learning rate tuned separately per estimator over {0.3, 1, 3, 10}, the mean pass rate rose from 17.2% to 89.7% with no baseline, 93.8% with the group mean, and 94.2% with GRPO (5 seeds, standard deviation under 1.1 points). Adding an exact KL penalty to the initial policy at gave final pass rates of 94.2%, 94.1%, 93.3% and 54.5%, with final KL of 2.02, 2.01, 1.97 and 0.82 nats. Small barely restrains a policy that is being pulled hard by a clean reward; it starts to bind only when it is comparable to the advantage scale. That matches why many verifiable-reward recipes drop it and why it earns its place when the reward is a learned model you are trying not to exploit.
Failure modes and how to spot them#
Zero-variance starvation. If most prompts are too hard or too easy, most groups have identical rewards and the effective batch shrinks. Log the fraction of groups with every step. Above 50% you are paying for rollouts that do nothing; filter prompts by pass rate or use DAPO's dynamic sampling, which resamples until the batch is full of informative groups.
Length drift. Mean completion length rising steadily while accuracy plateaus is the signature of the bias, especially on incorrect completions. Plot length separately for correct and incorrect answers; if the incorrect curve climbs faster, switch to a token-level or constant normaliser.
Entropy collapse. Token entropy falling fast in the first hundred steps, followed by a flat reward and a rising zero-variance rate, means the policy has become nearly deterministic and groups no longer explore. Raise the temperature, the upper clip bound, or .
Reward hacking. Reward climbing while held-out accuracy does not. With verifiers this usually means a parser gap (answers that the regex accepts but a human would not); with reward models it is the familiar over-optimisation. Keep a held-out evaluation with a stricter grader and read samples every few hundred steps.
Off-policy instability. With or asynchronous generation, watch the clip fraction (share of tokens on the flat part of Figure 2) and the approximate KL between and . A clip fraction above roughly 20% means the step is too big for the data you have.
Truncation noise. Completions cut off at the length limit score 0 regardless of quality. A rising truncation rate makes the reward curve fall for reasons unrelated to capability. Either mask truncated completions from the loss or raise the limit.
When to use GRPO, and what to use instead#
GRPO is the right default when you can score a completion automatically and you want the model to discover solutions better than any demonstration you could write. It is the wrong tool when you have no reliable reward, or when the behaviour you want is already present in data you could imitate.
| Situation | Use | Why |
|---|---|---|
| Checkable answers (maths, code, SQL, extraction against a schema) | GRPO or DAPO | Verifier rewards are cheap and hard to hack; no critic needed. |
| Same, but long chain-of-thought and lengths drifting | Dr. GRPO or DAPO | Remove length and difficulty bias; token-level loss. |
| Pairwise human preferences, no sampling budget | DPO, SimPO | Offline, one forward and backward per pair, no generation. |
| Learned reward model, dense or token-level signal needed | PPO | A critic gives per-token credit; GRPO only has sequence-level advantages. |
| Small sampling budget, few completions per prompt | RLOO or rejection sampling FT | Unbiased leave-one-out baseline; or just keep the good samples and run SFT. |
| Good demonstrations exist and the base cannot solve the task at all | SFT first | RL cannot reinforce what it never samples; pass rate 0 gives zero gradient. |
| A stronger teacher model is available | On-policy distillation | Dense per-token signal at a fraction of RL's sample cost. |
Minimal implementation#
The core of GRPO is about thirty lines on top of a model that can return per-token log-probabilities. The sketch below assumes completions are already generated and padded, with a mask marking completion tokens.
import torch
def grpo_advantages(rewards: torch.Tensor, G: int, scale: bool = True, eps: float = 1e-4):
"""rewards: (B*G,) ordered prompt-major. Returns (B*G,) advantages."""
r = rewards.view(-1, G)
a = r - r.mean(dim=1, keepdim=True)
if scale:
a = a / (r.std(dim=1, keepdim=True) + eps)
return a.view(-1)
def grpo_loss(logp, logp_old, adv, mask, logp_ref=None, beta=0.0, clip_eps=0.2):
"""logp, logp_old, logp_ref, mask: (N, T) per-token; adv: (N,)."""
ratio = torch.exp(logp - logp_old)
a = adv.unsqueeze(1)
surr = torch.minimum(ratio * a, torch.clamp(ratio, 1 - clip_eps, 1 + clip_eps) * a)
if beta > 0 and logp_ref is not None:
d = logp_ref - logp
surr = surr - beta * (torch.exp(d) - d - 1) # k3 estimator, per token
per_seq = (surr * mask).sum(1) / mask.sum(1).clamp(min=1) # 1/|o_i| (original GRPO)
return -per_seq.mean() # 1/G over the batch
# Usage inside a training step:
# logits = policy(input_ids).logits[:, :-1]
# logp = torch.gather(logits.log_softmax(-1), 2, input_ids[:, 1:, None]).squeeze(-1)
# loss = grpo_loss(logp, logp_old, grpo_advantages(rewards, G), completion_mask)
For real runs, use a library that handles generation and weight syncing. In TRL the equivalent is a GRPOTrainer with a Python reward function:
from trl import GRPOConfig, GRPOTrainer
def correct(completions, answer, **kw):
return [1.0 if extract_final(c) == a else 0.0 for c, a in zip(completions, answer)]
cfg = GRPOConfig(output_dir="out", num_generations=8, learning_rate=1e-6,
beta=0.04, epsilon=0.2, loss_type="grpo", max_completion_length=1024)
GRPOTrainer(model="your-sft-checkpoint", args=cfg, reward_funcs=correct,
train_dataset=ds).train()
Setting loss_type="grpo" and beta=0.04 reproduces the DeepSeekMath formulation; the library defaults implement the later variants. In POFE, GRPO is a recipe: you supply the prompt set and the reward function, and the run is judged on the metrics above, not on the reward curve alone.
Further reading#
Shao et al. (2024) is the primary source for the objective and the KL estimator; DeepSeek-AI (2025) shows GRPO at scale on a base model. Liu et al. (2025) and Yu et al. (2025) are the two essential critiques and repairs, covered in our Dr. GRPO and DAPO articles. Ahmadian et al. (2024) is the best argument that much of PPO's machinery is unnecessary for language models in the first place.
Frequently asked questions#
What is the difference between GRPO and PPO?
PPO estimates advantages with a learned value network (critic) and GAE. GRPO samples several completions per prompt and uses each completion's reward minus the group mean, divided by the group standard deviation, as the advantage. It keeps PPO's clipped ratio objective but drops the critic, which saves roughly the memory of a second full model.
What group size should I use for GRPO?
8 to 16 completions per prompt is a common starting point; DeepSeekMath used 64. Pick G so that fewer than half of groups have identical rewards on your prompt set. Larger groups give better-aimed gradients per prompt but cover fewer prompts for the same rollout budget.
Does GRPO need a KL penalty?
The original formulation uses a per-token KL estimator with beta = 0.04. Many recipes with rule-based verifiable rewards set beta to 0 and report no loss, and TRL now defaults to 0. Keep the KL term when the reward is a learned model that the policy could exploit.
Why does GRPO stop learning on some prompts?
If every completion in a group gets the same reward, all advantages are zero and the prompt contributes no gradient. This happens on prompts the model always solves or never solves. Filter prompts by current pass rate or resample such groups, as DAPO's dynamic sampling does.
Does GRPO need a reward model?
No. GRPO only needs a scalar score per completion. It was introduced with a learned reward model, but it is most often used with rule-based verifiers such as exact-match answer checks or unit tests.
Why do GRPO responses get longer during training?
Part of it is genuine: longer reasoning can help. Part of it is a bias from averaging the loss over each completion's own length, which penalises long wrong answers less per token. Dr. GRPO and DAPO change the normalisation to remove this effect.
References#
- Zhihong Shao, Peiyi Wang, Qihao Zhu, Runxin Xu, Junxiao Song, Mingchuan Zhang, Y. K. Li, Y. Wu, Daya Guo (2024). DeepSeekMath: Pushing the Limits of Mathematical Reasoning in Open Language Models. arxiv.org/abs/2402.03300
- DeepSeek-AI (2025). DeepSeek-R1: Incentivizing Reasoning Capability in LLMs via Reinforcement Learning. arxiv.org/abs/2501.12948
- John Schulman, Filip Wolski, Prafulla Dhariwal, Alec Radford, Oleg Klimov (2017). Proximal Policy Optimization Algorithms. arxiv.org/abs/1707.06347
- John Schulman (2020). Approximating KL Divergence. joschu.net/blog/kl-approx.html
- Zichen Liu, Changyu Chen, Wenjun Li, Penghui Qi, Tianyu Pang, Chao Du, Wee Sun Lee, Min Lin (2025). Understanding R1-Zero-Like Training: A Critical Perspective. arxiv.org/abs/2503.20783
- Qiying Yu, Zheng Zhang, Ruofei Zhu, Yufeng Yuan, Xiaochen Zuo, et al. (2025). DAPO: An Open-Source LLM Reinforcement Learning System at Scale. arxiv.org/abs/2503.14476
- Arash Ahmadian, Chris Cremer, Matthias Gallé, Marzieh Fadaee, Julia Kreutzer, Olivier Pietquin, Ahmet Üstün, Sara Hooker (2024). Back to Basics: Revisiting REINFORCE Style Optimization for Learning from Human Feedback in LLMs. arxiv.org/abs/2402.14740
- Jingcheng Hu, Yinmin Zhang, Qi Han, Daxin Jiang, Xiangyu Zhang, Heung-Yeung Shum (2025). Open-Reasoner-Zero: An Open Source Approach to Scaling Up Reinforcement Learning on the Base Model. arxiv.org/abs/2503.24290
- Hugging Face TRL maintainers (2025). TRL GRPO Trainer documentation. huggingface.co/docs/trl/main/en/grpo_trainer