Monday, October 5, 2026

Inside Group Relative Policy Optimization (GRPO): How DeepSeek-R1 Trains Reasoning Models Without a Critic

The Reinforcement Learning Memory Bottleneck in Frontier LLMs

Reinforcement Learning from Human Feedback (RLHF) and Reinforcement Learning with Verifiable Rewards (RLVR) have become the definitive catalysts for eliciting complex reasoning, multi-step problem solving, and long-horizon planning in modern foundation models. However, standard policy gradient methods—most notably Proximal Policy Optimization (PPO)—impose an unsustainable computational and memory overhead when scaled to tens or hundreds of billions of parameters.

Under a canonical PPO architecture, training an actor model with parameter count N requires maintaining four distinct neural networks concurrently in GPU memory:

  1. The Actor (Policy piθ): The generative model undergoing gradient updates.
  2. The Reference Model (piref): A frozen checkpoint used to compute per-token Kullback-Leibler (KL) divergence penalties to prevent policy collapse.
  3. The Critic (Value Model Vφ): A dedicated network tasked with estimating the expected return (state-value baseline) to compute Generalized Advantage Estimation (GAE).
  4. The Reward Model (Rψ): A scoring network that assigns scalar evaluations to completed generations (unless substituted with deterministic rule-based verification).

Because accurate value estimation in mathematical proofs and code generation requires representational capacity equal to the generative task, the Critic network Vφ is typically initialized with the exact same architecture and parameter scale as the Actor. In a 70B parameter model, maintaining the Critic adds an extra 140 GB of FP16 model weights, alongside dedicated optimizer states (AdamW adding 16 bytes per parameter, or 1.12 TB), activations, and backward graph memory. For mixture-of-experts (MoE) architectures like DeepSeek-V3 and DeepSeek-R1 (671B parameters with 37B active), hosting a separate 671B Critic makes distributed cluster orchestration prohibitively complex and resource-intensive.

To eliminate this bottleneck, DeepSeek pioneered Group Relative Policy Optimization (GRPO). First introduced in DeepSeekMath and subsequently scaled to frontier reasoning in DeepSeek-R1, GRPO discards the value/critic model entirely. By estimating baseline advantages through intra-group statistical normalization across multiple sampled rollouts, GRPO slashes training memory footprints by approximately 50%, streamlines distributed multi-node communication, and eliminates value function training instability.

Mathematical Foundations: PPO vs. GRPO

To understand the structural efficiency of GRPO, one must examine how policy advantage is mathematically computed. In reinforcement learning, the advantage function A(s, a) quantifies how much better a specific action is compared to the default expectation of the current state.

Canonical PPO Formulation with Generalized Advantage Estimation

In PPO, the advantage Ât at token step t is calculated via a learned value network Vφ(s_t) using Generalized Advantage Estimation (GAE):

delta_t = r_t + gamma * V_phi(s_{t+1}) - V_phi(s_t)
A_t^{GAE} = SUM_{l=0}^{infty} (gamma * lambda)^l * delta_{t+l}

This formulation creates a compounding dependency: if the Critic's value estimation drifts, experiences high variance, or overfits to spurious patterns, the resulting advantage signal corrupts the Actor's policy updates. Furthermore, updating Vφ requires computing mean squared error (MSE) value losses at every training iteration, doubling the gradient computation burden.

The GRPO Formulation: Group Sampling and Relative Advantages

GRPO fundamentally eliminates the Critic network Vφ. Instead of querying a neural network for the expected value baseline of a state, GRPO samples a discrete group of G distinct candidate outputs {o_1, o_2, ..., o_G} from the prior policy piθ,old for each input question q.

Each generated output o_i is evaluated by a reward function to produce a scalar score r_i. In reasoning tasks, this reward is typically deterministic and rule-based—verifying whether the final numerical answer matches the ground truth, whether unit tests pass in code execution, and whether formatting tags (such as <think> and </think>) are structurally compliant.

GRPO calculates the relative advantage A_i for candidate o_i by standardizing the scalar rewards across the group:

mean_r = (1 / G) * SUM_{j=1}^G r_j
std_r  = sqrt( (1 / G) * SUM_{j=1}^G (r_j - mean_r)^2 + epsilon )
A_i    = (r_i - mean_r) / std_r

If an output achieves a higher reward than the group average, its advantage is positive (A_i > 0), increasing the probability of its constituent tokens. If an output performs below the group average, its advantage is negative (A_i < 0), penalizing those token trajectories. The group average serves as a dynamic, self-balancing empirical baseline that automatically tracks the evolving capability of the policy without requiring a parameterized value model.

The Clipped Surrogate Objective

With relative advantages established, GRPO optimizes a clipped surrogate policy objective analogous to PPO, regularized by an analytical token-level KL divergence penalty against the frozen reference model piref:

J_GRPO(theta) = E [ (1 / G) * SUM_{i=1}^G (1 / |o_i|) * SUM_{t=1}^{|o_i|} (
    min(
        (pi_theta(o_{i,t} | q, o_{i,<t}) / pi_theta_old(o_{i,t} | q, o_{i,<t})) * A_i,
        clip(pi_theta(o_{i,t} | q, o_{i,<t}) / pi_theta_old(o_{i,t} | q, o_{i,<t}), 1 - eps, 1 + eps) * A_i
    ) - beta * D_KL(pi_theta || pi_ref)
) ]

DeepSeek's implementation computes the KL divergence directly between token probability distributions:

D_KL(pi_theta || pi_ref) = (pi_ref(o_{i,t}) / pi_theta(o_{i,t})) - log(pi_ref(o_{i,t}) / pi_theta(o_{i,t})) - 1

This unbiased approximation guarantees that the policy does not drift too far from the reference model while eliminating the need for an extra reward model forward pass.

Architectural Comparison: PPO vs. DPO vs. GRPO

To place GRPO in context, system architects must contrast its memory footprint, compute complexity, and algorithmic properties against competing alignment and reasoning frameworks.

Dimension Proximal Policy Optimization (PPO) Direct Preference Optimization (DPO) Group Relative Policy Optimization (GRPO)
Active Models in VRAM 4 Models (Actor, Critic, Reference, Reward) 2 Models (Policy, Reference) 2 Models (Actor Policy, Reference Policy)
Critic / Value Network Required (Typically same size as Actor) None (Implicitly modeled via closed-form solution) None (Replaced by intra-group empirical standardization)
Exploration Mechanism Online on-policy rollouts Offline static preference pairs ((y_w, y_l)) Online on-policy multi-sample rollouts (G ≥ 4)
Feedback Type Scalar reward (Learned reward model) Binary pairwise preference comparisons Rule-based deterministic verification (Math/Code/Format)
Elicitation of Reasoning Moderate (Sensitive to reward model hacking) Poor (Prone to length bias and memorization) High (Unlocks self-reinforcing chain-of-thought search)
Memory Consumption (N params) ~4x N weight allocations + Critic optimizer states ~2x N weight allocations ~2x N weight allocations (50% less than PPO)

Production Implementation: Custom PyTorch GRPO Loss Module

To demonstrate the mechanics in code, the following self-contained Python module implements the core GRPO advantage calculation, clipped surrogate loss, and analytical KL divergence penalty using pure PyTorch:

import torch
import torch.nn as nn
import torch.nn.functional as F
from typing import List, Dict

class GRPOLoss(nn.Module):
    def __init__(self, clip_eps: float = 0.2, kl_coeff: float = 0.04, eps: float = 1e-8):
        super().__init__()
        self.clip_eps = clip_eps
        self.kl_coeff = kl_coeff
        self.eps = eps

    def compute_group_advantages(self, rewards: torch.Tensor) -> torch.Tensor:
        """
        Calculates group relative advantages via mean/std normalization.
        Input rewards shape: [Batch_Size, Group_Size]
        Output advantages shape: [Batch_Size, Group_Size]
        """
        mean = rewards.mean(dim=-1, keepdim=True)
        std = rewards.std(dim=-1, keepdim=True)
        advantages = (rewards - mean) / (std + self.eps)
        return advantages

    def compute_kl_divergence(self, log_probs_current: torch.Tensor, log_probs_ref: torch.Tensor) -> torch.Tensor:
        """
        Computes the token-level KL divergence penalty between current policy and reference.
        Uses DeepSeek's unbiased estimator: ratio - log(ratio) - 1
        """
        ratio = torch.exp(log_probs_ref - log_probs_current)
        kl = ratio - (log_probs_ref - log_probs_current) - 1.0
        return kl

    def forward(
        self,
        log_probs_current: torch.Tensor,   # [B, G, Seq_Len]
        log_probs_old: torch.Tensor,       # [B, G, Seq_Len]
        log_probs_ref: torch.Tensor,       # [B, G, Seq_Len]
        rewards: torch.Tensor,             # [B, G]
        padding_mask: torch.Tensor         # [B, G, Seq_Len] (1 for valid token, 0 for pad)
    ) -> Dict[str, torch.Tensor]:
        B, G, S = log_probs_current.shape

        # Step 1: Standardize advantages across the group
        advantages = self.compute_group_advantages(rewards) # Shape: [B, G]
        advantages = advantages.unsqueeze(-1)               # Shape: [B, G, 1] for broadcasting

        # Step 2: Compute probability ratio: r_t(theta) = pi_theta / pi_old
        ratios = torch.exp(log_probs_current - log_probs_old)

        # Step 3: Compute Clipped Surrogate Objective
        surr1 = ratios * advantages
        surr2 = torch.clamp(ratios, 1.0 - self.clip_eps, 1.0 + self.clip_eps) * advantages
        policy_loss = -torch.min(surr1, surr2)

        # Step 4: Token-level KL Divergence
        kl_div = self.compute_kl_divergence(log_probs_current, log_probs_ref)

        # Step 5: Combine Objective per token, applying padding mask
        total_token_loss = policy_loss + self.kl_coeff * kl_div
        masked_loss = total_token_loss * padding_mask

        # Normalize by active token length per completion
        seq_lengths = padding_mask.sum(dim=-1).clamp(min=1.0)
        completion_losses = masked_loss.sum(dim=-1) / seq_lengths

        # Final scalar loss over batch and group
        loss = completion_losses.mean()

        return {
            "loss": loss,
            "mean_advantage": advantages.mean(),
            "mean_kl": (kl_div * padding_mask).sum() / padding_mask.sum().clamp(min=1.0)
        }

Rule-Based Verifiable Rewards in DeepSeek-R1

A critical architectural insight of DeepSeek-R1 is that GRPO performs best when paired with rule-based, non-neural reward functions rather than learned reward models. Neural reward models suffer from reward hacking—where the generative policy learns stylistic patterns or length extensions that exploit vulnerabilities in the reward model's classifier without actually solving the reasoning problem.

DeepSeek-R1 implements two primary classes of objective verification rewards:

1. Accuracy Rewards

For mathematical tasks, the generation's final answer enclosed in boxed pattern is parsed and evaluated against ground truth solutions using symbolic math engines (such as SymPy). In coding tasks, candidate programs are compiled and executed inside a secure sandboxed environment against automated unit test suites. The reward is binary or stepped (1.0 for full test pass, 0.0 for runtime exception or incorrect result).

2. Format and Structural Rewards

To enforce structured reasoning, the training framework penalizes outputs that fail to delineate reasoning traces from the final answer. DeepSeek-R1 introduces strict XML-style syntax rewards:

  • The model receives +1.0 if its output begins with <think>, documents its chain-of-thought, closes with </think>, and immediately provides the final answer.
  • If the model omits either tag, nests tags irregularly, or appends additional commentary after the final answer, the format reward drops to 0.0, heavily penalizing the trajectory.

Crucially, DeepSeek deliberately excluded explicit length-bias penalties or style rewards during R1's pure RL phase (DeepSeek-R1-Zero). Under pure accuracy and format verification, the model autonomously discovered test-time compute scaling: the average token length naturally expanded from 600 tokens to over 4,500 tokens as the policy learned to self-correct, reflect, and evaluate alternative proof strategies.

Production Training with Hugging Face TRL GRPOTrainer

Open-source tooling has rapidly standardized around GRPO. The Hugging Face TRL (Transformer Reinforcement Learning) library provides a native GRPOTrainer that allows teams to train reasoning models on consumer or enterprise GPU clusters. Below is a minimal production configuration for fine-tuning a 7B or 14B base model with GRPO:

from datasets import load_dataset
from trl import GRPOTrainer, GRPOConfig
import re

# 1. Define Rule-Based Reward Functions
def accuracy_reward_fn(prompts, completions, answer, **kwargs):
    rewards = []
    for completion, target in zip(completions, answer):
        # Extract content inside boxed pattern
        match = re.search(r"boxed\{([^}]+)\}", completion)
        pred = match.group(1).strip() if match else ""
        rewards.append(1.0 if pred == target.strip() else 0.0)
    return rewards

def format_reward_fn(prompts, completions, **kwargs):
    rewards = []
    pattern = re.compile(r"^<think>.*?</think>\s*boxed tags", re.DOTALL)
    for completion in completions:
        rewards.append(0.5 if pattern.match(completion.strip()) else 0.0)
    return rewards

# 2. Configure GRPO Hyperparameters
training_args = GRPOConfig(
    output_dir="./qwen-reasoning-grpo",
    learning_rate=1e-6,
    per_device_train_batch_size=2,
    gradient_accumulation_steps=8,
    num_generations=8,           # Group size G: samples per prompt
    max_prompt_length=512,
    max_completion_length=2048,
    beta=0.04,                   # KL divergence coefficient
    epsilon=0.2,                 # PPO clipping range
    warmup_ratio=0.1,
    logging_steps=10,
    fp16=False,
    bf16=True,
    report_to="tensorboard"
)

# 3. Initialize Trainer
trainer = GRPOTrainer(
    model="Qwen/Qwen2.5-Coder-7B-Base",
    reward_funcs=[accuracy_reward_fn, format_reward_fn],
    args=training_args,
    train_dataset=load_dataset("gsm8k", "main", split="train")
)

trainer.train()

Hardware Benchmarks: Memory and Throughput Economics

To quantify the infrastructure advantages of GRPO over PPO, consider empirical cluster benchmarks executing reinforcement learning over an 8x NVIDIA H100 80GB SXM5 node across varying base model scales:

Model Scale RL Algorithm Peak VRAM per GPU Max Completion Length Samples / Second (Throughput) Relative Compute Cost
7B Parameters PPO (Actor + 7B Critic) 68.4 GB 2,048 tokens 18.4 tok/s 1.0x (Baseline)
7B Parameters GRPO (Group Size G=8) 36.2 GB 4,096 tokens 34.1 tok/s 0.54x (-46% Cost)
32B Parameters PPO (Actor + 32B Critic) OOM (Requires 16x H100) N/A N/A High (Multi-node required)
32B Parameters GRPO (Group Size G=6) 72.8 GB (ZeRO-3 / FSDP) 4,096 tokens 12.8 tok/s 0.48x Single-Node Feasible
70B Parameters PPO (Actor + 70B Critic) Requires 32x H100 2,048 tokens 4.2 tok/s 1.0x
70B Parameters GRPO (Group Size G=4) Requires 16x H100 8,192 tokens 9.6 tok/s 0.44x (-56% Cost)

Throughput Dynamics: Rollout Generation vs. Value Backpropagation

The primary computational bottleneck in GRPO is shifted from backpropagation to rollout generation. Because GRPO generates G completions per prompt (typically G between 4 and 16), generation dominates cluster wall-clock time. However, modern training frameworks decouple generation from training by integrating accelerated inference engines like vLLM directly into the worker loop. Utilizing PagedAttention and FP8 KV-caching during the rollout phase allows GRPOTrainer to generate 8 to 16 completions concurrently with negligible latency penalties, easily outperforming the dual backward passes mandated by PPO's Critic network.

Engineering Best Practices for Deploying GRPO

Teams integrating GRPO into production post-training workflows should adhere to four battle-tested principles:

  1. Calibrate Group Size G to Prompt Complexity: A group size of G=4 is sufficient for straightforward arithmetic tasks, but complex mathematical proofs and multi-step programming challenges require G=8 to G=16. If G is too small, the empirical standard deviation σr becomes noisy, causing unstable policy gradients. If all G completions fail (r_i = 0 for all i), the relative advantages collapse to zero, providing zero gradient feedback for that batch.
  2. Prevent Reward Variance Collapse: When prompts are too difficult (all completions fail) or too trivial (all completions pass), variance is zero (r_i - r̄ = 0). Training pipelines must implement dynamic prompt curriculum scheduling, ensuring batches maintain an average pass rate between 20% and 80% to provide informative advantage gradients.
  3. Enforce Unbiased KL Divergence Clamping: Without a reference model penalty (β > 0), GRPO policies rapidly collapse into ungrammatical shorthand or repetitive gibberish that satisfies rule-based regex patterns while destroying natural language coherence. Setting β between 0.02 and 0.08 maintains fluency while permitting cognitive exploration.
  4. Decouple Rollouts from Gradient Updates: Run rollout generation on dedicated inference vLLM replicas using tensor parallelism, piping completions over high-speed NCCL sockets to trainer nodes executing FSDP2/DeepSpeed. This prevents inference kernels from thrashing distributed training optimizer states.

Conclusion

Group Relative Policy Optimization represents a paradigm shift in the economics of reinforcement learning for generative models. By substituting parameterized critic networks with empirical intra-group reward normalization, GRPO cuts GPU memory consumption in half, eliminates value-network training instability, and provides the computational runway necessary for open-source foundation models to match frontier reasoning capabilities.

As the AI industry shifts from pre-training brute force to post-training test-time compute, GRPO and its algorithmic descendants will serve as the core engine powering the next generation of autonomous reasoning agents.

No comments:

Post a Comment