Proximal Policy Optimization: Clipped Surrogate and Trust Regions
4115 words
21 min read
Visual companion
Python
Type and operator map
Python Week 1: the first filter for runtime behavior
View
Revision summary
What this note is really saying
Short form
# Proximal Policy Optimization: Clipped Surrogate and Trust Regions ## 🎯 Learning Objectives - Understand why unconstrained policy updates can collapse performance - Derive and implement the PPO clipped surrogate objective - Compare PPO-Clip and PPO-Penalty variants - Implement PPO with multiple epochs of minibatch...

Proximal Policy Optimization: Clipped Surrogate and Trust Regions
🎯 Learning Objectives
- Understand why unconstrained policy updates can collapse performance
- Derive and implement the PPO clipped surrogate objective
- Compare PPO-Clip and PPO-Penalty variants
- Implement PPO with multiple epochs of minibatch updates
- Apply PPO to continuous and discrete action spaces
📋 Prerequisites
- Actor-Critic Methods (Week 9): A2C, advantage estimation
- Policy Gradients (Week 8): REINFORCE, policy gradient theorem
- Trust Region Concepts: Why large policy updates are dangerous
1. 📖 Core Content
1.1 Intuition: Why Not Just Use A2C with Larger Learning Rates?
A2C makes a small policy update every n steps. If we set the learning rate too high, the policy changes too much in one update and collapses — the agent suddenly starts making terrible decisions and never recovers.
Why? Consider a policy that has a 70% chance of taking action A (good) and 30% chance of taking action B (bad). After one advantage estimation, it updates to 95% A, 5% B. This seems good! But if the advantage estimate was noisy, maybe A isn't actually better. Now the policy is very confident in a suboptimal action.
PPO solves this by limiting how much the policy can change in one update. It's like having a "speed limit" for policy learning.
PPO is the default algorithm for many RL applications because it's:
- Stable: Rarely catastrophically fails
- Sample efficient: Reuses data for multiple updates
- Simple: No complex second-order optimization (unlike TRPO)
- General: Works for discrete, continuous, and image-based tasks
1.2 The Problem with Large Policy Updates
For a policy gradient update:
If α is too large:
- The policy changes dramatically
- New policy generates very different state distribution
- Old advantage estimates no longer apply
- Policy gets worse, which changes distribution further
- Collapse The core issue: our loss function approximates the true return only for the current policy. For a very different policy, the loss is inaccurate.
1.3 PPO's Solution: Clipped Surrogate Objective
1.3.1 The Probability Ratio
Define the probability ratio:
When rt(θ)>1, action at is more likely under the new policy. When rt(θ)<1, action at is less likely.
The standard policy gradient objective can be rewritten:
But this can be expressed as:
This is the "conservative policy iteration" objective. Without constraints, maximizing it can lead to excessively large policy updates.
1.3.2 The Clipped Objective
PPO-Clip clips the probability ratio to stay within [1−ϵ,1+ϵ]:
(Diagram)
Why clipping works:
- If At>0 (good action): The objective increases with rt, but only up to 1+ϵ. Beyond that, the gradient is 0 — no incentive to make a good action even more likely.
- If At<0 (bad action): The objective decreases as rt drops, but only to 1−ϵ. Below that, the gradient is 0 — no incentive to make a bad action even less likely. The clipping acts as a regularizer: it removes the incentive to change the policy beyond a certain amount per update, regardless of how large the advantage is.
Worked Example 1: PPO Clipping in Action
Consider an action with advantage A=2.0 (strongly positive). Current policy probability: 0.3. Old policy probability: 0.2. ε=0.2.
r=0.3/0.2=1.5
Without clipping: contribution to objective = 1.5 × 2.0 = 3.0 With clipping: min(1.5×2.0,1.2×2.0)=min(3.0,2.4)=2.4
The clipped contribution (2.4) is less than the unclipped (3.0). The gradient will push the policy to increase the probability of this action, but the clipping limits how much.
Now, another action with advantage A=-1.0 (negative). Current: 0.5. Old: 0.3.
r=0.5/0.3=1.667
Unclipped: 1.667 × (-1.0) = -1.667 Clipped: min(1.667×(−1.0),1.2×(−1.0))=min(−1.667,−1.2)=−1.667
Wait — both are -1.667 because the min of -1.667 and -1.2 is -1.667 (more negative). So the clipping doesn't kick in for the negative case?
Let me reconsider: when A < 0, we want to minimize r⋅A (make it as negative as possible, which decreases the probability). The clipped branch (1+ε)A is -1.2. The min of -1.667 and -1.2 is -1.667 (unclipped). So we still use the unclipped value!
This means for negative advantages, the ratio can increase without bound, which would decrease the probability. The clipping only prevents the ratio from increasing too much when A > 0 or decreasing too much when A < 0.
Actually, let me re-read the clipping logic more carefully.
The CLIP objective uses min(rA,clip(r,1−ε,1+ε)A).
When A > 0:
- If r < 1-ε: clip to lower bound (1-ε)A < rA → min chooses (1-ε)A (lower) → objective is reduced
- If r > 1+ε: clip to upper bound (1+ε)A > rA → min chooses rA (lower) → objective is reduced Wait, I got confused. Let me re-examine. For A > 0:
- clip(r, 1-ε, 1+ε)A =
- If r < 1-ε: (1-ε)A (which is < rA since A>0)
- If r between bounds: rA
- If r > 1+ε: (1+ε)A (which is < rA since A>0)
- min(rA, clip(r, 1-ε, 1+ε)A) will pick the smaller value
- If r < 1-ε: (1-ε)A < rA → pick (1-ε)A (clipped, lower bound)
- If r between: both are rA → pick rA
- If r > 1+ε: (1+ε)A < rA → pick (1+ε)A (clipped, upper bound) For A < 0:
- clip(r, 1-ε, 1+ε)A =
- If r < 1-ε: (1-ε)A (which is > rA since A<0 and 1-ε < r means multiply by negative flips sign)
- If r between bounds: rA
- If r > 1+ε: (1+ε)A (which is > rA since A<0)
- min(rA, clip(r, 1-ε, 1+ε)A) will pick the smaller value
- If r < 1-ε: rA < (1-ε)A → pick rA (unclipped)
- If r between: both rA → pick rA
- If r > 1+ε: rA < (1+ε)A → pick rA (unclipped) So for negative advantages, the clipping doesn't activate! The gradient can freely push the probability down. This asymmetry is intentional: decreasing bad action probability is always safe. Wait no, that's not right either. Let me be very precise. For A < 0, r < 1-ε:
- clip(r)A = (1-ε)A
- rA - (1-ε)A = A(r - (1-ε))
- Since A < 0 and r - (1-ε) < 0, A(r - (1-ε)) > 0 (product of two negatives)
- So rA > (1-ε)A
- min(rA, (1-ε)A) = (1-ε)A (clipped) OK I was wrong. Let me redo: For A < 0, r < 1-ε:
- A is negative, r < 1-ε
- rA = (large negative × negative?) → positive? No.
- r < 1-ε, so r is small. A is negative. rA is a small negative × negative = hmm... Actually, A < 0 means the advantage is negative. r is a ratio ≥ 0 (it's a ratio of probabilities). For A < 0, r < 1-ε:
- rA is negative (since r>0, A<0)
- clip(r)A = (1-ε)A is also negative (since 1-ε>0, A<0)
- Since r < 1-ε and A < 0: rA > (1-ε)A (multiplying inequality by negative flips it, but we need to be careful: r < 1-ε and A < 0, so rA = r×A > 1-ε×A = (1-ε)A... actually no. Multiplying an inequality by a negative flips it. A < 0, so r < 1-ε → rA > (1-ε)A.)
- So min(rA, (1-ε)A) = (1-ε)A (clipped!) For A < 0, r > 1+ε:
- clip(r)A = (1+ε)A
- r > 1+ε and A < 0: rA < (1+ε)A (multiplying by negative flips the inequality)
- So min(rA, (1+ε)A) = rA (unclipped) Ah, so for negative A:
- If r is very low (much less likely): clip to (1-ε)A (makes objective clip to less negative, i.e., the gradient to reduce probability is clipped)
- If r is very high (much more likely): no clipping (gradient flows freely to reduce probability) So PPO clips BOTH increasing AND decreasing probability by too much. Good. Let me just present a clearer version.
1.4 PPO Algorithm
textfor iteration = 1 to N: # Collect data with current policy for actor = 1 to N_workers: Run policy π_θ_old for T timesteps Store (s_t, a_t, r_t, s_{t+1}) # Compute advantages Compute GAE advantages A_t using V_φ(s_t) # Optimize surrogate objective (multiple epochs) for epoch = 1 to K: # Shuffle data into minibatches for minibatch in data: # Compute ratio r_t(θ) = π_θ(a_t|s_t) / π_θ_old(a_t|s_t) # Clipped surrogate L_CLIP = min(r_t * A_t, clip(r_t, 1-ε, 1+ε) * A_t) # Value function loss L_V = (V_φ(s_t) - G_t)^2 # or use clipped value loss # Entropy bonus L_S = H(π_θ(a|s_t)) # Combined loss L = -L_CLIP + c1 * L_V - c2 * L_S # Update θ, φ θ ← θ + α ∇_θ L φ ← φ + α_φ ∇_φ L_V # Update old policy θ_old ← θ
1.4.1 Key Hyperparameters
| Parameter | Typical Value | Effect |
|---|---|---|
| ε (clip) | 0.1-0.3 | Higher ε allows larger policy updates |
| K (epochs) | 3-15 | More epochs = more data reuse |
| Minibatch size | 32-256 | Smaller = more gradient steps per epoch |
| GAE λ | 0.9-0.97 | Higher λ = lower bias, higher variance |
| γ (discount) | 0.99-0.999 | Task-dependent horizon |
| c₁ (VF coefficient) | 0.5-1.0 | Weight of value loss |
| c₂ (entropy coeff) | 0.0-0.01 | Higher = more exploration |
1.5 PPO-Penalty (Adaptive KL)
An alternative to clipping: add a penalty for policy change:
The KL penalty coefficient β is adapted during training:
- If DKL>dtarget×1.5: β←β×2 (penalize more)
- If DKL<dtarget/1.5: β←β/2 (relax penalty) This automatically adjusts the constraint based on observed KL divergence.
1.6 PPO-Clip vs PPO-Penalty
| Aspect | PPO-Clip | PPO-Penalty |
|---|---|---|
| Mechanism | Explicit ratio clipping | Adaptive KL penalty |
| Hyperparameters | ε (one parameter) | β₀, d_target (two params) |
| Robustness | More robust to hyperparams | Sensitive to target KL |
| Computational cost | Same | Slightly more (compute KL) |
| Empirical performance | Better on most benchmarks | Comparable |
| Debugging | Easier (clipping behavior visible) | Harder (β adaptation dynamics) |
PPO-Clip is the default and most widely used variant.
1.7 Edge Cases & Gotchas
- Clipping behavior: If all ratios are within [1-ε, 1+ε], the clipping has no effect. This means either: (a) the policy is already optimal, or (b) the learning rate is too low. Check the fraction of clipped samples (target: 10-20%).
- Value function clipping: PPO often uses a clipped value loss to match the policy clipping:
This prevents the value function from changing too fast.
- Multiple epochs with same data: The same trajectory is reused for K epochs. This is off-policy learning (the behavior policy is π_old, the target is π). PPO's clipping protects against the distribution mismatch.
- Early termination (early stopping): If the KL divergence exceeds a threshold (e.g., 0.01 per update), early-stop the inner loop. This is a safety check.
1.8 Why This Matters
PPO is the default deep RL algorithm for a wide range of applications:
| Domain | Application |
|---|---|
| Game playing | Dota 2 (OpenAI Five used PPO) |
| Robotics | Dexterous manipulation, locomotion |
| LLM alignment | RLHF uses PPO to align language models with human preferences |
| Autonomous driving | Policy optimization for driving behavior |
| Finance | Trading strategy optimization |
The simplicity and reliability of PPO make it the first algorithm to try for most new RL problems. Understanding PPO is essential for any RL practitioner.
2. 📐 Key Formulas / Concepts
| Concept | Formula | Description |
|---|---|---|
| Probability ratio | $r_t(\theta) = \frac{\pi_\theta(a_t\ | s_t)}{\pi_{\theta_{\text{old}}}(a_t\ |
| Clipped objective | LCLIP=E[min(rA,clip(r,1−ε,1+ε)A)] | PPO's stable surrogate |
| KL-penalized objective | $L^{KL} = \mathbb{E}[rA - \beta D_{KL}(\pi_{\text{old}}\ | \pi)]$ |
| Clipped value loss | LVCLIP=max((Vφ−G)2,(Vφclip−G)2) | Prevents value function overshoot |
| Adaptive KL | If DKL>dt×1.5 : β×2 | Automatic penalty tuning |
3. ⚠️ Common Pitfalls
Pitfall 1: Very Low Clipping Fraction
Mistake: Observing that < 1% of samples are clipped and concluding the model is converged.
Why: Low clipping fraction means all ratios are within [0.8, 1.2] (for ε=0.2). This could mean convergence, or it could mean the learning rate is too low or the policy isn't changing.
Correct approach: Monitor the fraction of clipped samples. Target 10-20%. If clipping is too low, increase the learning rate. If too high (> 50%), decrease the learning rate or increase the number of workers.
Pitfall 2: Too Many Epochs Without Early Stopping
Mistake: Setting K=80 epochs over the same trajectory data.
Why: After many epochs, the policy can diverge far from π_old even with clipping. The data was collected from π_old, and π becomes increasingly different, violating the on-policy assumption.
Correct approach: Use K=3-15 epochs. Monitor KL divergence per update. If KL exceeds ~0.01 per minibatch, stop early. If KL is very low, increase K or learning rate.
Pitfall 3: Not Normalizing States or Advantages
Mistake: Feeding raw state values (e.g., pixel values [0, 255] or joint angles [-π, π]) into the policy network without normalization.
Why: Neural networks learn much better with normalized inputs. Advantage normalization is also critical — raw advantages can have very high variance.
Correct approach: Normalize states to have mean 0, standard deviation 1 (running normalization). Normalize advantages to mean 0, std 1 per batch.
Pitfall 4: Continuous Action Noise Schedule
Mistake: Using a fixed action noise std for continuous control.
Why: Initially, high exploration noise is needed. Later, the noise should decrease to exploit the learned policy. A fixed noise either prevents convergence (too high) or prevents exploration (too low).
Correct approach: Learn the log_std parameter as part of the policy network (state-dependent or fixed but learned). This allows the agent to control its own exploration.
4. 📝 Practice Questions
Q1: For a state-action pair with old probability 0.1, new probability 0.5, advantage +3.0, ε=0.2, compute the clipped objective contribution.r=0.5/0.1=5.0clip(r, 0.8, 1.2) = 1.2Unclipped: r·A = 5.0 × 3.0 = 15.0 clipped: clip(r)·A = 1.2 × 3.0 = 3.6min(15.0, 3.6) = 3.6The clipped contribution is 3.6. Without clipping, the objective contribution would be 15.0, creating a huge gradient that would push the probability even higher. The clipping caps the contribution at 3.6, providing no gradient to increase the ratio beyond 1.2. Q2: Explain why PPO reuses the same trajectory for K epochs (multiple gradient updates) while A2C uses it once.A2C: On-policy. Each transition is used for exactly one gradient update, then discarded. This is strictly on-policy but sample-inefficient.PPO: Uses importance sampling to be approximately on-policy. The probability ratio rt(θ)=πθ(at∣st)/πθold(at∣st) corrects for the fact that the data was collected from an older policy.PPO can safely reuse data for multiple epochs because:
- The ratio rt(θ) downweights transitions where the new policy differs from the old policy
- The clipping mechanism prevents the objective from being dominated by a few transitions with extreme ratios
- The KL divergence is bounded (implicitly via clipping, explicitly via early stopping)
This reuse improves sample efficiency by 3-15× compared to A2C (depending on K). Q3: In PPO-Clip, if ε=0.5, what's the effective range of the probability ratio before clipping kicks in?[1-ε, 1+ε] = [0.5, 1.5]A ratio of 0.5 means the new policy is half as likely to take this action as the old policy. A ratio of 1.5 means the new policy is 1.5× more likely.Larger ε (0.5) allows more policy change per update. This is suitable for:
- Environments with very stable dynamics (simulated robotics)
- When you trust your advantage estimates
- Tasks requiring fast learning
Smaller ε (0.1) allows less change. Suitable for:
- Noisy environments (Atari)
- When advantage estimates are unreliable
- More conservative learning Q4: A PPO agent trains for 10M steps and the clipped fraction is 0% (none of the ratios exceed [1-ε, 1+ε]). What could be wrong?
If no ratios exceed the clipping bounds:
- Learning rate too low: The policy isn't changing, so all ratios ≈ 1.0. Increase learning rate.
- Network capacity too low: The network can't learn the optimal policy. Increase network size.
- Vanishing gradients: The policy is saturated (e.g., actions are very confident). Check for tanh saturation or softmax degeneracy.
- Convergence: The policy might actually be optimal. But this is unlikely after 10M steps if the clipping is exactly 0%.
- Entropy coefficient too high: If entropy bonus dominates, the policy stays near-uniform. Check entropy over training.
In practice, the clipped fraction should be 10-30% for healthy PPO training. Q5: Compare PPO's handling of continuous vs discrete action spaces.Discrete actions (e.g., Atari):
- Policy outputs logits for each action, converted to probabilities via softmax
- Ratio rt(θ)=πθ(at∣st)/πθold(at∣st) is straightforward (ratio of two probabilities)
- Clipping applies directly to probability ratios
Continuous actions (e.g., robotic control):
- Policy outputs mean μθ(st) and log_std σθ for each action dimension
- Action probability: πθ(at∣st)=N(at∣μθ(st),σθ2)
- Ratio rt(θ)=N(at∣μθold,σθold2)N(at∣μθ,σθ2) — ratio of probability densities
- Clipping same as discrete; ratio can vary more smoothly
For continuous actions, PPO often benefits from:
- Tanh squashing: Apply tanh to action samples to bound them within [-1, 1]
- Log-probability correction: Adjust log-probability for the tanh transformation
- State-dependent standard deviation: Instead of fixed log_std, predict it from state Q6: Explain the relationship between PPO's clipping and TRPO's trust region constraint.
TRPO (Trust Region Policy Optimization) constrains policy updates using KL divergence:maxθE[πθold(a∣s)πθ(a∣s)A(s,a)] s.t. E[DKL(πθold∥πθ)]≤δThis requires computing the KL constraint and solving it with conjugate gradient — complex and computationally expensive.PPO-Clip achieves a similar effect without explicit KL computation:
- TRPO limits KL divergence explicitly — guarantees the new policy stays within a trust region
- PPO limits probability ratio — implicitly limits KL, since KL is bounded by a function of the ratio
For small changes, DKL(πθold∥πθ)≈E[(rt−1)2]/2. So clipping r to [1-ε, 1+ε] approximately limits KL.PPO-Penalty even more explicitly uses KL (adding a penalty term), making it even closer to TRPO but with first-order optimization.Key difference: TRPO's constraint is "hard" (must be satisfied). PPO's clipping is "soft" (can be violated, but clipped gradient discourages it). PPO is simpler and faster; TRPO has stronger theoretical guarantees. Q7: Design a PPO agent for a continuous control task where actions are torques in [-1, 1] and state is joint angles and velocities. Describe the network architecture.Network architecture:pseudoState (e.g., 24 dims: joint angles + velocities) │ ├── Linear(256) ──► LayerNorm ──► tanh │ ├── Linear(256) ──► LayerNorm ──► tanh │ ├── Policy Head ──► Linear(128) ──► tanh │ │ │ ├── μ head: Linear(action_dim) → tanh (to bound [-1, 1]) │ │ │ └── log_std: Parameter(action_dim) or Linear(action_dim) │ └── Value Head ──► Linear(128) ──► tanh ──► Linear(1)Key design choices:
- LayerNorm: Helps stabilize training with varying input distributions
- Tanh activation: Bounds activations, prevents extreme outputs
- Separate policy/value heads: Sharing low-level features, separate high-level processing
- Tanh on μ: Ensures action means are within [-1, 1]
- Learned log_std: Can be state-independent (single parameter) or state-dependent (network output)
Training details:
- γ = 0.99 (typically OK for control tasks with reasonable episode lengths)
- GAE λ = 0.95
- ε = 0.2
- K = 10 epochs per iteration
- Entropy coefficient = 0.01 (supplementary bonus, not critical for continuous control) Q8: Why does PPO benefit from early stopping in the inner loop?
PPO's inner loop performs K epochs over the same trajectory data. Each epoch applies gradients that change θ further from θ_old.After many epochs, even with clipping, the KL divergence between π_θ and π_θ_old can grow large. When KL is large:
- The importance sampling correction (ratio r_t) becomes unreliable
- The state distribution mismatch between old and new policy introduces bias
- The clipping is a blunt instrument — it prevents extreme ratios but doesn't prevent gradual drift
Early stopping monitors the approximate KL (e.g., average KL per minibatch). If KL > threshold (e.g., 0.01 * 1.5), stop the inner loop. This provides a safety net.Without early stopping, you'd need very conservative parameters (small ε, small K). Early stopping allows more aggressive learning: if KL stays low, keep optimizing; if KL spikes, stop and collect fresh data. Q9: In RLHF (Reinforcement Learning from Human Feedback), PPO is used to fine-tune language models. How does PPO need to be modified for this setting?RLHF fine-tunes a language model to maximize a reward score from a human preference model. Key modifications:
KL penalty with original model: The PPO loss includes a KL penalty between the current model and the original (unfine-tuned) model: L=E[rt⋅At]−β⋅DKL(πorig∥πθ) This prevents the model from diverging too far from the original pretrained model. Per-token PPO: The policy generates text one token at a time. The action is the next token, the state is the sequence so far. PPO operates per-token, but the reward is only available at the end of the sequence. Credit assignment: The advantage for each token is computed using GAE over the sequence. Only the final reward signal (from the reward model) is available — it's assigned to each token proportionally to recency. No value function sharing: The value function (critic) is a separate head added to the language model. It's trained to predict the expected reward from any point in the sequence. Batched generations: The LM generates K completion samples per prompt. All are scored by the reward model. The PPO update uses these scored generations. Reference model: A frozen copy of the original LM serves as both (a) the KL constraint target and (b) the behavior policy for importance sampling.This approach is used for models like ChatGPT, Claude, and Llama-2-Chat. Q10: For a robotic reaching task, PPO with ε=0.2 fails to learn (policy stays near-random). Propose 3 potential fixes.
Increase ε to 0.3-0.5: If the policy is stuck at random, the allowed change per update (ε=0.2) might be too restrictive. A larger ε allows more aggressive improvement. Reduce K (epochs) and increase learning rate: If K is high (e.g., 80), the policy might be repeatedly optimizing the same data without changing. Reduce K to 3-5 and increase learning rate by 5-10×. Check reward scaling: If rewards are very small (e.g., -0.001 per step), advantages are tiny, and PPO's gradient is negligible. Scale rewards so that the typical advantage magnitude is ~1.0. Or normalize advantages within the batch. Fix exploration: If the policy's action noise (log_std) collapses to near-zero, the policy doesn't explore and stays at the initial poor policy. Initialize log_std to 0 (std=1) and don't let it drop below -2 (std=0.14) initially. Increase GAE λ: If λ is too low (e.g., 0.8), the advantage estimate is myopic. Increase λ to 0.97 to capture longer-term consequences of actions. Add a dense reward shaping: If the sparse reaching reward (0 or 1 at the end) is too hard to optimize, add a shaping reward based on distance to the target:rshaped=rsparse+α⋅(distt−1−distt)This gives the agent immediate feedback for moving toward the target.
5. 🔗 Cross-References
- Previous: Actor-Critic Methods (Week 9) — A2C foundation
- Next: Exploration Methods (Week 11) — Beyond PPO's entropy bonus
- Related: Policy Gradients (Week 8) — Baseline policy gradient concepts
- External: Schulman et al., "Proximal Policy Optimization Algorithms" (arXiv 2017)
- External: Schulman et al., "Trust Region Policy Optimization" (ICML 2015) Join Discord PreviousActor-Critic MethodsNextExploration Methods