Chapter 5 · Book pages 142–150
PPO — Proximal Policy Optimization
The big picture
Chapter 4 ended with a promise: stage 3 of the pipeline is PPO, and this chapter is the reason. Vanilla policy gradient has a fatal flaw — no constraint on step size. A single unlucky batch can push the policy into a region where it generates garbage; garbage gets low rewards; the next gradient makes things worse; the collapse is unrecoverable. PPO's entire contribution is a cheap way to take safe steps.
Stop 1 — Motivation: from TRPO to PPO
The first serious fix was TRPO (2015): constrain the KL divergence between the old and new policy so updates stay inside a trust region. It works perfectly — but requires expensive second-order optimization: the Fisher information matrix and conjugate gradients.
Go deeper: why second-order hurts at 70B scale
TRPO's constraint DKL(πθold ‖ πθ) ≤ δ is enforced exactly, but computing it needs curvature information (the Fisher matrix) and iterative solves (conjugate gradients) — machinery that is painful to distribute across hundreds of GPUs. PPO replaces the hard constraint with a soft, per-sample clip that any first-order optimizer (Adam over mini-batches) can apply. Book §5.1, 5.4.4, p. 142–143.
Stop 2 — The clipped objective
The core innovation. Define the probability ratio between the live policy and the frozen snapshot that collected the data, rt(θ) = πθ(at|st) / πθold(at|st). PPO's objective:
LCLIP(θ) = Et [ min( rt(θ)Ât, clip(rt(θ), 1−ε, 1+ε)Ât ) ] (5.1)
The min operator creates a pessimistic bound. For a good action ( > 0) we want to raise its probability — r grows with r, but the clip caps the benefit at r = 1 + ε: "don't get greedy on one good example." For a bad action ( < 0) we want to lower its probability — r improves as r falls, but the clip caps the benefit at r = 1 − ε: "don't forget too aggressively based on one bad example."
Interactive · Clip explorer
Slide the ratio r and the advantage  — watch r·Â, clip(r)·Â, and the pessimistic min, and see whether the gradient flows (the four cases of eq. 5.9).
Go deeper: the four gradient cases of eq. 5.9
With Lt = min(rtÂt, r̄tÂt), the gradient is ∇rt·Ât when the unclipped term is smaller, and exactly 0 when the clipped term is smaller. Expanded: Â > 0 and r < 1 + ε → gradient flows (keep pushing up); Â > 0 and r ≥ 1 + ε → gradient zero (already increased enough); Â < 0 and r > 1 − ε → gradient flows (keep pushing down); Â < 0 and r ≤ 1 − ε → gradient zero (already decreased enough). Clipping removes the incentive to move, not the ability — a soft wall, not a hard one. Book §5.2, 5.4.5, p. 142–144.
Stop 3 — The full PPO loss
The clipped policy term is one of three ingredients:
L = LCLIP − c₁(Vθ(st) − Vttarget)² + c₂H[πθ(·|st)] (5.2)
Go deeper: the full derivation in six steps (§5.4)
(1) Objective: maximize expected cumulative reward J(θ) (5.3). (2) Policy gradient theorem: ∇J = E[Σ ∇ log π·Ât] (5.4) — the advantage replaces the full return to cut variance. (3) Importance sampling: PPO collects data with πθold but updates πθ; correcting the mismatch turns the objective into the surrogate LCPI = E[rt(θ)·Ât] (5.5–5.7). (4) Unconstrained, one step can push r far from 1.0 — importance weights explode, the policy enters untested regions where the reward model is unreliable, collapse follows; TRPO's answer is the hard KL constraint. (5) PPO clips the surrogate instead (5.8–5.9). (6) Combine: θk+1 = θk + α·∇[LCLIP − c₁LVF + c₂H] (5.10–5.12). The book's summary: importance sampling enables data reuse across epochs, clipping keeps weights from going extreme, the min takes the more conservative of the two — "monotonic improvement with probability 1, using only first-order gradients" (the book's claim, §5.4.6). Book §5.4.1–5.4.6, p. 143–144.
Stop 4 — The rollout buffer
A rollout is one trajectory from the current policy — for RLHF, one prompt answered token by token until end-of-text, each token a "step". The rollout buffer stores, per token:
B = { (st, at, log πθold(at|st), rt, V(st)) } (5.13)
— state, action, the log-probability under the exact policy that generated it (for the ratio), reward, and the value baseline (for GAE). The buffer runs a strict three-phase clockwork: collect (a 70B model with batch 128 × 512 tokens produces up to 65K token-level transitions), train (GAE + K = 3–10 epochs of mini-batch descent on the clipped objective), purge (wipe it completely). Watch the cycle, and contrast it with a replay buffer:
Interactive · Rollout-buffer lifecycle vs replay buffer
Step through collect → train → purge and watch the ratio drift from 1.0; toggle to replay-buffer mode to see the off-policy alternative.
Go deeper: the numbers of one collect phase
Batch = 128 prompts × 512 max tokens → up to ~65K token-level transitions per rollout. K epochs typically 3–10 over that single buffer before the purge. The generation bottleneck at 60–70% of wall-clock is the direct consequence of on-policy data going stale — every update cycle must start with fresh rollouts. Book §5.5.1–5.5.3, p. 144–146.
Stop 5 — PPO for RLHF: the full loop
The book's concrete walkthrough, one PPO step for a 70B chat model (Llama-3-70B policy, batch of 128 prompts, 512 max tokens): the reward model scores each response, per-token KL is measured against the frozen reference policy, GAE advantages are whitened to zero mean and unit variance, and the update runs 4 epochs of mini-batches of 16:
Interactive · One PPO step for a 70B chat model
Walk the six steps with the book's actual numbers at each stage.
Go deeper: tokenization pitfalls
Tokenization decides what a "step" is, and that creates three subtle issues. KL accounting: the same semantic content tokenized differently sums to different total KL — rare words split into more subwords collect a higher total penalty. Credit assignment: GAE assigns advantage per token position, but the model only truly "decides" at the first token of a word; later subword tokens are largely deterministic. Reward placement: reward only at the final token means credit must propagate backward through GAE — longer responses get a more diluted signal. Mitigations: normalize KL by sequence length, word-level reward shaping, or rewards at semantic boundaries. Book §5.6, p. 146.
Stop 6 — Logits and the two-network mechanics
PPO holds two parameter states with the same topology: the live policy πθ, updated by backpropagation, and the old policy πθold, a frozen snapshot anchoring one optimization cycle. During rollout, the frozen snapshot emits raw logits zold (a vector of size |V| = 32K–128K), softmax turns them into probabilities, a token is sampled — and the log-probability log πθold(at|st) is stored as a scalar in the buffer.
rt(θ) = exp( log πθ(at|st) − log πθold(at|st) ) (5.20)
— exponentiating a difference instead of dividing raw probabilities, which would underflow or overflow numerically.
Go deeper: the weight lifecycle (table 5.1) and continuous actions
Across one cycle: at rollout start θ and θold are the same copy, so r = 1.0 by identity; as mini-batch steps accumulate, θ drifts from θold and r deviates (e.g. 1.06, 0.94); when clipping activates, r is trapped at 1 ± ε; at optimization end θold is discarded; the next cycle copies θ → θold and r resets to 1.0. For continuous action spaces (robotics, not LLMs), the network outputs a mean µ and standard deviation σ and log-probs come from the Gaussian log-PDF (5.22) — the ratio and clip then work identically. Book §5.7.1–5.7.5, p. 146–148.
Stop 7 — TRL implementation
The HuggingFace TRL library provides production-ready PPO for LLMs. The valuable part is the config — every hyperparameter from this chapter in one place (book's listing, values verbatim):
ppo_config = PPOConfig(
learning_rate=1.5e-6, # low LR for stability
batch_size=128, # prompts per step
mini_batch_size=16, # gradient accumulation unit
ppo_epochs=4, # epochs per batch (reuse data)
gamma=1.0, # no discounting (single turn)
lam=0.95, # GAE lambda
cliprange=0.2, # PPO epsilon
cliprange_value=0.2, # value function clipping
vf_coef=0.1, # value loss coefficient
init_kl_coef=0.05, # initial KL penalty
target_kl=6.0, # adaptive KL target
whiten_rewards=True, # normalize advantages
gradient_accumulation_steps=4,
max_grad_norm=1.0,
)
Around it: the model loads as AutoModelForCausalLMWithValueHead (a causal LM plus the critic's value head) with LoRA adapters (r = 64, α = 16, on the q/k/v/o projections), and the training loop per batch is generate (512 tokens, temperature 0.7, top-p 0.9) → score with the reward model → ppo_trainer.step(...), which handles KL, GAE, and clipping internally. Monitoring: stats["ppo/mean_scores"] and stats["ppo/policy/approx_kl"].
Go deeper: what the training loop hides
ppo_trainer.step(query_tensors, response_tensors, rewards) runs the whole stop-5 pipeline internally: per-token KL against the reference, final reward R = rRM − 0.05 × mean_KL, GAE with λ = 0.95 and γ = 1.0, advantage whitening, then 4 epochs × mini-batches of 16 with ε = 0.2. The generation call maps to the vLLM workers in production setups (OpenRLHF, TRL integrations). Book §5.6, 5.8, p. 146, 149–150.
Stop 8 — Critical hyperparameters
The book's danger table — each parameter, its typical value, and the cost of getting it wrong:
| Parameter | Typical | Effect of getting it wrong |
|---|---|---|
cliprange | 0.2 | Too low: no learning. Too high: instability. |
init_kl_coef | 0.01–0.1 | Too low: reward hacking. Too high: stuck at SFT. |
target_kl | 4–8 | Adaptive controller target. Lower = conservative. |
ppo_epochs | 4 | Too many: overfits to batch. Too few: wastes generation compute. |
learning_rate | 1–5 × 10⁻⁶ | Too high: catastrophic forgetting. |
batch_size | 64–256 | Larger = smoother gradients, more generation compute. |
temperature | 0.7–1.0 | Lower: less exploration. Higher: noisier advantages. |
Interactive · Hyperparameter danger board
Pick a parameter, slide it too low or too high, and see the book's stated consequence.
target_kl is 6.0 in the book's TRL config but 4–8 in this table — the config picks one point inside the typical band, the table gives the band. And init_kl_coef 0.05 (config) sits in the middle of the 0.01–0.1 range: low enough to learn, high enough to suppress reward hacking.