Phase 09 - Lesson 08
Proximal Policy Optimization (PPO)
This lesson includes a graded coding exercise that runs in your browser, unlocked with lifetime access.
O A2C descarta cada rollout após uma única atualização. O PPO envolve o gradiente de política em uma razão de importância recortada (clipped importance ratio) para que você possa executar 10+ épocas nos mesmos dados sem que a política exploda. Schulman et al. (2017). Ainda é o algoritmo padrão de gradiente de política em 2026.
Tipo: Build Idiomas: Python Pré-requisitos: Phase 9 · 06 (REINFORCE), Phase 9 · 07 (Actor-Critic) Tempo: ~75 minutos
O Problema
O A2C (Lição 07) é on-policy: o gradiente E_{π_θ}[A · ∇ log π_θ] requer dados amostrados da π_θ atual. Faça uma atualização e a π_θ muda; os dados que você usou agora são off-policy. Reutilize-os e seu gradiente será enviesado.
Rollouts são caros. No Atari, um único rollout em 8 envs × 128 passos = 1024 transições e uma dúzia de segundos de tempo de ambiente. Descartar isso após um único passo de gradiente é um desperdício.
A otimização de política por região de confiança (Trust Region Policy Optimization - TRPO, Schulman 2015) foi a primeira solução: restringir cada atualização de modo que a divergência KL entre a política antiga e a nova permaneça abaixo de δ. Teoricamente elegante, mas requer a resolução de um gradiente conjugado a cada atualização. Ninguém executa TRPO em 2026.
O PPO (Schulman et al. 2017) substitui a restrição rígida de região de confiança por um objetivo recortado simples. Uma linha extra de código. Dez épocas por rollout. Sem gradientes conjugados. Garantias teóricas boas o suficiente. Nove anos depois, ainda é o algoritmo padrão de gradiente de política para tudo, de MuJoCo a RLHF.
O Conceito
A razão de importância.
r_t(θ) = π_θ(a_t | s_t) / π_{θ_old}(a_t | s_t)
Esta é a razão de verossimilhança da nova política em relação à política que coletou os dados. r_t = 1 significa nenhuma mudança. r_t = 2 significa que a nova política tem o dobro de probabilidade de escolher a_t em comparação com a antiga.
O substituto recortado (clipped surrogate).
L^{CLIP}(θ) = E_t [ min( r_t(θ) A_t, clip(r_t(θ), 1-ε, 1+ε) A_t ) ]
Dois termos:
- Se a vantagem
A_t > 0e a razão tenta crescer além de1 + ε, o recorte (clip) achata o gradiente — não empurre uma ação boa além de+εacima da probabilidade antiga. - Se a vantagem
A_t < 0e a razão tenta crescer além de1 - ε(o que significa que tornaríamos uma ação ruim mais provável em comparação com sua redução recortada), o recorte limita o gradiente — não empurre uma ação ruim abaixo de-ε.
O min lida com a outra direção: se a razão se moveu na direção benéfica, você ainda obtém o gradiente (sem recorte no lado que o prejudicaria).
ε = 0.2 típico. Plote o objetivo como uma função de r_t: uma função linear por partes com um teto plano no "lado bom" e um piso plano no "lado ruim".
A perda completa do PPO.
L(θ, φ) = L^{CLIP}(θ) - c_v · (V_φ(s_t) - V_t^{target})² + c_e · H(π_θ(·|s_t))
Mesma estrutura de ator-crítico que o A2C. Três coeficientes, geralmente c_v = 0.5, c_e = 0.01, ε = 0.2.
O loop de treinamento.
- Colete
N × Ttransições emNambientes paralelos porTpassos cada. - Compute as vantagens (GAE), congele-as como constantes.
- Congele
π_{θ_old}como um snapshot daπ_θatual. - Para
Képocas, para cada minibatch de(s, a, A, V_target, log π_old(a|s)):- Compute
r_t(θ) = exp(log π_θ(a|s) - log π_old(a|s)). - Aplique
L^{CLIP}+ perda de valor + entropia. - Passo de gradiente.
- Compute
- Descarte o rollout. Retorne ao passo 1.
K = 10 e minibatches de 64 é um conjunto padrão de hiperparâmetros. O PPO é robusto: os números exatos raramente importam dentro de uma variação de ±50%.
Variante de penalidade KL. O artigo original propôs uma alternativa usando uma penalidade KL adaptativa: L = L^{PG} - β · KL(π_θ || π_old) com β ajustado com base no KL observado. A versão com recorte tornou-se dominante; a variante KL sobrevive no RLHF (onde o KL em relação à política de referência é uma restrição separada que você sempre deseja de qualquer maneira).
Desenvolvendo (Build It)
Passo 1: capturar log π_old(a | s) no momento do rollout
for step in range(T):
probs = softmax(logits(theta, state_features(s)))
a = sample(probs, rng)
s_next, r, done = env.step(s, a)
buffer.append({
"s": s, "a": a, "r": r, "done": done,
"v_old": value(w, state_features(s)),
"log_pi_old": log(probs[a] + 1e-12),
})
s = s_next
O snapshot é tirado uma vez, no momento do rollout. Ele não muda durante as épocas de atualização.
Passo 2: calcular as vantagens GAE (Lição 07)
Igual ao A2C. Normalize em todo o lote (batch).
Passo 3: atualização do substituto recortado (clipped surrogate)
for _ in range(K_EPOCHS):
for mb in minibatches(buffer, size=64):
for rec in mb:
x = state_features(rec["s"])
probs = softmax(logits(theta, x))
logp = log(probs[rec["a"]] + 1e-12)
ratio = exp(logp - rec["log_pi_old"])
adv = rec["advantage"]
surrogate = min(
ratio * adv,
clamp(ratio, 1 - EPS, 1 + EPS) * adv,
)
# backprop -surrogate, add value loss, subtract entropy
grad_logpi = onehot(rec["a"]) - probs
if (adv > 0 and ratio >= 1 + EPS) or (adv < 0 and ratio <= 1 - EPS):
pg_grad = 0.0 # clipped
else:
pg_grad = ratio * adv
for i in range(N_ACTIONS):
for j in range(N_FEAT):
theta[i][j] += LR * pg_grad * grad_logpi[i] * x[j]
O padrão "recortado → gradiente zero" é o coração do PPO. Se a nova política já se desviou demais na direção benéfica, a atualização é interrompida.
Passo 4: valor e entropia
Adicione o MSE padrão ao alvo do crítico e um bônus de entropia no ator, igual ao A2C.
Passo 5: diagnósticos
Três coisas para monitorar a cada atualização:
- KL médio (Mean KL)
E[log π_old - log π_θ]. Deve permanecer em[0, 0.02]. Se ultrapassar0.1, reduzaK_EPOCHSou a taxa de aprendizado (LR). - Fração de recorte (Clip fraction) — a fração de amostras cuja razão está fora de
[1-ε, 1+ε]. Deve ser de~0.1-0.3. Se for~0, o recorte nunca é acionado → aumente aLRouK_EPOCHS. Se for~0.5+, você está sobreajustando (overfitting) o rollout → diminua-os. - Variância explicada (Explained variance)
1 - Var(V_target - V_pred) / Var(V_target). Métrica de qualidade do crítico. Deve subir em direção a 1 conforme o crítico aprende.
Armadilhas (Pitfalls)
- Coeficiente de recorte (clip coefficient) desregulado.
ε = 0.2é o padrão de fato. Mudar para0.1torna as atualizações muito tímidas;0.3+convida à instabilidade. - Muitas épocas.
K > 20rotineiramente desestabiliza porque a política se desvia muito deπ_old. Limite as épocas, especialmente para redes grandes. - Sem normalização de recompensas. Escalas de recompensa grandes consomem a faixa de recorte. Normalize as recompensas (desvio padrão móvel) antes de calcular as vantagens.
- Esquecer a normalização de vantagens. A normalização de média zero/desvio padrão unitário por lote é padrão. Ignorá-la arruína o PPO na maioria dos benchmarks.
- Taxa de aprendizado não decaída. O PPO se beneficia do decaimento linear da LR até zero. Uma LR constante costuma ser pior.
- Erros matemáticos na razão de importância. Sempre use
exp(log_new - log_old)para estabilidade numérica, nãonew / old. - Sinal do gradiente incorreto. Maximizar o substituto = minimizar
-L^{CLIP}. Um sinal invertido é o bug mais comum no PPO.
Como Usar (Use It)
O PPO é o algoritmo de RL padrão de 2026 em um número surpreendente de domínios:
| Caso de uso | Variante do PPO |
|---|---|
| MuJoCo / controle de robótica | PPO com política Gaussiana, GAE(0.95) |
| Atari / jogos discretos | PPO com política categórica, rollouts contínuos de 128 passos |
| RLHF para LLMs | PPO com penalidade KL para o modelo de referência, recompensa do RM ao final da resposta |
| Agentes de jogos em larga escala | IMPALA + PPO (AlphaStar, OpenAI Five) |
| LLMs de raciocínio | GRPO (Lição 12) — variante do PPO sem crítico |
| Dados apenas de preferência | DPO — colapso em forma fechada de PPO+KL, sem amostragem online |
O formato da perda do PPO — substituto recortado + valor + entropia — é a base para o DPO, GRPO e quase todo pipeline de RLHF.
Envie (Ship It)
Salve como outputs/skill-ppo-trainer.md:
---
name: ppo-trainer
description: Produce a PPO training config and a diagnostic plan for a given environment.
version: 1.0.0
phase: 9
lesson: 8
tags: [rl, ppo, policy-gradient]
---
Given an environment and training budget, output:
1. Rollout size. `N` envs × `T` steps.
2. Update schedule. `K` epochs, minibatch size, LR schedule.
3. Surrogate params. `ε` (clip), `c_v`, `c_e`, advantage normalization on.
4. Advantage. GAE(`λ`) with explicit `γ` and `λ`.
5. Diagnostics plan. KL, clip fraction, explained variance thresholds with alerts.
Refuse `K > 30` or `ε > 0.3` (unsafe trust region). Refuse any PPO run without advantage normalization or KL/clip monitoring. Flag clip fraction sustained above 0.4 as drift.
Exercícios
- Fácil. Execute o PPO no GridWorld 4×4 com
ε=0.2, K=4. Compare a eficiência de amostragem com a do A2C (uma época por rollout) em passos equivalentes do ambiente. - Médio. Varra
K ∈ {1, 4, 10, 30}. Plote o retorno versus os passos no ambiente e acompanhe o KL médio por atualização. Em qualKo KL explode nesta tarefa? - Difícil. Substitua o substituto recortado por uma penalidade KL adaptativa (
βdobrado seKL > 2·target, cortado pela metade seKL < target/2). Compare o retorno final, a estabilidade e a ausência de recorte (clip-free-ness).
Termos-Chave
| Termo | O que dizem | O que realmente significa |
|---|---|---|
| Razão de importância | "r_t(θ)" | `π_θ(a |
| Substituto recortado | "O principal truque do PPO" | min(r·A, clip(r, 1-ε, 1+ε)·A); gradiente plano após o recorte no lado benéfico. |
| Região de confiança | "Intenção do TRPO / PPO" | Limitar o KL de cada atualização para garantir melhora monótona. |
| Penalidade KL | "Região de confiança suave" | PPO alternativo: `L - β · KL(π_θ |
| Fração de recorte | "Com que frequência o recorte é acionado" | Diagnóstico — deve ser 0.1-0.3; fora disso significa desregulado. |
| Treinamento multi-época | "Reutilização de dados" | K épocas em cada rollout; custo de variância trocado por eficiência de amostragem. |
| Quase on-policy | "Principalmente on-policy" | O PPO é nominalmente on-policy, mas K>1 épocas usam dados ligeiramente off-policy com segurança. |
| PPO-KL | "O outro PPO" | Variante com penalidade KL; usada no RLHF onde o KL em relação à referência já é uma restrição. |
Leituras Adicionais
- Schulman et al. (2017). Proximal Policy Optimization Algorithms — o artigo.
- Schulman et al. (2015). Trust Region Policy Optimization — TRPO, o predecessor do PPO.
- Andrychowicz et al. (2021). What Matters In On-Policy RL? A Large-Scale Empirical Study — cada hiperparametro do PPO ablatado.
- Ouyang et al. (2022). Training language models to follow instructions with human feedback — InstructGPT; a receita do PPO no RLHF.
- OpenAI Spinning Up — PPO — exposição moderna e clara com PyTorch.
- CleanRL PPO implementation — implementação do PPO em arquivo único de referência usada por muitos artigos.
- Hugging Face TRL — PPOTrainer — a receita de produção para PPO em modelos de linguagem; leia junto com a Lição 09 (RLHF).
- Engstrom et al. (2020). Implementation Matters in Deep Policy Gradients — o artigo sobre as "37 otimizações no nível do código"; quais truques do PPO são estruturais e quais são folclore.