Roadmap / Post-Training & Alignment

✓

PPO Clipped Objective

mediumpost-trainingreinforcement-learning

The problem

PPO (Proximal Policy Optimization) improves a policy using samples collected by an older copy of it. Taking several gradient steps on the same samples is efficient but dangerous: the policy could move so far that the samples no longer describe it. PPO limits how far each token's probability can move, by clipping the update.

For every sampled token, with ρ=elog⁡πnew−log⁡πold\rho = e^{\log \pi_{\text{new}} - \log \pi_{\text{old}}} (how much more, or less, likely the new policy makes it than the old one) and advantage AA (how much better than expected the token was, positive or negative):

J=1N∑min⁡(ρA, ρ~A)J = \frac{1}{N}\sum \min\big(\rho A,\ \tilde\rho A\big)ρ~=clip(ρ, 1−ϵ, 1+ϵ)\tilde\rho = \mathrm{clip}(\rho,\ 1 - \epsilon,\ 1 + \epsilon)

where ϵ\epsilon (epsilon) is 0.2, so ρ~\tilde\rho is ρ\rho forced into [0.8,1.2][0.8, 1.2]. JJ is maximized: a token with positive advantage wants its probability to go up, one with negative advantage wants it down, but the clip stops the update once ρ\rho has gone past the limit.

Example. ϵ=0.2\epsilon = 0.2. Four tokens, all with log⁡πold=0\log \pi_{\text{old}} = 0:

  • ρ=1.5\rho = 1.5, A=+1A = +1: ρA=1.5\rho A = 1.5, ρ~A=1.2\tilde\rho A = 1.2, minimum 1.21.2: gradient 0 (clipped).
  • ρ=0.5\rho = 0.5, A=+1A = +1: ρA=0.5\rho A = 0.5, ρ~A=0.8\tilde\rho A = 0.8, minimum 0.50.5: gradient ρA=0.5\rho A = 0.5.
  • ρ=0.5\rho = 0.5, A=−1A = -1: ρA=−0.5\rho A = -0.5, ρ~A=−0.8\tilde\rho A = -0.8, minimum −0.8-0.8: gradient 0 (clipped).
  • ρ=1.5\rho = 1.5, A=−1A = -1: ρA=−1.5\rho A = -1.5, ρ~A=−1.2\tilde\rho A = -1.2, minimum −1.5-1.5: gradient ρA=−1.5\rho A = -1.5.

Objective: (1.2+0.5−0.8−1.5)/4=−0.15(1.2 + 0.5 - 0.8 - 1.5)/4 = -0.15. Gradient: (0,0.5,0,−1.5)/4=(0,0.125,0,−0.375)(0, 0.5, 0, -1.5) / 4 = (0, 0.125, 0, -0.375). Clip fraction: 2 of 4 tokens are clipped, 0.50.5.

Where the gradient is zero

Where the unclipped term ρA\rho A is the minimum, its derivative with respect to log⁡πnew\log \pi_{\text{new}} is ρA\rho A (since dρ/dlog⁡π=ρd\rho / d\log\pi = \rho). Where the clipped term is the strict minimum, it does not change when the policy moves: derivative 0. That happens when:

  • A>0A > 0 and ρ>1+ϵ\rho > 1 + \epsilon: a good token already made more likely than allowed;
  • A<0A < 0 and ρ<1−ϵ\rho < 1 - \epsilon: a bad token already made less likely than allowed.

The other two cases keep their gradient: a mistake in the wrong direction (the second and fourth cases) is always corrected.

What to implement

For arrays of shape (N,)(N,):

  • ppo_objective(logp_new, logp_old, adv, eps=0.2): JJ.
  • ppo_grad(logp_new, logp_old, adv, eps=0.2): ∂J/∂log⁡πnew\partial J / \partial \log \pi_{\text{new}}, shape (N,)(N,), including the 1/N1/N of the mean.
  • clip_fraction(logp_new, logp_old, adv, eps=0.2): the fraction of tokens whose term is clipped, that is, where the gradient is 0. Training logs track it: if it is large, the updates are being cut a lot.

Requirements

  • Work from log-probabilities: compute ρ\rho with np.exp of the difference.
  • No loops.
solution.py
Python idle

Press Run (⌘/Ctrl + Enter) to test your code.