🇺🇸 English | 🇧🇷 Português
PPO (Proximal Policy Optimization, Clip variant) implemented from scratch in PyTorch, with GAE and a component-ablation study.
A modular, on-policy PPO implementation in four decoupled units: ActorCritic (network),
RolloutBuffer (storage + GAE), PPO (clipped objective + update), and PPOTrainer
(collect-rollout → update loop). Includes an ablation study measuring the effect of
removing GAE, clipping, and the entropy bonus.
ActorCritic(ppo/networks.py) — shared trunk, policy + value heads.RolloutBuffer(ppo/rollout_buffer.py) — on-policy rollout; GAE/returns; minibatches.use_gaeflag.PPO(ppo/ppo.py) —act,update(PPO-clip objective).use_clipping,use_entropyflags.PPOTrainer(ppo/trainer.py) — on-policy loop + metrics (History).
The three ablation flags live in a single configurable PPO/buffer — no duplicated code.
uv sync --extra devimport gymnasium as gym
from ppo import PPO, RolloutBuffer, PPOTrainer
env = gym.make("CartPole-v1")
obs_dim = env.observation_space.shape[0]; n = env.action_space.n
agent = PPO(obs_dim, n)
buf = RolloutBuffer(size=2048, obs_dim=obs_dim)
trainer = PPOTrainer(agent, env, buf, seed=0)
hist = trainer.train(total_steps=100_000, rollout_len=2048)
print(trainer.evaluate(num_episodes=10))uv run python experiments/run_cartpole.py # validation (PPO reaches ~414/500)
uv run python experiments/run_lunarlander.py # full PPO
uv run python experiments/run_ablation.py # ablation (GAE/clip/entropy)Results in results/. Docs: docs/ — including the
ablation study, where removing GAE proved the most harmful.
uv run pytestIncludes exact numerical tests of GAE and the clipped objective.
MIT — see LICENSE.