Module 4. Policy gradients: from REINFORCE to PPO
Choose your answers and select “Check”. Numbers accept a decimal point, comma, or simple fraction. Answers and drafts are saved in this browser and shared between RU/EN.
Use the author’s worked answers to review open questions and code tasks yourself. Code does not run on this site.
Checked: 0 / 8 · Correct: 0
Question P01 · The price of the log-derivative identity
single answer
The identity removes the need to differentiate . What is received in exchange?
Question P02 · Reward-to-go
coding task
Specification: — the return from the current step to the end of the episode. Compute it in a backward pass: , .
Input format: line 1 — space-separated rewards; line 2 — . Output format: one line — space-separated (6 decimals).
Starter code:
import numpy as np
def reward_to_go(rewards, gamma=1.0):
# YOUR CODE HERE
raise NotImplementedError
if __name__ == "__main__":
rewards = [float(x) for x in input().split()]
gamma = float(input())
print(" ".join(f"{x:.6f}" for x in reward_to_go(rewards, gamma)))
Open tests:
| stdin | stdout |
|---|---|
1 0 2 3 ⏎ 0.9 | 4.807000 4.230000 4.700000 3.000000 |
1 0 2 3 ⏎ 1.0 | 6.000000 5.000000 5.000000 3.000000 |
0 0 1 ⏎ 0.5 | 0.250000 0.500000 1.000000 |
Question P03 · What can be subtracted without a correction
single answer
A baseline is subtracted from . What condition makes the substitution safe for the expected gradient?
Question P04 · The scale of group centering
numeric answer · tolerance ±0.005
Group rewards are centered on the group mean: , group size , responses conditionally independent.
By what factor does the expectation of the resulting gradient estimate differ from ?
Question P05 · RLOO and the group mean: collinear but rescaled
coding task
Specification: with the full group mean; . Requires .
Input format: line 1 — the group size ; line 2 — space-separated rewards.
Output format: line 1 — group-mean advantages (6 decimals); line 2 — RLOO advantages (6 decimals); line 3 — the ratio (6 decimals), or undefined if the denominator is zero.
Starter code:
import numpy as np
def group_and_loo(rewards):
"""Return (mean_advantages, loo_advantages)."""
# YOUR CODE HERE
raise NotImplementedError
if __name__ == "__main__":
g = int(input())
rewards = [float(x) for x in input().split()]
mean_adv, loo_adv = group_and_loo(rewards)
print(" ".join(f"{x:.6f}" for x in mean_adv))
print(" ".join(f"{x:.6f}" for x in loo_adv))
print(f"{loo_adv[0] / mean_adv[0]:.6f}" if abs(mean_adv[0]) > 1e-12 else "undefined")
Open tests:
| stdin | stdout |
|---|---|
4 ⏎ 1 0 1 0 | 0.500000 -0.500000 0.500000 -0.500000 ⏎ 0.666667 -0.666667 0.666667 -0.666667 ⏎ 1.333333 |
3 ⏎ 2 2 2 | 0.000000 0.000000 0.000000 ⏎ 0.000000 0.000000 0.000000 ⏎ undefined |
Question P06 · Generalized advantage estimation
coding task
Specification: the episode terminates on its last step. with ; , . Critic target: .
Input format: line 1 — rewards; line 2 — value estimates ; line 3 — and . Output format: line 1 — space-separated (6 decimals); line 2 — critic targets (6 decimals).
Starter code:
import numpy as np
def gae(rewards, values, gamma, lam):
"""Return (advantages, value_targets)."""
# YOUR CODE HERE
raise NotImplementedError
if __name__ == "__main__":
rewards = [float(x) for x in input().split()]
values = [float(x) for x in input().split()]
gamma, lam = (float(x) for x in input().split())
adv, targets = gae(rewards, values, gamma, lam)
print(" ".join(f"{x:.6f}" for x in adv))
print(" ".join(f"{x:.6f}" for x in targets))
Open tests:
| stdin | stdout |
|---|---|
0 0 1 ⏎ 0.4 0.5 0.6 ⏎ 1.0 0.5 | 0.250000 0.300000 0.400000 ⏎ 0.650000 0.800000 1.000000 |
0 0 1 ⏎ 0.4 0.5 0.6 ⏎ 1.0 0.0 | 0.100000 0.100000 0.400000 ⏎ 0.500000 0.600000 1.000000 |
Question P07 · Bootstrapping at the episode boundary
single answer
A batch was collected with a length cap; some episodes were cut off by it and some ended at a real terminal. What happens to the advantage estimate if both groups are treated identically, as terminal?
Question P08 · When the clipping plateau is active
multiple answers
For which combinations of advantage sign and ratio movement does the clipped branch actually bound the objective? Select all that apply.
Question P09 · PPO diagnostics: outside the interval versus actively clipped
coding task
Specification: each sample supplies a ratio and an advantage . Compute three quantities at a given :
- the fraction with ;
- the fraction where the pessimistic branch is strictly below the unclipped one, i.e. ;
- the non-negative sample estimate .
Input format: line 1 — the number of samples and ; then lines of ratio advantage.
Output format: three lines — quantities 1, 2 and 3 (6 decimals).
Starter code:
import numpy as np
def ppo_diagnostics(ratio, advantage, clip_epsilon):
"""Return (outside_fraction, active_clip_fraction, approx_kl)."""
# YOUR CODE HERE
raise NotImplementedError
if __name__ == "__main__":
n, eps = input().split()
rows = [tuple(float(x) for x in input().split()) for _ in range(int(n))]
r = np.array([row[0] for row in rows])
a = np.array([row[1] for row in rows])
for value in ppo_diagnostics(r, a, float(eps)):
print(f"{value:.6f}")
Open tests:
| stdin | stdout |
|---|---|
5 0.2 ⏎ 0.75 1.0 ⏎ 1.00 1.0 ⏎ 1.30 1.0 ⏎ 1.10 -1.0 ⏎ 0.85 -1.0 | 0.400000 ⏎ 0.200000 ⏎ 0.018505 |
Question P10 · The non-negative sample KL estimate
numeric answer · tolerance ±0.001
Probability ratios on three samples: .
What is ?
Question P11 · RLOO and GRPO: the shared idea and the differences
single answer
RLOO and GRPO both generate several responses per prompt and build a relative signal. What separates them in canonical form?
Question P12 · What one weight across all tokens does not solve
single answer
A response-level advantage is broadcast across every token and multiplied by the mask. What does this construction do correctly, and what does it not?