Salta ai contenuti

Policy gradient e REINFORCE: ottimizzare direttamente la policy

Q-learning impara un valore e ne deriva una policy come arg-max; il policy gradient salta il passaggio e tocca direttamente i parametri della policy, spinto da un trucco di calcolo che vale per qualsiasi distribuzione campionabile. È la macchina che oggi muove RLHF, l’algoritmo dietro ChatGPT, Claude e ogni agent fine-tuning con reward task-specifico.

Il capitolo precedente ha chiuso l’arco value-based: si stima QQ^*, e la policy ottima esce gratis come argmaxaQ(s,a)\arg\max_a Q(s,a). Funziona quando le azioni sono poche e discrete e quando si ha pazienza di aspettare la convergenza di un fixed point. Si rompe quando le azioni sono continue (un torque, una posizione, un token su un vocabolario di 128.000 elementi), quando la policy ottima è stocastica (gioco a somma zero, ambiente partial-observable), quando la cosa che si ottimizza non è un return scalare ma una preferenza umana fra due output di un language model.

Per tutti questi casi serve un altro modo di guardare il problema: parametrizzare la policy πθ(as)\pi_\theta(a|s) con una rete neurale e ottimizzare θ\theta direttamente massimizzando il return atteso J(θ)=Eτπθ[R(τ)]J(\theta) = \mathbb{E}_{\tau \sim \pi_\theta}[R(\tau)]. È la famiglia policy-based, e questo capitolo ne fissa i fondamenti: REINFORCE come algoritmo seminal, il Policy Gradient Theorem come giustificazione formale, baseline e advantage come arnesi di riduzione della varianza, PPO come compromesso pratico che oggi gira in produzione su scala di miliardi di parametri.

Tre motivi per cui conta. Il primo è di filiazione: REINFORCE (Williams 1992) → Policy Gradient Theorem (Sutton et al. 2000) → Natural Policy Gradient (Kakade 2001) → TRPO (Schulman 2015) → PPO (Schulman 2017) sono una catena lineare. Senza la radice, nessuna foglia ha senso. Il secondo è operativo: Long Ouyang e colleghi nel 2022, in “Training language models to follow instructions with human feedback” (NeurIPS 2022), formalizzano l’allineamento di GPT-3.5 come un loop PPO con reward model e KL penalty contro una reference policy. Quel loop, nelle sue varianti, è ciò che sta dietro ChatGPT, Claude, Gemini, e ogni agent post-trained con reward task-specifico fino al 2026. Il terzo è di collegamento: per capire DPO, GRPO, RLAIF, Constitutional AI, reasoning RL alla DeepSeek-R1, occorre essere fluenti nel linguaggio score function / advantage / clipped surrogate. Senza questo capitolo quei nomi sono sigle.

La promessa esecutiva: alla fine si saprà derivare REINFORCE in cinque righe di calcolo, scrivere un PPO minimal in ottanta righe di PyTorch, leggere l’objective di RLHF e dire dove sta il policy gradient, dove la KL penalty, dove il reward model. E si saprà perché PPO è “instabile e costoso”, che è la frase con cui Rafailov e colleghi giustificano, nel 2023, l’esistenza di DPO.

Il grafo concettuale si appoggia a quattro filoni che convergono fra il 1970 e il 2017.

Score function gradient e reinforcement comparison. Già negli anni ‘60-‘70 la statistica conosce il “log-derivative trick” o “score function estimator”: un modo per stimare il gradiente di un’aspettazione campionando dalla distribuzione stessa. La stessa idea ricompare in stochastic optimization (Glynn anni ‘80), in econometria, nei “likelihood ratio gradient estimator”. Ronald Williams (informatico statunitense, allora a Northeastern University), nel 1992, in “Simple Statistical Gradient-Following Algorithms for Connectionist Reinforcement Learning” (Machine Learning vol. 8), porta il trucco dentro l’RL applicato alle reti neurali. Battezza la famiglia REINFORCE (un acronimo forzato per “REward Increment = Nonnegative Factor times Offset Reinforcement times Characteristic Eligibility”) e ne deriva versioni episodic e step-by-step. È il paper-radice.

Programmazione dinamica e Bellman. Visto in markov-decision-process (122) e equazione-bellman (123). Policy gradient non passa per fixed point di Bellman direttamente — non stima VV^* o QQ^* — ma li usa come strumenti accessori (baseline, critic). La differenza ontologica è netta: nel value-based la policy è un derivato del valore; nel policy-based la policy è il primum movens, e il valore è uno strumento di varianza.

Function approximation con reti neurali. Senza la backpropagation di Rumelhart-Hinton-Williams (1986) e senza la dimostrazione empirica che le reti scalano (Tesauro 1992, Mnih 2013, vedi td-gammon-1992 e dqn-atari-2013), il policy gradient resta un esercizio teorico. Richard Sutton (informatico canadese, University of Alberta e DeepMind, padre del moderno RL e co-autore con Andrew Barto del manuale di riferimento), David McAllester, Satinder Singh, Yishay Mansour pubblicano nel 2000 (NIPS 1999) “Policy Gradient Methods for Reinforcement Learning with Function Approximation”. Il Policy Gradient Theorem dimostrato lì ha la forma con la quale è scritto in ogni implementazione moderna: θJ(θ)=E[θlogπθ(as)Qπ(s,a)]\nabla_\theta J(\theta) = \mathbb{E}[\nabla_\theta \log \pi_\theta(a|s) \cdot Q^\pi(s,a)].

Trust region e geometric optimization. Sham Kakade (matematico, Harvard) introduce nel 2001 il Natural Policy Gradient: usa la matrice di informazione di Fisher come preconditioner. Idea: il gradiente in spazio dei parametri è arbitrario, perché due parametrizzazioni diverse della stessa distribuzione danno gradienti diversi; si vuole un gradiente nello spazio delle distribuzioni, dove la metrica naturale è la KL. Vijay Konda (operations research, MIT) e John Tsitsiklis (operations researcher, MIT) formalizzano in parallelo il framework actor-critic (2003): policy = actor, value function = critic stimato in parallelo per ridurre varianza dello stimatore.

Il salto deep arriva con John Schulman (informatico statunitense, ex-OpenAI ora Anthropic). Tre paper consecutivi cambiano lo stato dell’arte. Nel 2015 “Trust Region Policy Optimization” (ICML) introduce TRPO: ottimizza un surrogate sotto vincolo KL(πoldπθ)δ\mathrm{KL}(\pi_{old} \| \pi_\theta) \leq \delta, con conjugate gradient su Fisher-vector products. Nello stesso anno, “High-Dimensional Continuous Control Using Generalized Advantage Estimation” (ICLR 2016) introduce GAE: stima dell’advantage con bias-variance tradeoff parametrizzato da λ\lambda. Nel 2017 “Proximal Policy Optimization Algorithms” (arXiv:1707.06347) introduce PPO: stessa intenzione di TRPO (non muoversi troppo dalla policy precedente) ma con un vincolo soft via clipping del ratio di probabilità. PPO funziona, è semplice, gira su SGD standard. Diventa lo standard de facto.

In parallelo, Volodymyr Mnih (DeepMind) e colleghi (2016, ICML) propongono A3C / A2C: parallel actor-learners che fanno rollout in parallelo, eliminando il bisogno di replay buffer e dando varianza bassa con on-policy. Tuomas Haarnoja (Berkeley/DeepMind) nel 2018 propone SAC (Soft Actor-Critic): off-policy, max-entropy, robusto su continuous control. Sono i tre pilastri del deep policy gradient pre-LLM.

L’innesto su LLM avviene nel 2022. Long Ouyang e colleghi (OpenAI) pubblicano “Training language models to follow instructions with human feedback” (arXiv:2203.02155). Il pipeline è: (1) supervised fine-tuning su demos umane; (2) reward model addestrato su preferenze pairwise umane; (3) PPO loop con il reward model come rr e una KL penalty βKL(πθπref)\beta \cdot \mathrm{KL}(\pi_\theta \| \pi_{ref}) contro la reference policy. Il modello risultante, InstructGPT, è il diretto antenato di ChatGPT-3.5 lanciato a novembre 2022. Vedi chatgpt-2022 (24) per la cornice. Il pattern viene immediatamente adottato da Anthropic, Google DeepMind, Meta.

Rafael Rafailov (Stanford) e colleghi nel 2023 in “Direct Preference Optimization” (NeurIPS 2023) mostrano che, sotto reward Bradley-Terry e KL-regularization, l’optimal policy ha forma chiusa π(yx)πref(yx)exp(r(x,y)/β)\pi^*(y|x) \propto \pi_{ref}(y|x) \exp(r(x,y)/\beta); invertendo per rr e sostituendo nella binary cross-entropy su preferenze pairwise, si ottiene una loss supervised che bypassa rollout PPO. È un’equivalenza argomentabile — coincide con PPO in setting bandit con KL-reg, ha gap nel caso multi-step. Nel 2024, DeepSeek-AI introduce GRPO (Group Relative Policy Optimization, “DeepSeekMath” arXiv:2402.03300): variante PPO che sostituisce il critic con una baseline group-relative (media del reward su un gruppo di rollout dallo stesso prompt), riducendo costo memoria. Diventa la spina dorsale di DeepSeek-R1 (2025), il primo modello reasoning open-weight competitivo.

Una nota di differenziazione per evitare doppioni. In 122 si è introdotto l’MDP. In 123 si è dato Bellman. In 124 si sono visti VI/PI con modello noto. In 125 Q-learning sostituisce il modello con campioni e impara QQ^*. Qui — capitolo 126 — non si stima un valore per derivarne la policy: si parametrizza la policy direttamente e si ottimizza per gradient ascent. Actor-critic e PPO/TRPO dettagliati arrivano nei capitoli successivi (in preparazione); qui si dà la loro radice formale e un PPO minimo operativo, perché PPO è ciò che si vede in produzione.

Tre angoli prima del formalismo. Due descrivono il policy gradient standalone; il terzo lega la macchina a RLHF, che è la motivazione operativa di chi legge.

Angolo 1 — Alza la probabilità di ciò che ha funzionato

Sezione intitolata “Angolo 1 — Alza la probabilità di ciò che ha funzionato”

ANALOGIA (didattica, non causale). Pensa a un bambino che impara a tirare canestro. Tira, qualche volta entra, qualche volta no. Non ha un modello fisico del pallone. Quello che fa, in modo automatico, è: dopo un canestro riuscito, “fissa” qualcosa nel gesto — la posizione del polso, il piegamento delle ginocchia — e tende a ripetere quel pattern. Dopo un tiro fallito, il pattern viene leggermente sfumato.

Policy gradient è la versione formale di questa intuizione. La policy πθ(as)\pi_\theta(a|s) assegna una probabilità a ogni azione possibile in ogni stato. Dopo una traiettoria di reward totale RR, se RR è alto si vuole che le azioni effettivamente prese diventino più probabili in quegli stati; se RR è basso, meno probabili. Il modo formale di “aumentare la probabilità di aa in ss” è muovere θ\theta nella direzione θlogπθ(as)\nabla_\theta \log \pi_\theta(a|s), scalata da quanto RR è stato buono.

L’aggiornamento elementare è

θθ+αθlogπθ(atst)Rt.\theta \leftarrow \theta + \alpha \cdot \nabla_\theta \log \pi_\theta(a_t|s_t) \cdot R_t.

Letteralmente: la quantità θlogπθ(atst)\nabla_\theta \log \pi_\theta(a_t|s_t) è la direzione in cui spingere i parametri per rendere ata_t più probabile in sts_t; lo scalare RtR_t dice se vale la pena spingere (positivo) o tirare indietro (negativo).

Marca la classe: questa è ANALOGIA. Il bambino non fa gradient ascent; il policy gradient non capisce cosa sta facendo. La somiglianza è didattica.

Angolo 2 — Il log-derivative trick come unica idea

Sezione intitolata “Angolo 2 — Il log-derivative trick come unica idea”

C’è un’unica identità matematica che fa funzionare tutto il resto. Si vuole calcolare il gradiente di un’aspettazione di una funzione, dove la distribuzione stessa dipende dai parametri:

θExpθ[f(x)]=θpθ(x)f(x)dx.\nabla_\theta \mathbb{E}_{x \sim p_\theta}[f(x)] = \nabla_\theta \int p_\theta(x) f(x) \, dx.

Scambiando gradiente e integrale (sotto regolarità), e usando l’identità θpθ(x)=pθ(x)θlogpθ(x)\nabla_\theta p_\theta(x) = p_\theta(x) \cdot \nabla_\theta \log p_\theta(x), si ottiene:

θExpθ[f(x)]=Expθ[θlogpθ(x)f(x)].\nabla_\theta \mathbb{E}_{x \sim p_\theta}[f(x)] = \mathbb{E}_{x \sim p_\theta}[\nabla_\theta \log p_\theta(x) \cdot f(x)].

Questo è il log-derivative trick (TEOREMA: identità esatta, non approssimazione). La rilevanza è che il lato destro è stimabile via Monte Carlo: campiona xipθx_i \sim p_\theta, calcola θlogpθ(xi)f(xi)\nabla_\theta \log p_\theta(x_i) \cdot f(x_i), fai la media. È un’identità nota in statistica fin dagli anni ‘60; Williams 1992 la importa in RL, Sutton 2000 la generalizza al setting MDP.

Applicato a RL: ff = return della traiettoria, pθp_\theta = distribuzione di traiettorie indotta da πθ\pi_\theta. La densità delle traiettorie si fattorizza in (probabilità iniziale) × (prodotto di transizioni) × (prodotto di azioni). Solo le azioni dipendono da θ\theta. Il gradiente del log si decompone perciò in

θlogpθ(τ)=tθlogπθ(atst).\nabla_\theta \log p_\theta(\tau) = \sum_t \nabla_\theta \log \pi_\theta(a_t|s_t).

I termini ρ0(s0)\rho_0(s_0) e P(st+1st,at)P(s_{t+1}|s_t,a_t) scompaiono. È la ragione tecnica per cui policy gradient è model-free: non serve mai stimare PP.

Angolo 3 — Il loop di RLHF è un policy gradient travestito

Sezione intitolata “Angolo 3 — Il loop di RLHF è un policy gradient travestito”

L’objective che Ouyang 2022 ottimizza per InstructGPT è

maxπθExD,yπθ(x)[rϕ(x,y)βlog(πθ(yx)/πref(yx))]\max_{\pi_\theta} \mathbb{E}_{x \sim D, y \sim \pi_\theta(\cdot|x)} \big[ r_\phi(x,y) - \beta \log(\pi_\theta(y|x) / \pi_{ref}(y|x)) \big]

dove rϕr_\phi è il reward model congelato addestrato su preferenze umane, e πref\pi_{ref} è la policy SFT di partenza congelata. Il termine KL impedisce a πθ\pi_\theta di andare troppo lontano da πref\pi_{ref} (mode collapse, reward hacking).

EQUIVALENZA ARGOMENTABILE: questo è policy gradient standard con reward modificato r(x,y)=rϕ(x,y)βlog(πθ(yx)/πref(yx))r'(x,y) = r_\phi(x,y) - \beta \log(\pi_\theta(y|x) / \pi_{ref}(y|x)). Un LLM è una policy che produce token un alla volta; ogni prompt xx è uno stato; ogni completion yy è una traiettoria di azioni; il reward è terminale (assegnato alla fine della completion). Si rollouta, si calcola rr', si fa PPO clipped sull’advantage stimato. Marca la classe: equivalenza sotto ipotesi (in particolare assumendo che πref\pi_{ref} sia fissato e che il reward sia terminale o token-decomposto in modo coerente). Non è identità formale generale.

Tre angoli, una macchina sola.

Prima di entrare nelle formule, fissa una tassonomia operativa dei metodi policy-based. Aiuta a non confondere i nomi.

  • REINFORCE (Williams 1992): vanilla policy gradient con return Monte Carlo come stimatore di QπQ^\pi. Niente critic. Alta varianza.
  • REINFORCE con baseline: aggiunge b(s)Vπ(s)b(s) \approx V^\pi(s) stimato online, riduce varianza. Già un actor-critic minimal.
  • A2C / A3C (Mnih 2016): actor-critic on-policy, advantage stimato a n-step o tramite GAE, parallelizzato su molti worker. A3C asincrono, A2C sincrono — in pratica A2C funziona altrettanto bene ed è più semplice.
  • NPG (Kakade 2001): policy gradient preconditioned con Fisher information matrix.
  • TRPO (Schulman 2015): NPG + trust region KL esplicito + line search; garantisce monotonic improvement sotto ipotesi.
  • PPO (Schulman 2017): TRPO approssimato via clip del probability ratio; SGD standard, niente Fisher, niente CG.
  • DDPG (Lillicrap 2015), TD3 (Fujimoto 2018): deterministic policy gradient + actor-critic off-policy con replay; per continuous control.
  • SAC (Haarnoja 2018): max-entropy stochastic actor-critic off-policy con replay; standard moderno per continuous control.
  • GRPO (DeepSeek 2024): PPO-like con baseline group-relative invece di critic; specializzato per reasoning RL.

I primi cinque sono on-policy; gli ultimi tre tipicamente off-policy (con caveat). Il capitolo si concentra su REINFORCE come base e PPO come algoritmo operativo; actor-critic dettagliato e PPO/TRPO completi sono in capitoli dedicati (in preparazione).

Un MDP M=(S,A,P,R,γ,ρ0)\mathcal{M} = (S, A, P, R, \gamma, \rho_0) con γ[0,1)\gamma \in [0,1) e distribuzione iniziale ρ0\rho_0 su SS. Una policy stocastica parametrizzata πθ(as)\pi_\theta(a|s) — tipicamente softmax su logits di una rete (azioni discrete) o gaussiana con media e std prodotte da una rete (azioni continue).

Una traiettoria τ=(s0,a0,r0,s1,a1,r1,,sT)\tau = (s_0, a_0, r_0, s_1, a_1, r_1, \dots, s_T) ha densità

pθ(τ)=ρ0(s0)t=0T1πθ(atst)P(st+1st,at).p_\theta(\tau) = \rho_0(s_0) \prod_{t=0}^{T-1} \pi_\theta(a_t|s_t) \, P(s_{t+1}|s_t, a_t).

Il return della traiettoria è R(τ)=t=0T1γtrtR(\tau) = \sum_{t=0}^{T-1} \gamma^t r_t. L’objective è

J(θ)=Eτπθ[R(τ)].J(\theta) = \mathbb{E}_{\tau \sim \pi_\theta}[R(\tau)].

Si vuole θ=argmaxθJ(θ)\theta^* = \arg\max_\theta J(\theta), via gradient ascent: θθ+αθJ(θ)\theta \leftarrow \theta + \alpha \nabla_\theta J(\theta). Manca solo θJ(θ)\nabla_\theta J(\theta).

Riga 1. Definizione dell’objective.

J(θ)=pθ(τ)R(τ)dτ.J(\theta) = \int p_\theta(\tau) R(\tau) \, d\tau.

Riga 2. Gradiente sotto integrale (regolarità).

θJ(θ)=θpθ(τ)R(τ)dτ.\nabla_\theta J(\theta) = \int \nabla_\theta p_\theta(\tau) R(\tau) \, d\tau.

Riga 3. Identità p=plogp\nabla p = p \nabla \log p.

=pθ(τ)θlogpθ(τ)R(τ)dτ=Eτ[θlogpθ(τ)R(τ)].= \int p_\theta(\tau) \nabla_\theta \log p_\theta(\tau) R(\tau) \, d\tau = \mathbb{E}_\tau[\nabla_\theta \log p_\theta(\tau) \cdot R(\tau)].

Riga 4. Log della densità si fattorizza; solo i πθ(atst)\pi_\theta(a_t|s_t) dipendono da θ\theta.

θlogpθ(τ)=t=0T1θlogπθ(atst).\nabla_\theta \log p_\theta(\tau) = \sum_{t=0}^{T-1} \nabla_\theta \log \pi_\theta(a_t|s_t).

Riga 5. Sostituendo:

θJ(θ)=Eτ ⁣[(tθlogπθ(atst))R(τ)].\nabla_\theta J(\theta) = \mathbb{E}_\tau\!\left[ \left(\sum_t \nabla_\theta \log \pi_\theta(a_t|s_t)\right) R(\tau) \right].

Questa è la forma “vanilla” di REINFORCE. Williams 1992 mostra che si può raffinare. Una traiettoria all’istante tt è influenzata solo dalle azioni successive; le azioni passate non possono cambiare il passato. Quindi si può sostituire R(τ)R(\tau) con il return da tt, Gt=k=tT1γktrkG_t = \sum_{k=t}^{T-1} \gamma^{k-t} r_k, ottenendo lo stimatore a varianza minore

θJ(θ)=E ⁣[tθlogπθ(atst)Gt].\nabla_\theta J(\theta) = \mathbb{E}\!\left[\sum_t \nabla_\theta \log \pi_\theta(a_t|s_t) \cdot G_t\right].

Questa è la forma “REINFORCE con causality” che si trova nelle implementazioni.

TEOREMA (Sutton-McAllester-Singh-Mansour 2000, riformulato per policy parametrizzata differenziabile): per un MDP con discount γ\gamma e policy stocastica πθ\pi_\theta,

θJ(θ)=Esdπ,aπθ(s) ⁣[θlogπθ(as)Qπ(s,a)]\nabla_\theta J(\theta) = \mathbb{E}_{s \sim d^\pi, \, a \sim \pi_\theta(\cdot|s)}\!\left[ \nabla_\theta \log \pi_\theta(a|s) \cdot Q^\pi(s,a) \right]

dove dπ(s)d^\pi(s) è la distribuzione discounted di stati visitati sotto π\pi.

Significato. Il gradiente del return atteso è uguale all’aspettazione, sotto la distribuzione naturale di stati e azioni sotto la policy, del prodotto fra (spinta che alza la probabilità di aa in ss) e (quanto vale fare aa in ss). Tre conseguenze pratiche.

Prima: QπQ^\pi è la quantità giusta da pesare con logπ\nabla \log \pi, non GtG_t in generale; GtG_t è uno stimatore unbiased ma molto rumoroso di QπQ^\pi. Questo motiva actor-critic.

Seconda: la distribuzione dπd^\pi è “naturale”: campionare la distribuzione di stati sotto la policy corrente equivale, in aspettazione, a stimare il gradiente. È on-policy: cambiare policy cambia dπd^\pi.

Terza: il teorema giustifica la sostituzione di QπQ^\pi con qualsiasi funzione f(s,a)f(s,a) tale che Ea[logπ(as)(f(s,a)Qπ(s,a))]=0\mathbb{E}_a[\nabla \log \pi(a|s) \cdot (f(s,a) - Q^\pi(s,a))] = 0. Una scelta possibile è f(s,a)=Qπ(s,a)Vπ(s)=Aπ(s,a)f(s,a) = Q^\pi(s,a) - V^\pi(s) = A^\pi(s,a), l’advantage.

Baseline e advantage (riduzione varianza, no bias)

Sezione intitolata “Baseline e advantage (riduzione varianza, no bias)”

Sostituire GtG_t con Gtb(st)G_t - b(s_t) per qualsiasi funzione bb che non dipende da ata_t lascia il gradiente invariato in aspettazione:

Ea[θlogπθ(as)b(s)]=b(s)aπθ(as)θπθ(as)πθ(as)=b(s)θaπθ(as)=b(s)θ1=0.\mathbb{E}_a[\nabla_\theta \log \pi_\theta(a|s) \cdot b(s)] = b(s) \sum_a \pi_\theta(a|s) \frac{\nabla_\theta \pi_\theta(a|s)}{\pi_\theta(a|s)} = b(s) \nabla_\theta \sum_a \pi_\theta(a|s) = b(s) \nabla_\theta 1 = 0.

Ne segue (TEOREMA di unbiasedness): la baseline introduce zero bias. Riduce la varianza dello stimatore se b(s)b(s) è correlata con GtG_t. La scelta ottimale (in MSE) è vicina a Vπ(s)V^\pi(s). In pratica si addestra una rete Vϕ(s)V_\phi(s) in parallelo (il critic), e si usa

A^t=GtVϕ(st)\hat A_t = G_t - V_\phi(s_t)

come stimatore di Aπ(st,at)A^\pi(s_t, a_t). Questo è già un actor-critic minimal.

Schulman et al. 2015 propongono un compromesso bias-variance parametrizzato. Definendo l’errore TD a un passo δt=rt+γVϕ(st+1)Vϕ(st)\delta_t = r_t + \gamma V_\phi(s_{t+1}) - V_\phi(s_t), il GAE è

A^tGAE(γ,λ)=l=0(γλ)lδt+l.\hat A_t^{\mathrm{GAE}(\gamma, \lambda)} = \sum_{l=0}^{\infty} (\gamma \lambda)^l \delta_{t+l}.

Casi limite. λ=0\lambda=0: A^t=δt\hat A_t = \delta_t (TD(0), basso varianza, alto bias se VϕV_\phi è inaccurata). λ=1\lambda=1: A^t=GtVϕ(st)\hat A_t = G_t - V_\phi(s_t) (Monte Carlo, alto varianza, zero bias). λ0.95\lambda \approx 0.95 è il default di facto in PPO.

bias-variance tradeoff: tre curve sovrapposte (lambda=0, lambda=0.95, lambda=1) su un asse "training steps", asse y "advantage estimate variance"; label inglese: "low variance, high bias" / "balanced" / "low bias, high variance"

Il problema del REINFORCE/A2C standard: passi di gradiente troppo grandi su distribuzioni rare possono cambiare la policy in modo catastrofico (la nuova policy è qualitativamente diversa, gli advantage stimati con la vecchia non valgono più, il training collassa).

TRPO (Schulman 2015) impone formalmente KL(πθoldπθ)δ\mathrm{KL}(\pi_{\theta_{old}} \| \pi_\theta) \leq \delta a ogni update e ottimizza il surrogate via conjugate gradient su Fisher-vector products. Funziona, ma è costoso.

PPO (Schulman 2017) approssima la stessa intenzione con un trucco euristico. Definisci il probability ratio

rt(θ)=πθ(atst)πθold(atst).r_t(\theta) = \frac{\pi_\theta(a_t|s_t)}{\pi_{\theta_{old}}(a_t|s_t)}.

Il surrogate “vanilla” è LVPG(θ)=Et[rt(θ)A^t]L^{\mathrm{VPG}}(\theta) = \mathbb{E}_t[r_t(\theta) \hat A_t] (versione importance-sampling di policy gradient). Il clipped surrogate è

LCLIP(θ)=Et ⁣[min ⁣(rt(θ)A^t,clip(rt(θ),1ϵ,1+ϵ)A^t)]L^{\mathrm{CLIP}}(\theta) = \mathbb{E}_t\!\left[\min\!\big( r_t(\theta) \hat A_t, \, \mathrm{clip}(r_t(\theta), 1-\epsilon, 1+\epsilon) \cdot \hat A_t \big)\right]

con ϵ\epsilon tipicamente 0.10.1 o 0.20.2. Il significato del min: se A^t>0\hat A_t > 0 (azione migliore della media), il gradiente smette di crescere quando rtr_t supera 1+ϵ1+\epsilon; se A^t<0\hat A_t < 0, smette quando rtr_t scende sotto 1ϵ1-\epsilon. Il min protegge dal lato pessimistico e disincentiva movimenti troppo grandi. Marca la classe: PPO clip è euristica, non garantisce KL ≤ δ. Engstrom et al. (2020, “Implementation Matters in Deep RL”) mostrano che molti vantaggi di PPO sono attribuibili a ottimizzazioni di codice (advantage normalization, learning rate scheduling, value clipping) più che al clip in sé. Resta lo standard de facto.

La loss totale di PPO include tre termini: il clipped surrogate, una value loss, un entropy bonus.

LTOT=LCLIPc1(Vϕ(st)Vttarg)2+c2H[πθ(st)]L^{\mathrm{TOT}} = L^{\mathrm{CLIP}} - c_1 (V_\phi(s_t) - V^{\mathrm{targ}}_t)^2 + c_2 \, H[\pi_\theta(\cdot|s_t)]

con c10.5c_1 \approx 0.5, c20.01c_2 \approx 0.01. L’entropy bonus tiene la policy esplorativa, contrastando l’entropy collapse.

PPO clipped vs unclipped: due curve di L^surrogate vs r_t a parità di Â=+1, una lineare (unclipped), una con plateau dopo r=1+ε; secondo subplot per Â=-1; label inglese "L_surrogate", "probability ratio r_t", "Â > 0", "Â < 0"

Il gradiente standard θJ\nabla_\theta J vive nello spazio dei parametri. Ma la stessa policy può essere parametrizzata in mille modi diversi (una rete con bias, senza, con normalizzazione differente), e il gradiente standard cambia a seconda della parametrizzazione. La distanza naturale fra due policy non è la distanza euclidea fra i parametri ma una distanza fra distribuzioni — la più usata è la KL divergence, e localmente la KL è quadratica con metrica data dalla matrice di informazione di Fisher F(θ)=E[(θlogπθ)(θlogπθ)]F(\theta) = \mathbb{E}[(\nabla_\theta \log \pi_\theta)(\nabla_\theta \log \pi_\theta)^\top].

Sham Kakade (2001, “A Natural Policy Gradient”, NIPS) propone il preconditioner: invece del gradiente g=θJg = \nabla_\theta J, usa g~=F1g\tilde g = F^{-1} g. È il gradiente naturale: la direzione di massimo aumento di JJ per unità di KL, non per unità di norma euclidea. TRPO è essenzialmente NPG con un trust region esplicito; PPO è un’approssimazione ulteriore che evita di calcolare FF.

Marca la classe: NPG è una filiazione diretta dell’information geometry di Amari (1985), non un’analogia; le trust region di TRPO/PPO discendono storicamente da NPG. Per un trattamento moderno e leggibile vedi Schulman 2015 sezione 3, oppure il blog post di Achiam su Spinning Up.

Esempio 1 — Numerico: REINFORCE su un contextual bandit a 3 azioni

Sezione intitolata “Esempio 1 — Numerico: REINFORCE su un contextual bandit a 3 azioni”

Stato fisso (un solo stato). Tre azioni, reward deterministico r=(0,1,2)r = (0, 1, 2). Policy softmax con logits θ=(θ1,θ2,θ3)\theta = (\theta_1, \theta_2, \theta_3), π(a)=exp(θa)/jexp(θj)\pi(a) = \exp(\theta_a) / \sum_j \exp(\theta_j). Init θ=(0,0,0)\theta = (0, 0, 0), quindi π=(1/3,1/3,1/3)\pi = (1/3, 1/3, 1/3).

Iterazione 1. Sample: a=2a = 2 (probabilità 1/3), reward osservato r=1r = 1.

Calcolo del gradiente del log della policy. Per softmax, vale l’identità (verificabile per derivazione diretta)

θjlogπ(a)=1[j=a]π(j).\nabla_{\theta_j} \log \pi(a) = \mathbb{1}[j = a] - \pi(j).

In forma vettoriale: θlogπ(a=2)=e2π=(0,1,0)(1/3,1/3,1/3)=(1/3,2/3,1/3)\nabla_\theta \log \pi(a=2) = e_2 - \pi = (0, 1, 0) - (1/3, 1/3, 1/3) = (-1/3, 2/3, -1/3).

Update REINFORCE senza baseline: θθ+αGlogπ\theta \leftarrow \theta + \alpha \cdot G \cdot \nabla \log \pi con α=0.5\alpha = 0.5, G=1G = 1. Risultato: θ=(0.167,0.333,0.167)\theta = (-0.167, 0.333, -0.167).

Nuova policy. exp(θ)(0.846,1.395,0.846)\exp(\theta) \approx (0.846, 1.395, 0.846), somma 3.087\approx 3.087, π(0.274,0.452,0.274)\pi \approx (0.274, 0.452, 0.274). L’azione 2 è ora più probabile, le altre meno. Esattamente la dinamica intuitiva: “ho preso a=2a=2 e ho avuto un reward positivo, quindi la rendo più probabile”.

Cosa va male senza baseline. Tutti i reward sono positivi, quindi ogni update alza la probabilità dell’azione campionata, anche se è subottimale. L’azione 1 (r=0r=0) viene rinforzata se campionata (reward zero, gradiente nullo, neutrale); l’azione 2 (r=1r=1) viene rinforzata se campionata; l’azione 3 (r=2r=2) viene rinforzata di più. Solo grazie all’esplorazione (sampling stocastico) si arriva ad aggiornare l’azione 3 e θ3\theta_3 a sua volta cresce — ma il processo è lento.

Fix con baseline. Se bb = media dei reward osservati (1\approx 1), advantage A^=rb\hat A = r - b. Per azione 1: A^=1\hat A = -1 (decremento). Per azione 2: A^=0\hat A = 0 (neutro). Per azione 3: A^=+1\hat A = +1 (incremento). Ora le azioni subottimali vengono attivamente ridotte, non ignorate. La convergenza è molto più rapida.

Esempio 2 — Codice: PPO su CartPole-v1 in PyTorch (≈80 righe)

Sezione intitolata “Esempio 2 — Codice: PPO su CartPole-v1 in PyTorch (≈80 righe)”

Versione minimal, single-file, didattica. Le scelte sono didattiche, non production: in produzione si usa stable-baselines3 o cleanrl.

import gym, torch, torch.nn as nn, torch.optim as optim
from torch.distributions import Categorical
class ActorCritic(nn.Module):
def __init__(self, obs_dim, act_dim):
super().__init__()
self.shared = nn.Sequential(nn.Linear(obs_dim, 64), nn.Tanh(),
nn.Linear(64, 64), nn.Tanh())
self.pi_head = nn.Linear(64, act_dim)
self.v_head = nn.Linear(64, 1)
def forward(self, x):
h = self.shared(x)
return self.pi_head(h), self.v_head(h).squeeze(-1)
env = gym.make("CartPole-v1")
ac = ActorCritic(4, 2)
opt = optim.Adam(ac.parameters(), lr=3e-4)
gamma, lam, eps_clip, K_epochs, T = 0.99, 0.95, 0.2, 4, 2048
def collect_rollout():
obs_buf, act_buf, rew_buf, val_buf, logp_buf, done_buf = [], [], [], [], [], []
s, _ = env.reset()
for _ in range(T):
s_t = torch.tensor(s, dtype=torch.float32)
with torch.no_grad():
logits, v = ac(s_t)
dist = Categorical(logits=logits); a = dist.sample()
logp = dist.log_prob(a)
s2, r, term, trunc, _ = env.step(a.item())
obs_buf.append(s); act_buf.append(a.item()); rew_buf.append(r)
val_buf.append(v.item()); logp_buf.append(logp.item())
done_buf.append(term or trunc)
s = s2 if not (term or trunc) else env.reset()[0]
return obs_buf, act_buf, rew_buf, val_buf, logp_buf, done_buf
def gae(rews, vals, dones, gamma, lam):
advs = [0.0] * len(rews); last = 0.0
for t in reversed(range(len(rews))):
v_next = 0.0 if (t == len(rews)-1 or dones[t]) else vals[t+1]
delta = rews[t] + gamma * v_next * (1 - dones[t]) - vals[t]
last = delta + gamma * lam * (1 - dones[t]) * last
advs[t] = last
return advs
for it in range(500):
obs, acts, rews, vals, logp_old, dones = collect_rollout()
advs = gae(rews, vals, dones, gamma, lam)
rets = [a + v for a, v in zip(advs, vals)]
obs_t = torch.tensor(obs, dtype=torch.float32)
acts_t = torch.tensor(acts); logp_old_t = torch.tensor(logp_old)
advs_t = torch.tensor(advs, dtype=torch.float32)
advs_t = (advs_t - advs_t.mean()) / (advs_t.std() + 1e-8)
rets_t = torch.tensor(rets, dtype=torch.float32)
for _ in range(K_epochs):
logits, v_pred = ac(obs_t)
dist = Categorical(logits=logits)
logp = dist.log_prob(acts_t)
ratio = torch.exp(logp - logp_old_t)
l_clip = torch.min(ratio * advs_t,
torch.clamp(ratio, 1-eps_clip, 1+eps_clip) * advs_t).mean()
l_v = ((v_pred - rets_t) ** 2).mean()
l_h = dist.entropy().mean()
loss = -l_clip + 0.5 * l_v - 0.01 * l_h
opt.zero_grad(); loss.backward(); opt.step()
if it % 20 == 0: print(it, sum(rews) / sum(dones) if sum(dones) else 0)

Cose da notare. Il segno meno davanti a lclipl_clip e lhl_h è perché PyTorch fa gradient descent; vogliamo gradient ascent su un objective che include LCLIPL^{\mathrm{CLIP}} e l’entropia. La normalizzazione dell’advantage (mean/std nel batch) è una di quelle “implementation details” che cambiano materialmente la performance. La GAE è calcolata in reverse pass per riusare δ\delta. Il KepochsK_epochs consente di riusare lo stesso rollout per più passi di gradiente — è on-policy approssimato, e funziona finché il ratio non si allontana troppo (qui sta il clip).

Esempio 3 — Scenario reale: il loop PPO di RLHF in InstructGPT

Sezione intitolata “Esempio 3 — Scenario reale: il loop PPO di RLHF in InstructGPT”

Pipeline a tre stadi (Ouyang 2022, sezione 3).

Stadio 1 — Supervised fine-tuning (SFT). Si parte da GPT-3, si fa fine-tuning su demos di prompt + risposta scritte da labeler. Output: πSFT\pi_{\mathrm{SFT}}. Questa diventerà πref\pi_{ref}.

Stadio 2 — Reward modeling. Per ogni prompt si campionano KK output da πSFT\pi_{\mathrm{SFT}}. I labeler li ordinano dal migliore al peggiore. Si addestra un reward model rϕ(x,y)r_\phi(x, y) via cross-entropy pairwise (Bradley-Terry): per ogni coppia (yw,yl)(y_w, y_l) con ywy_w preferito, logσ(rϕ(x,yw)rϕ(x,yl))\log \sigma(r_\phi(x,y_w) - r_\phi(x,y_l)). Output: un reward model frozen.

Stadio 3 — PPO. La policy πθ\pi_\theta inizializzata da πSFT\pi_{\mathrm{SFT}}, value head inizializzato da rϕr_\phi (warm start). Per ogni prompt xx campionato da una distribuzione di prompt:

  1. genera completion yπθ(x)y \sim \pi_\theta(\cdot|x);
  2. calcola rϕ(x,y)r_\phi(x, y) (reward terminale);
  3. calcola la KL token-wise contro πref\pi_{ref}: KLt=logπθ(ytx,y<t)logπref(ytx,y<t)\mathrm{KL}_t = \log \pi_\theta(y_t|x, y_{<t}) - \log \pi_{ref}(y_t|x, y_{<t});
  4. costruisce un reward per-token rt=βKLtr_t = -\beta \cdot \mathrm{KL}_t per t<yt < |y| e rT=rϕ(x,y)βKLTr_T = r_\phi(x,y) - \beta \cdot \mathrm{KL}_T all’ultimo token;
  5. stima A^t\hat A_t con GAE usando il critic;
  6. aggiorna θ\theta con LCLIPL^{\mathrm{CLIP}}, LVL^V, e (opzionale) un termine pretraining loss su un piccolo subset di dati pretraining (l’LM mixing di InstructGPT, mitigazione di “alignment tax” — il modello non deve dimenticare il pretraining).

β\beta tipico: 0.05–0.2. Troppo basso implica il policy collassa su risposte alto-reward sintetiche (reward hacking). Troppo alto implica il policy non si muove abbastanza dal SFT.

EQUIVALENZA ARGOMENTABILE (vista nel terzo angolo). Questo loop è policy gradient con reward modificato r=rϕβlog(πθ/πref)r' = r_\phi - \beta \log(\pi_\theta/\pi_{ref}). È PPO standard applicato a una policy LLM. La cosa interessante è che la struttura algoritmica non cambia rispetto a CartPole: cambia solo la scala (miliardi di parametri, sequenze di centinaia di token), e la natura del reward (non un punteggio di gioco ma un proxy di preferenza umana).

RLHF training loop architettura: blocchi "prompt x", "π_θ (trainable)", "π_ref (frozen, KL anchor)", "r_φ (frozen, reward model)", "PPO update"; frecce di flusso; label inglese: "rollout", "score", "KL", "advantage", "clipped update"

flowchart LR
    A[Pretrained LM<br/>es. GPT-3] --> B[Stage 1: SFT<br/>fine-tune su demo]
    B --> C[π_SFT = π_ref]
    C --> D[Stage 2: Reward Modeling<br/>train r_φ su preferenze pairwise]
    D --> E[r_φ frozen]
    C --> F[Stage 3: PPO<br/>π_θ inizializzata da π_SFT]
    E --> F
    C -.KL anchor.-> F
    F --> G[Modello allineato<br/>π_θ*]

Figura 5 — pipeline RLHF a tre stadi — pretrained LM, SFT su demo, Reward Modeling su preferenze pairwise, PPO con KL anchor verso π_SFT, fino al modello allineato

RLHF su LLM frontier (2022–2026). PPO è il workhorse standard di InstructGPT (OpenAI), GPT-4, Claude (Anthropic ha varianti proprie ma la struttura è simile, vedi Bai 2022 “Training a Helpful and Harmless Assistant”), Gemini (DeepMind), Llama 2/3 (Meta). Il pipeline tre-stadi (SFT → RM → PPO) è la spina dorsale. Variazioni: KL anchor adattivo, reward model ensembling per mitigare reward hacking, iterative DPO + PPO per re-train del reward model lungo il processo.

DPO e famiglia (2023–2025). Direct Preference Optimization (Rafailov 2023), Identity Preference Optimization (IPO), KTO (Kahneman-Tversky Optimization), ORPO (Odds Ratio Preference Optimization). Tutte alternative al PPO loop, più semplici da implementare e meno costose. Dominano i modelli open-weight (Llama 3, Mistral, Qwen) per il post-training preference alignment 2024–2026.

GRPO e reasoning RL. DeepSeekMath (2024), DeepSeek-R1 (2025) usano GRPO. La novità: niente value network, baseline = media del reward sul gruppo di rollout. Funziona bene quando si hanno reward verificabili (math, code, logica) — il modello produce KK catene di ragionamento, le si valuta, si fa policy gradient con baseline group-mean. È diventato il pattern standard per reasoning RL.

RLAIF e Constitutional AI (Bai 2022). Le preferenze pairwise, invece di venire da labeler umani, sono prodotte dal modello stesso guidato da una “costituzione” (un set di principi). Il PPO loop è identico; cambia la sorgente del segnale.

Agent fine-tuning (2024–2026). Agenti tool-use trained con PPO o GRPO su reward task-specifico. Esempi: SWE-bench (test passa / non passa), browser agent (task completato), math agent (risposta corretta). Un modello SFT su demos viene rifinito con RL su reward verificabile.

Robotica continuous control. SAC e PPO sono gli standard. SAC per la sua robustezza in off-policy (maximum entropy, replay buffer), PPO per la stabilità on-policy. Benchmarks: MuJoCo, Isaac Gym, Robosuite.

AlphaStar e OpenAI Five (DeepMind 2019, OpenAI 2018-2019). StarCraft II e Dota 2 multi-agent: scala industriale di policy gradient. OpenAI Five usa PPO scaled massicciamente (Rapid framework) con migliaia di rollout in parallelo; AlphaStar combina supervised pretraining su replay umani, self-play, e league training con popolazione di agenti. Sono i banchi di prova che hanno mostrato che PPO scala a problemi reali con orizzonti temporali di decine di migliaia di passi.

Recommendation systems con bandit feedback. In contextual bandit setting (un solo passo per episodio, reward immediato), REINFORCE si riduce a un caso particolare studiato in letteratura come “policy learning from logged bandit feedback” (Swaminathan-Joachims 2015). Si usa per ranking, content recommendation, ad serving, dove il segnale è click/no-click e si vuole ottimizzare la policy mantenendo low-variance importance sampling.

AlphaGo (DeepMind 2016). Il policy network di AlphaGo viene pre-addestrato con supervised learning su 30 milioni di posizioni di partite umane su KGS, poi rifinito con policy gradient (REINFORCE-style, con self-play e una baseline value network). Il value network e il policy network sono poi combinati con MCTS al momento del play. Vedi alphago-2016 (22).

Dialog systems pre-LLM. Prima di RLHF, policy gradient era già usato per task-oriented dialog (Williams 2007, Levin 2000), per ottimizzare la durata della conversazione o il task completion rate.

Più che altrove, qui è la sezione che separa chi ha letto il paper da chi ha implementato l’algoritmo.

Alta varianza di REINFORCE puro. Lo stimatore Jlogπ(a)G\nabla J \approx \nabla \log \pi(a) \cdot G ha varianza che cresce col numero di passi nella traiettoria e con la magnitudo del return. Una traiettoria sfortunata produce update di segno opposto al gradiente vero. Mitigazione: baseline Vϕ(s)V_\phi(s), advantage, GAE, batch grandi (migliaia di traiettorie), reward normalization, advantage normalization (mean/std nel batch). Empiricamente, la advantage normalization è una delle “implementation details” che cambiano materialmente la stabilità — vedi Engstrom 2020.

On-policy implica sample inefficiency. Ogni rollout è “consumato” e si butta dopo KK epoch di update (in PPO, K4K \approx 4). Non si possono riusare dati vecchi a meno di importance-sampling correction (che ha sua varianza esplosiva). Confronta con DQN, off-policy, che ricicla milioni di transizioni dal replay buffer. PPO rispetto a SAC è più stabile ma molto più sample-inefficient. Per LLM dove ogni rollout è lungo, costoso da generare e da scorare, la sample inefficiency si paga in dollari.

Entropy collapse. Se l’entropy bonus c2c_2 è troppo piccolo, la policy diventa troppo presto deterministica, smette di esplorare, si blocca su un ottimo locale. Se è troppo grande, la policy resta troppo random e non convergono. È un iperparametro fragile; in RLHF si usa più spesso la KL anchor contro πref\pi_{ref} come surrogato di entropy regularization.

PPO clipping è euristica. Non garantisce KL(πoldπθ)δ\mathrm{KL}(\pi_{old} \| \pi_\theta) \leq \delta, contrariamente a TRPO. Engstrom et al. (2020, “Implementation Matters in Deep Reinforcement Learning”) in un’analisi sistematica mostrano che molte performance attribuite al clip sono in realtà dovute a value clipping, learning rate annealing, advantage normalization, observation normalization. Take-away: ϵ\epsilon è iperparametro empirico, non principio.

TRPO costoso. Conjugate gradient su Fisher-vector products richiede O(P2)O(P^2) memoria nel peggior caso e backward multipli per iterazione. Per modelli con miliardi di parametri (LLM) impraticabile. PPO è il compromesso che sopravvive a quella scala.

Reward hacking in RLHF. Il policy trova modi di alzare il reward model senza migliorare la qualità reale. Esempi documentati: sycophancy (concordare sempre con l’utente, anche su errori), verbosità eccessiva, format-gaming (usare bullet point sempre perché il RM li preferisce), inserimento di disclaimer ridondanti. La causa è strutturale: il reward model è un proxy imperfetto delle preferenze umane, e ottimizzare un proxy abbastanza forte fa emergere ogni sua imperfezione. Mitigazioni: KL penalty contro πref\pi_{ref} (limita quanto lontano si può andare), ensembling di reward model, RLAIF + critique, eval out-of-distribution continui.

Mode collapse in RLHF. Con β\beta troppo basso o reward troppo aggressivo, πθ\pi_\theta collassa su poche risposte alto-reward, perde diversità. Sintomo: outputs ripetitivi, struttura sempre uguale. La KL penalty contro πref\pi_{ref} è lì proprio per questo.

Reward model out-of-distribution drift. Durante il PPO loop la policy si sposta; il RM è addestrato su completion del SFT, e man mano che la policy si allontana il RM produce predizioni sempre meno affidabili. Mitigazioni: iterative reward model retraining (raccogliere nuove preferenze su completion della policy aggiornata), KL anchor stretto.

Goodhart’s law. “Quando una misura diventa un obiettivo, smette di essere una buona misura”. La preferenza umana è già un proxy della “qualità” che vorremmo, il reward model è un proxy della preferenza umana, il policy gradient ottimizza il reward model. Doppio proxy, doppio rischio. Inevitabile in RLHF, si combatte con eval continui non basati sul RM.

LLM RLHF instabile e costoso. Il loop PPO per LLM richiede mantenere quattro copie dei pesi in memoria: πθ\pi_\theta (trainable), πref\pi_{ref} (frozen), rϕr_\phi (frozen, ma può essere su un altro device), value network (trainable). Più rollout, più scoring, più training. Un round di PPO su un modello 7B richiede ore su un cluster. È la motivazione esplicita di Rafailov 2023 per DPO: “PPO è instabile e costoso, possiamo fare meglio?”. DPO bypassa il rollout, usa solo backprop su preferenze pairwise statiche, ed è essenzialmente un supervised loss. Trade-off: meno espressivo (non può adattarsi a reward dinamici), ma molto più semplice.

Importance sampling off-policy esplode. Se si vuole riusare rollout vecchi (true off-policy), occorre correggere via importance sampling con πold/πθ\pi_{old}/\pi_\theta. La varianza di questo prodotto cresce esponenzialmente con la lunghezza della traiettoria, rendendo lo stimatore inutile per traiettorie lunghe. È il motivo per cui PPO si limita a KK epoch sulla stessa rollout, e SAC usa trucchi di reparametrizzazione invece di score function gradient.

Numerical issues su sequenze lunghe. Per LLM con sequenze lunghe (4k+ token), tlogπθ(yt...)\sum_t \log \pi_\theta(y_t|...) può accumulare valori grandi, e exp(logplogpold)exp(logp - logp_old) può overfloware. Standard fix: gradient clipping (1\|\nabla\| \leq 1), advantage normalization, mixed precision con loss scaling, KL stop-early se la KL del batch supera una soglia (es. 0.02).

Credit assignment per reward terminali. Nel RLHF il reward arriva alla fine della completion. Il GAE distribuisce credit ai token intermedi via VϕV_\phi, ma se VϕV_\phi è inaccurata (specialmente all’inizio dell’addestramento) il credit è rumoroso. Token assignment problem amplificato in agent fine-tuning con reward task-completion.

Discount factor accoppiato a credit assignment. La derivazione formale del Policy Gradient Theorem in setting discounted introduce un fattore γt\gamma^t davanti al gradiente al passo tt, che molte implementazioni standard omettono. Thomas (2014, “Bias in Natural Actor-Critic Algorithms”) osserva che questa omissione introduce un bias formalmente non zero, ma in pratica l’omissione è universale e non danneggia. È una di quelle cose che si scoprono leggendo il codice di cleanrl e poi cercando il paper che giustifica la differenza fra teoria e pratica.

Action space continuo e reparametrization vs score function. Per azioni continue con policy gaussiana πθ(as)=N(μθ(s),σθ(s))\pi_\theta(a|s) = \mathcal{N}(\mu_\theta(s), \sigma_\theta(s)), lo score function gradient funziona, ma esiste un’alternativa a varianza minore: il reparametrization trick (Kingma 2013 nel contesto VAE). Si scrive a=μθ(s)+σθ(s)ϵa = \mu_\theta(s) + \sigma_\theta(s) \cdot \epsilon con ϵN(0,I)\epsilon \sim \mathcal{N}(0, I), e si fa backprop attraverso aa. Funziona per Q-funzioni differenziabili e azioni continue (DDPG, SAC), non per setting con reward black-box o azioni discrete.

Hyperparameter sensitivity. PPO è notoriamente sensibile a ϵ\epsilon, λ\lambda, learning rate, batch size, KepochsK_{\mathrm{epochs}}, c1c_1, c2c_2, gradient clip. Il “default funziona” che si trova nei codebase stable-baselines3 o cleanrl è il risultato di anni di tuning empirico. Trasferire PPO da un dominio (CartPole) a un altro (MuJoCo, Atari, LLM) richiede re-tuning. È parte del costo nascosto di “PPO funziona”.

flowchart LR
    A[Pretrained LM<br/>es. GPT-3] --> B[Stage 1: SFT<br/>fine-tune su demo]
    B --> C[π_SFT = π_ref]
    C --> D[Stage 2: Reward Modeling<br/>train r_φ su preferenze pairwise]
    D --> E[r_φ frozen]
    C --> F[Stage 3: PPO<br/>π_θ inizializzata da π_SFT]
    E --> F
    C -.KL anchor.-> F
    F --> G[Modello allineato<br/>π_θ*]

Figura 5 — REINFORCE high variance vs baseline reduction: due distribuzioni di stimatore di gradiente sovrapposte, una larga senza baseline, una stretta con baseline V; label inglese “without baseline”, “with V baseline”, “gradient estimate”

  • probabilita-base (103) per il concetto di aspettazione e di varianza dello stimatore.
  • entropia-cross-entropy (105) per la KL divergence usata come anchor in RLHF, e per l’entropy bonus in PPO.
  • gradienti-intuito (106) per cosa significa “gradiente in spazio dei parametri” e perché il preconditioner in NPG ha senso.
  • discesa-gradiente (107) per Adam, learning rate, gradient clipping — la macchina che gira sotto.
  • softmax-sigmoid (108) per la parametrizzazione standard delle policy discrete e per la derivata θlogπ\nabla_\theta \log \pi in forma chiusa.
  • bias-varianza (111) per l’idea generale di trade-off, applicata qui al λ del GAE.
  • markov-decision-process (122) per il framework di base.
  • equazione-bellman (123) per il significato di VπV^\pi e QπQ^\pi usati come baseline e critic.
  • value-iteration-policy-iteration (124) per il contrasto: VI/PI sono value-based; qui si fa policy-based.
  • q-learning (125) per il fratello off-policy value-based; la policy esce da argmaxQ\arg\max Q invece di essere parametrizzata.
  • actor-critic (in preparazione) per l’unione esplicita actor + critic e A2C/A3C.
  • ppo-trpo (in preparazione) per il dettaglio dei due algoritmi e le loro prove di convergenza.
  • rlhf-ppo (in preparazione, Parte XI) per il pipeline RLHF completo applicato a LLM.
  • dpo-family (in preparazione, Parte XI) per DPO, IPO, KTO come alternative al PPO loop.
  • alphago-2016 (22) per l’uso storico di REINFORCE-style policy gradient nel self-play di AlphaGo.

Una piccola lista di “implementation details” che spesso fanno la differenza fra un codice che impara e uno che diverge. Catturate sintetizzando Engstrom 2020, Andrychowicz 2021 (“What Matters in On-Policy RL”), e i log degli autori di cleanrl.

  • Advantage normalization per batch: A^(A^μ)/(σ+108)\hat A \leftarrow (\hat A - \mu)/(\sigma + 10^{-8}). Quasi sempre attiva.
  • Reward scaling / clipping: ridurre la magnitudo del reward o clipparlo a [10,10][-10, 10] stabilizza specie in Atari.
  • Value function clipping: applicare un clip simile a quello del policy ratio anche al value loss, per evitare che il critic faccia salti grandi.
  • Orthogonal initialization delle feature layers (gain 2\sqrt{2}) e small-gain init dell’output policy head (gain 0.010.01) per partire con policy quasi uniforme.
  • Linear learning rate decay dall’inizio alla fine del training.
  • Gradient clipping 0.5\|\nabla\| \leq 0.5 globale.
  • KL early stopping per epoch: se la KL del batch supera una soglia (es. 1.5target_KL1.5 \cdot \mathrm{target\_KL}), interrompi gli epoch su quel rollout.
  • Observation normalization con running mean/std, soprattutto per stati continui.
  • Tanh activations spesso migliori di ReLU per policy heads; meno esplosioni di logit.

Per LLM RLHF aggiungi: mixed precision (bf16) per ridurre memoria, gradient checkpointing sui forward del modello, LoRA sul policy per ridurre i parametri trainable, token-level KL invece di sequence-level per credit assignment più fine.

  • Sutton, R.S.; Barto, A.G. Reinforcement Learning: An Introduction (2nd ed., MIT Press 2018), capitolo 13 “Policy Gradient Methods”. Esposizione canonica didattica, con derivazioni accessibili e riferimenti alla letteratura primaria.
  • Schulman, J. et al. “Proximal Policy Optimization Algorithms” (arXiv:1707.06347, 2017). Il paper di PPO. Da leggere insieme al precedente “Trust Region Policy Optimization” (2015) per capire la motivazione.
  • Achiam, J. Spinning Up in Deep Reinforcement Learning (OpenAI, 2018-, spinningup.openai.com). Implementazioni pulite di VPG, TRPO, PPO, DDPG, TD3, SAC con derivazioni leggibili e codice annotato. Migliore risorsa pratica.
  • Ouyang, L. et al. “Training language models to follow instructions with human feedback” (arXiv:2203.02155, 2022). InstructGPT. Da leggere come case study di RLHF applicato.
  • Rafailov, R. et al. “Direct Preference Optimization: Your Language Model is Secretly a Reward Model” (arXiv:2305.18290, 2023). Per capire l’alternativa al PPO loop e le sue ipotesi.