Group Relative Policy Optimization (GRPO) [323] is a reinforcement learning algorithm designed specifically for language models that eliminates the need for a separate value network (critic). Introduced by DeepSeek as part of their DeepSeekMath work and later scaled to DeepSeek-R1 [69], GRPO has rapidly become the dominant RL method for LLM training—adopted by most open-source alignment frameworks (TRL, OpenRLHF, veRL) as the default algorithm.

The core idea is deceptively simple: instead of training a neural network to predict expected reward (the critic in PPO), GRPO estimates it empirically by generating multiple responses to the same prompt and using the group’s reward statistics as a baseline. This removes an entire model from memory, halves the engineering complexity, and—surprisingly—often outperforms PPO because empirical baselines are more accurate than a poorly-trained value function.

GRPO is particularly effective for:

  • Reasoning tasks with verifiable rewards (math, code) where binary correctness provides a clean signal.
  • Large models (70B+) where the memory savings from removing the critic are critical.
  • Multi-turn and agentic settings where value estimation across tool calls is intractable.

This chapter covers GRPO’s motivation, algorithm, key variants (Dr. GRPO, DAPO, 2-GRPO, GDPO), and practical implementation with TRL.

Motivation

PPO’s value model (critic) has three major problems for language:

  1. Memory: The value head shares the policy backbone (140GB for 70B). Doubles memory if separate.
  2. Accuracy: Predicting expected reward for a partial sequence is extremely hard. The value function is often wrong → wrong advantages → wrong gradient direction.
  3. Training: Value head needs many samples to converge. During early RL, it gives noisy predictions that destabilize policy learning.

GRPO’s key insight[323]: Instead of learning V⁡(s), estimate it empirically from a group of samples. Generate G responses to the same prompt, compute their rewards, and use the group statistics as the baseline.

Algorithm

  1. For each prompt x, sample G completions: {y1,…,yG}∼πθ(⋅|x)
  2. Score each: ri=R⁡(x,yi)
  3. Normalize within group: A^i=ri−μGσG where μG=1G​∑jrj, σG=std​({rj})
  4. Apply PPO-style clipped update using these advantages
A^i=ri−μGσG,L=𝔼[min(rt(θ)A^i,clip(rt(θ),1±ϵ)A^i)]−βDKL[πθ∥πref](7.1)
Figure 7.1: GRPO in action: G=5G{=}5 responses are sampled for a single math prompt. Three are correct (r=1r{=}1), two a
Figure 7.1:GRPO in action: G=5 responses are sampled for a single math prompt. Three are correct (r=1), two are wrong (r=0). The group mean μG=0.6 acts as the baseline; correct responses receive positive advantage (reinforced), wrong ones receive negative advantage (suppressed).

TRL Implementation

The following shows a minimal working example using HuggingFace TRL.

from trl import GRPOConfig, GRPOTrainer
from transformers import AutoModelForCausalLM, AutoTokenizer
 
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2.5-7B-Instruct",
    torch_dtype=torch.bfloat16, attn_implementation="flash_attention_2")
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-7B-Instruct")
 
grpo_config = GRPOConfig(
    output_dir="./grpo_output",
    num_generations=8,           # G = group size
    temperature=1.0,             # High temp for diversity within group
    max_completion_length=2048,  # Max response length
    beta=0.04,                   # KL penalty coefficient
    learning_rate=1e-6,
    per_device_train_batch_size=2,  # Prompts per device (x8 gens = 16 responses)
    gradient_accumulation_steps=8,
    num_train_epochs=2,
    bf16=True,
    gradient_checkpointing=True,
    max_grad_norm=0.5,
    logging_steps=10,
    # vLLM generation for speed (critical for GRPO due to 8x generation)
    use_vllm=True,
    vllm_gpu_memory_utilization=0.7,
)
 
# Reward function: binary correctness for math
def reward_fn(completions, prompts, **kwargs):
    """Return list of floats: 1.0 if correct, 0.0 if wrong."""
    rewards = []
    for completion, prompt in zip(completions, prompts):
        answer = extract_answer(completion)
        expected = get_ground_truth(prompt)
        rewards.append(1.0 if answer == expected else 0.0)
    return rewards
 
# Can combine multiple reward functions!
def format_reward_fn(completions, **kwargs):
    """Bonus for using proper LaTeX formatting."""
    return [0.5 if "\\boxed{" in c else 0.0 for c in completions]
 
trainer = GRPOTrainer(
    model=model,
    args=grpo_config,
    reward_funcs=[reward_fn, format_reward_fn],  # Multi-objective!
    train_dataset=math_dataset,
    tokenizer=tokenizer,
)
trainer.train()

Group Size Analysis

GSignal QualityComputeWhen to Use2Very noisy (coin flip)LowNever recommended — too noisy for stable learning4ModerateModerateQuick experiments, easy tasks (pass rate > 50%)8Good (standard)HighDefault. Good balance for most tasks16ExcellentVery highHard tasks (pass rate < 20%), need many attempts to get positives32Near-perfectExtremeOnly if you have massive compute and very hard task

GRPO Variants and Extensions

Diversity in GRPO Groups

MethodHow It Promotes Diversity
Entropy bonusAdd α​H​(πθ) to the reward. Directly penalizes low-entropy (deterministic) policies.
KL penalty−βDKL[πθ∥πref] prevents collapse toward a single mode.
Rejection samplingGenerate many candidates, keep top-k by reward. Naturally selects for diverse high-quality responses.
Best-of-NAt inference: generate N responses, score all, return the best. Diversity comes from sampling.
DPO with diverse pairsTrain on pairs where chosen/rejected differ in approach, not just quality.
Multi-rewardUse multiple reward models (safety, helpfulness, code quality). Prevents collapsing to one dimension.

Table 7.1:Diversity-promoting methods for RL training.

Post-training alignment (RLHF, DPO) often reduces output diversity due to typicality bias: human annotators systematically prefer familiar, “typical” text over novel alternatives. This mode collapse is a data-level phenomenon, not purely algorithmic.

Verbalized Sampling (VS) [422] is a training-free prompting strategy that circumvents this collapse by asking the model to explicitly verbalize a probability distribution over multiple responses in a single generation.

# Verbalized Sampling: prompt model to output distribution
def verbalized_sample(model, tokenizer, task, n=5):
    prompt = (
        f"{task}\n\n"
        f"Generate {n} different responses and assign a probability "
        f"to each (probabilities should sum to 1.0). "
        f"Format: [response] (probability: X.XX)"
    )
    output = model.generate(
        tokenizer(prompt, return_tensors="pt").input_ids,
        max_new_tokens=1024,
        temperature=0.7,
        do_sample=True,
    )
    # Parse responses and probabilities from output
    responses, probs = parse_verbalized_distribution(
        tokenizer.decode(output[0])
    )
    # Sample from the verbalized distribution
    import random
    chosen = random.choices(responses, weights=probs, k=1)[0]
    return chosen

Before diving into the extensions, let us briefly recap the base GRPO algorithm established in the previous sections. The core mechanism—sampling a group of completions, normalizing their rewards, and applying a clipped policy gradient—is elegant in its simplicity. However, practitioners quickly discovered specific failure modes: pretraining bias diluting gradients (Dr. GRPO), symmetric clipping limiting exploration (DAPO), wasteful large group sizes (2-GRPO), and reward-scale imbalance in multi-objective settings (GDPO). The following sections address each of these in turn.

DAPO – Dynamic Adaptive Policy Optimization

Standard PPO/GRPO clips the importance ratio symmetrically at [1−ϵ,1+ϵ]. DAPO replaces this with an asymmetric band:

clipDAPO​(ρ,A)={clip⁡(ρ, 1−ϵ, 1+ϵhigh)if ​A>0clip⁡(ρ, 1−ϵ, 1+ϵ)if ​A≤0

where ϵhigh>ϵ (typical values: ϵ=0.2, ϵhigh=0.28). When the advantage is positive the policy is allowed to move further toward the good token; when the advantage is negative the usual conservative clipping applies to avoid over-suppression.

Base GRPO divides the loss by the number of sequencesG. DAPO divides by the total number of tokens across all sequences:

ℒtoken=−1∑i=1G|oi|∑i=1G∑t=1|oi|min(ρi,tA^i,clipDAPO(ρi,t,A^i)A^i).

This prevents long completions from dominating the gradient signal simply because they contain more tokens.

When a completion is truncated (no EOS token within the maximum length budget), it provides misleading signal: the model is penalised for tokens that were generated correctly but happened to appear before the truncation boundary. DAPO masks these completions entirely:

mi=𝟏[EOS∈oi],ℒfiltered=−∑i=1Gmi​∑t(⋯)∑i=1Gmi​|oi|.

Rather than a hard mask, a softer variant applies a length penalty that grows smoothly as completions approach the maximum length Lmax:

ri←ri−λ⋅max⁡(0,|oi|−LcacheLmax−Lcache),

where Lcache is a “safe” length threshold.

DAPO re-samples prompts whose entire group of completions receives the same reward (all correct or all incorrect), because such groups contribute zero gradient after normalisation. This keeps the effective batch size stable throughout training.

GSPO – Group Sequence Policy Optimization

GSPO [51] defines a sequence-level importance weight as the geometric mean of per-token ratios, which equals the |oi|-th root of the full sequence probability ratio:

si​(θ)=(πθ​(oi∣q)πold​(oi∣q))1/|oi|=exp⁡(1|oi|​∑t=1|oi|log⁡πθ​(oi,t|q,oi,<t)πold​(oi,t|q,oi,<t)).

This is the length-normalised sequence probability ratio. The GSPO loss clips this single scalar per sequence:

ℒGSPO=−1G∑i=1Gmin(si(θ)A^i,clip(si(θ),1−ϵ,1+ϵ)A^i).

Dr. GRPO – Debiased Reward GRPO

Dr. GRPO modifies the per-token gradient weight to account for the token’s marginal contribution to the reward signal. Tokens that the model already assigns high probability to (regardless of the reward) are down-weighted:

wi,t=A^i⋅(1−πref​(oi,t|q,oi,<t)),

where πref is the reference (pretrained) model. This is a form of token efficiency: the gradient is concentrated on tokens where the policy genuinely needs to change.

2-GRPO – Minimal Two-Rollout GRPO

The key insight is that GRPO’s effectiveness does not primarily come from accurate advantage estimation (which requires large G). Instead, it comes from an implicit contrastive objective that is structurally similar to DPO:

ℒ2-GRPO≈−𝔼(o+,o−)∼πθ​[log⁡σ⁡(β​log⁡πθ​(o+|q)πold​(o+|q)−β​log⁡πθ​(o−|q)πold​(o−|q))],

where o+ is the higher-reward completion and o− the lower-reward one. With G=2, this contrastive structure is explicit. With G=16, the same signal is present but diluted by redundant pairs.

SAPO – Soft Adaptive Policy Optimization

SAPO replaces the min⁡(ρ​A,clip⁡(ρ,⋅)​A) objective with a smooth surrogate:

ℒSAPO​(ρ,A)={−A⋅σ(ρ−1τ+)⋅ρif ​A>0−A⋅σ(1−ρτ−)⋅ρif ​A≤0

where σ is the sigmoid function and τ+,τ− are asymmetric temperature parameters. A higher temperature produces a softer gate (more exploration); a lower temperature approaches hard clipping.

TIS and MIS – Truncated and Masked Importance Sampling

TIS corrects the bias by multiplying the gradient by a truncated correction factor:

wTIS​(oi)=min⁡(C,πtrain​(oi|q)πvllm​(oi|q)),

where πtrain is the probability from the training forward pass and πvllm is the probability reported by vLLM. The truncation at C prevents extreme corrections from destabilising training.

MIS takes a harder approach: it zeros out the gradient for any sequence where the correction ratio exceeds a threshold C:

wMIS(oi)=[πtrain​(oi|q)πvllm​(oi|q)≤C].

This is more conservative but avoids the risk of large (even truncated) correction weights.

Both TIS and MIS can be applied at the token level or the sequence level:

  • Sequence-level: compute the ratio as the geometric mean over all tokens (as in GSPO). Theoretically correct but higher variance.
  • Token-level: compute a separate ratio for each token. Biased (the product of per-token corrections is not the sequence correction) but lower variance.

VESPO – Variational Sequence-Level Soft Policy Optimization

VESPO derives a weighting function W⁡(τ) for each trajectory τ from the variational objective. The final gradient weight takes the form:

g⁡(τ)=W​(τ)k⋅exp⁡(λ⁡(1−W⁡(τ))),

where W⁡(τ)=πθ​(τ)/πold​(τ) is the sequence-level importance weight, k controls the sharpness of the weighting, and λ controls the exponential decay for stale (low-weight) trajectories. This kernel:

  • Is smooth everywhere (no discontinuous gradient at clip boundaries).
  • Naturally down-weights stale trajectories (W≪1) via the exponential term.
  • Is asymmetric: high-weight trajectories (W>1) are treated differently from low-weight ones.

DPPO – Direct Policy Divergence Policy Optimization

DPPO computes the trust region constraint directly using either Total Variation (TV) or KL divergence between the old and new policy distributions:

ℒDPPO=−𝔼[A^⋅πθ(o|q)⋅𝟏[D(πθ∥πold)≤δ]],

where D is the chosen divergence measure. In practice, DPPO approximates this with token-level binary or top-k masks:

  • binary_tv: mask tokens where |πθ−πold|>δ.
  • binary_kl: mask tokens where πθ​log⁡(πθ/πold)>δ.
  • topk_tv: keep only the top-k tokens by TV contribution.
  • topk_kl: keep only the top-k tokens by KL contribution.

ScaleRL and CISPO

Standard GRPO normalises rewards within a group of G completions for a single prompt. CISPO normalises rewards across the entire batch:

A^i=ri−μbatchσbatch+ϵ,

where μbatch and σbatch are computed over all rewards in the current training batch. This provides a more stable baseline and prevents any single prompt from dominating the gradient.

CISPO combines batch-level scaling with DAPO’s token-level loss aggregation and asymmetric clipping:

ℒCISPO=−1∑i,tmi,t∑i=1G∑t=1|oi|mi,t⋅min(ρi,tA^i,clipDAPO(ρi,t,A^i)A^i),

where mi,t is the overlong-filtering mask.

GDPO – Group Reward-Decoupled Policy Optimization

The core mechanism normalises each reward independently before aggregating:

A^n(i)=rn(i)−μnσn+ϵ,A^(i)=∑n=1NwnA^n(i),

where rn(i) is the n-th reward for completion i, μn and σn are the mean and standard deviation of reward n within the group, and wn are user-specified weights.

GOPO – Group Ordinal Policy Optimization

GOPO [54] starts from a simple observation: reward models are trained with pairwise comparisons (“is A better than B?”), so only the rank order of their outputs is trustworthy—the raw numeric scores carry no inherent meaning. Yet GRPO feeds those raw magnitudes directly into the advantage calculation. For tasks with non-verifiable rewards—summarization, open-ended chat, instruction following—this mismatch introduces noise, because a gap of 0.6 reward points might reflect genuine quality in one region of the output space and mean nothing in another.

Key Insight: Discard reward magnitudes entirely. Use only the ordinal ranking of rewards within a group.

Algorithm: Given a group of N responses {o1,…,oN} with rewards {r1,…,rN}:

  1. Rank responses by reward: assign rank rank​(oi)∈{1,…,N} (1 = worst, N = best).
  2. Replace raw advantages with rank-based scores:A^iGOPO=f⁡(rank​(oi)N)(7.2)where f is a monotonic transformation (e.g., linear mapping to [−1,1] or quantile normalization).
  3. Apply PPO-style clipped objective using rank-based advantages.

Comparison with GRPO:

AspectGRPOGOPOAdvantage signalA^i=(ri−μ)/σ (uses magnitudes)A^i=f⁡(ranki/N) (uses ordinal rank only)Sensitivity to reward scaleHigh — miscalibrated RM scores distort advantagesNone — invariant to monotonic reward transformationsBest forVerifiable rewards (binary, well-calibrated)Non-verifiable rewards (RM-based, noisy magnitudes)

Empirical gains (over GRPO on non-verifiable tasks):

  • Reward curves (both training and held-out) sit above GRPO throughout optimization
  • Win-rates judged by a separate LLM evaluator improve at most training checkpoints
  • Convergence is markedly faster—matching GRPO’s final quality with fewer gradient steps
  • The advantage grows as the reward model becomes noisier or more poorly calibrated