Lab 10. Proximal Policy Optimization from Scratch

Work in progress: this part of the notes is still being revised.

Overview

This lab puts chapter 20 to work. You will implement PPO from scratch with Gymnasium’s vectorized environments, train it to land a spacecraft, remove its ingredients one at a time to see which matter, and then train a simulated cheetah to run with a Gaussian policy.

Part 1 — PPO from scratch

  1. Create 8 environments with gym.make_vec(..., vectorization_mode="sync", vector_kwargs={"autoreset_mode": gym.vector.AutoresetMode.SAME_STEP}). In this mode a finished sub-environment is reset within the same call to step, and its true final observation is returned in info["final_obs"]; use it to bootstrap at truncations (chapter 19, appendix A).
  2. Build separate actor and critic networks, each with two tanh layers of 64 units, orthogonal initialization with gain \(\sqrt2\), and output layers with gains 0.01 (actor) and 1 (critic).
  3. Each iteration, collect 256 steps from each environment, compute GAE advantages and value targets, and run 10 epochs of minibatch updates (32 minibatches of 64) on the loss of chapter 20: the clipped objective with \(\epsilon=0.2\), the value loss with coefficient 0.5, and an entropy bonus of 0.01. Normalize the advantages in each minibatch, clip the gradient’s norm to 0.5, and anneal Adam’s step size linearly from \(3\times10^{-4}\) to 0. Use \(\gamma=0.999\) and \(\lambda=0.98\).
  4. After the last epoch of each iteration, measure how far the policy moved: the mean KL divergence from the policy that collected the batch, estimated by \(\mathbb E[(r-1)-\ln r]\) with \(r\) the probability ratio, and the fraction of samples whose ratio is outside \([1-\epsilon,1+\epsilon]\).
  5. Train for 500,000 steps with 2 seeds, and report the average return of the last 20 episodes as training proceeds.

Part 2 — Which ingredients matter

Rerun part 1 with one change at a time: 4 epochs and 1 epoch instead of 10; no clipping (a clipping range so large it never binds); no advantage normalization; PPO’s clipped value loss (with the same \(\epsilon\), in the units of the rewards); and \(\gamma=0.99\), \(\lambda=0.95\), the usual defaults.

Part 3 — Continuous control

  1. For continuous actions, let the actor output the mean of a Gaussian and keep its log standard deviation as a free parameter, initialized to 0; sum the log-probabilities and entropies over the action dimensions, and clip the sampled actions to the bounds only when sending them to the environment.
  2. Add running normalization of the observations (clipped to \([-10,10]\)) and scale the rewards by a running estimate of the standard deviation of the discounted return.
  3. Train on HalfCheetah-v5 for 1,000,000 steps with \(\gamma=0.99\), \(\lambda=0.95\) and no entropy bonus, with and without the normalizations, 2 seeds each.

Expected results

output
=== Parts 1 and 2: PPO on LunarLander-v3, 8 environments x 256 steps, 500,000 steps, 2 seeds ===
  average return of the last 20 episodes, mean of seeds; KL and fraction clipped after the last epoch,
  averaged over the second half of training; the final return of each seed (last 20% of training)
                                       100k   200k   300k   400k   500k       KL  clip   per seed
  PPO (10 epochs, clipping 0.2)          60    165    215    246    247    0.003  0.03     250   243
    4 epochs                             12     73    105    127    169    0.002  0.01     143   168
    1 epoch                            -107    -26    -23    -25     21    0.000  0.00      24     2
    no clipping                          46     84    174    234    238    0.046  0.00     254   200
    no advantage normalization          155    185    225    215    206    0.004  0.04     188   201
    value clipping                        8     96    102    106    112    0.005  0.05     106   120
    discount 0.99, lambda 0.95          -31     -5     20     54    117    0.004  0.04      36   165

=== Part 3: PPO on HalfCheetah-v5, 8 environments x 256 steps, 1,000,000 steps, 2 seeds ===
                                       200k   400k   600k   800k  1000k       KL  clip   per seed
  normalized observations and rewards    757   1359   1226   1621   1594    0.016  0.23    1446  1667
  no normalization                      296    830   1364   1891   2048    0.018  0.25    1443  2653

Things to notice:

Going further

  1. Breaking the unclipped agent. Rerun “no clipping” with 30 epochs, then with a step size of \(10^{-3}\), and compare with the clipped agent under the same settings. Then add early stopping of the epochs when the measured KL exceeds 0.015. Which of the three controls, clipping, fewer epochs, or early stopping, is most robust?
  2. A squashed Gaussian. Replace the clipping of actions in part 3 by a tanh-squashed Gaussian with the log-density correction of chapter 21, and compare.
  3. A shared network. Share the first layer of the actor and the critic, and tune the value coefficient. Does it help on LunarLander?
  4. Phasic policy gradient. Add PPG’s auxiliary phase to part 1: every 16 iterations, train the critic for 6 more epochs on all the stored data and distill it into an auxiliary value head of the actor with a KL term.
  5. Enough seeds. Run part 3 with 8 seeds per variant and compare the interquartile means with bootstrap confidence intervals. Does normalization matter on HalfCheetah? On Hopper?