Reinforcement Learning · lesson 02/5
Policy Gradients (REINFORCE)
Policy gradients skip the value table and optimize the policy directly. If a sampled action leads to a high return, raise its log-probability; if it leads to a low return, lower it. REINFORCE is that sentence written as a gradient, and it is the ancestor of PPO, GRPO, and every RLHF recipe in use today.
The idea
The objective is the expected return of the policy's own trajectories:
The difficulty is that the distribution being averaged over also depends on . The log-derivative trick resolves it:
which turns the gradient of an expectation into an expectation of a gradient:
Weights no longer appear inside the distribution, so you can estimate the gradient from sampled episodes.
Three refinements make it usable:
- Baselines. Subtracting any function leaves the expectation unchanged but shrinks variance: use with .
- Reward-to-go. Rewards earned before step cannot depend on , so replace the full return with .
- On-policy. The expectation is over samples from the current , so one batch licenses exactly one update; the moment moves, the data is stale.
Worked example
A two-action softmax policy with logits gives .
The gradient of with respect to the logits is .
Suppose the sampled action was with return-to-go and learning rate . Ascending the objective gives
Re-normalizing, rises from 0.731 to about 0.762. Had the same action returned , the identical formula moves the logits the other way and drops to about 0.720. The action is not important; the sign and size of the return attached to it is the entire learning signal.
In code
import torch
logits = torch.tensor([[1.0, 0.0]], requires_grad=True)
log_probs = torch.log_softmax(logits, dim=-1)
action, G = 0, 3.0
loss = -(log_probs[0, action] * G) # minimize the negative objective = ascend
loss.backward()
print(-0.1 * logits.grad) # [[ 0.0807, -0.0807]] -> the ascent stepA baseline would replace G with G - value.detach(), and reward-to-go would replace the scalar with a per-step tensor.
Check yourself
- REINFORCE is unbiased. Why subtract a baseline if the expected gradient does not change?
- Why can you not reuse one REINFORCE batch for a second gradient step after has changed?
- What is the difference between measured from the start of the episode and the reward-to-go, and which one does the update use?
Key takeaways
- The log-derivative trick turns "how well did this sample do" into a differentiable weight on log-probabilities.
- Baselines and reward-to-go reduce variance without introducing bias.
- Policy gradients are on-policy: the samples must come from the policy being updated.