Lab 6. Policy Gradient and Actor-Critic Methods on CartPole

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

Overview

This lab puts chapter 13 to work on the cart-pole. You will write a vectorized simulator and check it against Gymnasium, compare the gradient estimators of REINFORCE, build an online actor–critic, measure the bias and variance of generalized advantage estimates, and compare the vanilla and natural policy gradients.

Part 1 — REINFORCE and its estimators

  1. Write the cart-pole dynamics for \(n\) copies at once, with the constants and the Euler integration of Gymnasium’s source, and automatic resets. Check that it reproduces env.unwrapped.state exactly over random episodes.
  2. Implement per-episode REINFORCE with four weightings of the score \(\nabla\ln\pi(A_t\mid S_t)\): the whole discounted return \(G_0\) at every step; \(\gamma^tG_t\), the return from step \(t\) discounted back to the start; \(G_t\), without the factor \(\gamma^t\), as most implementations do; and \(G_t-\hat v(S_t)\), with \(\hat v\) learned by gradient Monte Carlo on a Fourier basis of order 2 (81 features, per-feature step sizes \(0.01/\|\mathbf c\|\), averaged over the steps of each episode).
  3. For step sizes \(3\times10^{-4}\), \(10^{-3}\), and \(3\times10^{-3}\), run 10 seeds of 1,000 episodes. Report the average return in windows of 200 episodes, and count the seeds whose last 100 episodes average more than 475.

Part 2 — Online actor–critic

  1. Implement the one-step actor–critic of chapter 13 with a TD(0) critic on the same Fourier features, \(\alpha^{\boldsymbol\theta}=0.1\) and \(\alpha^{\mathbf w}=0.03/\|\mathbf c\|\), updating at every step.
  2. At the 500-step limit the episode is cut off, not over: bootstrap from the true next state. Then run the agent again treating the time limit as termination.
  3. Add accumulating eligibility traces with \(\lambda=0.9\) to the actor and the critic, with \(\alpha^{\boldsymbol\theta}=0.03\) and \(\alpha^{\mathbf w}=0.003/\|\mathbf c\|\).
  4. Compare the three agents over 300 episodes, 10 seeds, with REINFORCE with baseline.

Part 3 — The bias and variance of gradient estimators

  1. Fix the policy \(\boldsymbol\theta=(0,0,1.5,1.5,0)\), which pushes toward the side the pole is falling to and lasts about 110 steps on average.
  2. Fit three critics: least squares on quadratic features of the scaled state (\(1\), \(u_i\), \(u_iu_j\); 15 features) to the returns of 2,000 episodes of this policy (“fitted”); the same for the worse policy \((0,0,0.75,0.75,0)\) (“stale”); and \(\hat v=0\) (“zero”).
  3. Over 10,000 episodes, compute each episode’s gradient estimate with the whole return, \(\gamma^tG_t\), \(\gamma^t(G_t-\hat v(S_t))\), \(G_t\), and GAE(\(\lambda\)) for \(\lambda=0\), 0.5, 0.9, 0.97, and 1 with each critic.
  4. For the average of 10 episodes, compute the squared bias and the variance, relative to the squared norm of the target: the mean of the \(\gamma^tG_t\) estimates for the first group, and of the \(G_t\) estimates for the others, which estimate a different direction (exercise 13.7).

Part 4 — The natural policy gradient

  1. Write a batch actor–critic: each iteration runs 10 episodes, computes GAE(0.95) with a quadratic critic fitted by least squares to the previous batch’s returns, and averages the estimates into \(\hat{\mathbf g}\).
  2. The vanilla update is \(\boldsymbol\theta\leftarrow\boldsymbol\theta+\alpha\hat{\mathbf g}\). For the natural update, estimate the Fisher matrix \(\hat{\mathbf F}\) as the average over all steps of the batch of \(\nabla\ln\pi\,\nabla\ln\pi^\top\), add \(10^{-3}\) of its diagonal as damping, and take the step \(\Delta=\sqrt{2\delta/\hat{\mathbf g}^\top\hat{\mathbf F}^{-1}\hat{\mathbf g}}\;\hat{\mathbf F}^{-1}\hat{\mathbf g}\), whose quadratic estimate of the KL divergence, \(\tfrac12\Delta^\top\hat{\mathbf F}\Delta\), equals \(\delta\). The matrix is only \(5\times5\), so solve with it directly.
  3. Run \(\alpha\in\{0.003,0.01,0.03\}\) and \(\delta\in\{0.003,0.01,0.03\}\) for 100 iterations, 10 seeds, with the scaled features and with the raw state, \(\mathbf x(s)=(s,1)\). Give all configurations the same initial states and random numbers, seed by seed, and compare the natural gradient runs with raw and scaled features episode by episode.

Expected results

output
=== Part 1: a vectorized CartPole, and REINFORCE with a linear softmax policy ===
  largest state difference from Gymnasium over 20 random episodes: 0.0e+00
  average episode length (the return, at most 500), 10 seeds; solved: last 100 episodes average over 475
                               episodes 1-200 201-400 401-600 601-800 801-1000  solved
       whole, alpha = 3e-04          24.2    37.1    81.0   105.6   117.8     0 of 10
       whole, alpha = 1e-03          37.2   101.1   100.3   102.0   104.1     0 of 10
       whole, alpha = 3e-03          29.9    41.2    42.1    49.8    38.7     0 of 10
  disc-to-go, alpha = 3e-04          25.1    43.5   138.4   238.6   282.5     0 of 10
  disc-to-go, alpha = 1e-03          66.5   194.9   245.2   274.1   269.4     0 of 10
  disc-to-go, alpha = 3e-03          89.6   152.3   147.4   173.2   237.1     0 of 10
       to-go, alpha = 3e-04          25.4    77.7   212.8   266.8   286.6     1 of 10
       to-go, alpha = 1e-03          83.3   148.5   186.9   189.1   198.5     0 of 10
       to-go, alpha = 3e-03          63.9   122.2   119.3   179.6   178.1     0 of 10
    baseline, alpha = 3e-04          26.3   110.8   385.6   465.1   478.5     9 of 10
    baseline, alpha = 1e-03         143.3   436.6   452.3   467.5   468.5     6 of 10
    baseline, alpha = 3e-03         235.3   322.5   418.0   400.1   382.5     3 of 10

=== Part 2: online actor-critic (linear softmax actor, Fourier critic of order 2) ===
  average episode length, 10 seeds             episodes 1-50  51-100 101-150 151-200 201-250 251-300  solved
  one-step actor-critic                         424.7   500.0   500.0   500.0   500.0   500.0    10 of 10
    same, time limit treated as termination     364.6   426.5   463.4   432.4   474.4   465.4     4 of 10
  actor-critic, lambda = 0.9                    382.5   500.0   500.0   500.0   500.0   500.0    10 of 10
  for comparison, REINFORCE with baseline        24.1    45.0   174.4   329.7   404.7   444.9

=== Part 3: gradient estimators at a fixed policy (average episode length about 110), batches of 10 episodes ===
  relative squared error of a 10-episode estimate = squared bias + variance, both divided by |gradient|^2
  (a) estimates of the gradient of the discounted value of the start state:
    whole return G_0                         bias^2  0.004   variance 16.778
    gamma^t G_t                              bias^2  0.000   variance  1.972
    gamma^t (G_t - v(S_t)), fitted critic    bias^2  0.001   variance  0.859
  (b) estimates of the direction without gamma^t: G_t, and GAE(lambda) with three critics (bias^2 + variance):
    G_t, no critic: 0.000 + 1.527
                     lambda = 0       lambda = 0.5     lambda = 0.9     lambda = 0.97    lambda = 1    
    fitted critic   0.002 + 0.136  0.002 + 0.153  0.002 + 0.286  0.001 + 0.441  0.001 + 0.652
    stale critic    0.160 + 0.045  0.155 + 0.046  0.153 + 0.060  0.093 + 0.134  0.000 + 0.535
    zero critic     0.999 + 0.001  0.995 + 0.003  0.817 + 0.051  0.424 + 0.265  0.000 + 1.527
  (from 10,000 episodes, each squared bias is uncertain by about a thousandth of its variance)

=== Part 4: vanilla versus natural policy gradient, 10 episodes per iteration, GAE(0.95) ===
  average episode length, 10 seeds                    iterations 1-20   21-40   41-60   61-80  81-100  solved
  vanilla, alpha = 0.003, scaled features             25.1    45.1   172.4   348.5   402.7     1 of 10
  vanilla, alpha = 0.01, scaled features              53.7   223.8   277.4   311.8   297.0     2 of 10
  vanilla, alpha = 0.03, scaled features              65.7   136.4   134.4   146.9   139.8     0 of 10
  natural, delta = 0.003, scaled features             99.6   323.8   373.7   388.2   401.1     5 of 10
  natural, delta = 0.01, scaled features             178.9   338.6   380.2   395.1   392.2     3 of 10
  natural, delta = 0.03, scaled features             176.3   331.7   359.2   340.9   356.6     1 of 10
  vanilla, alpha = 0.003, raw features                27.9    42.9    57.5    93.8   168.9     0 of 10
  vanilla, alpha = 0.01, raw features                 39.5    72.2   123.3   128.4   166.9     0 of 10
  vanilla, alpha = 0.03, raw features                 48.9    64.3    50.5    54.3    80.4     0 of 10
  natural, delta = 0.003, raw features                99.6   323.8   373.7   388.2   401.1     5 of 10
  natural, delta = 0.01, raw features                178.9   338.6   380.2   392.7   390.1     2 of 10
  natural, delta = 0.03, raw features                176.3   332.2   364.7   352.8   335.0     0 of 10
  natural, delta = 0.003: raw and scaled features give identical runs in 10 of 10 seeds
  natural, delta = 0.01: raw and scaled features give identical runs in 6 of 10 seeds; the others first differ at iterations 70, 89, 90, 95
  natural, delta = 0.03: raw and scaled features give identical runs in 0 of 10 seeds; the others first differ at iterations 36, 36, 37, 37, 37, 37, 43, 47, 58, 58

Things to notice:

Going further

  1. Time as a feature. Add \(t/500\) to the critic’s features in part 2 and treat the time limit as termination. Does the agent recover the performance of the bootstrapping version? Which is the better fix when the time limit is part of the task, and which when it is only a convenience of the simulation?
  2. A constant baseline. In part 1, subtract a constant \(b\) from \(G_t\) for several values of \(b\), including the average return. The expected gradient does not change; how does the performance change, and how does the best \(b\) compare with the optimal baseline of exercise 13.3?
  3. Entropy regularization. Add \(\tau\nabla\mathcal H(\pi(\cdot\mid S_t))\) to the actor’s update in part 4, as in exercise 13.8. Does it help the natural gradient past its plateau, or does it make the plateau lower?
  4. A neural network policy. Replace the linear policy of part 2 by a network with one hidden layer of 64 units in PyTorch, with a network critic, and update from batches of steps collected from 8 parallel copies of the environment. This is A2C (chapter 19). How much faster or slower is it than the linear agent, and how sensitive to its step sizes?
  5. Natural gradients without the matrix. For a network, \(\mathbf F\) is too large to form. Compute \(\mathbf F^{-1}\hat{\mathbf g}\) by conjugate gradient, using only products \(\mathbf F\mathbf v\) computed as averages of \(\nabla\ln\pi\,(\nabla\ln\pi^\top\mathbf v)\), and add a backtracking line search that accepts a step only if the empirical KL divergence is below δ and a surrogate estimate of the improvement is positive. Check that it matches part 4 on the linear policy: this is TRPO.