Salta ai contenuti

Actor-critic e A2C/A3C: chi agisce e chi giudica

Q-learning ha solo un critic e fabbrica la policy come arg-max. REINFORCE ha solo un actor e paga in varianza. L’idea di tenerli entrambi — l’actor che decide, il critic che stima quanto vale lo stato — risale al 1983, sopravvive a quarant’anni di reinforcement learning, e oggi è l’architettura standard di ogni fine-tune con feedback umano: PPO di InstructGPT, ChatGPT, Claude, Gemini è actor-critic.

Il capitolo precedente ha fissato il policy gradient: si parametrizza la policy πθ(as)\pi_\theta(a|s) e si fa gradient ascent sull’objective J(θ)=Eτπθ[R(τ)]J(\theta) = \mathbb{E}_{\tau \sim \pi_\theta}[R(\tau)]. Il problema operativo emerso era la varianza dello stimatore: il return R(τ)R(\tau) di una singola traiettoria è un’osservazione rumorosissima del valore atteso, e il gradiente che ne deriva oscilla violentemente. Il rimedio standard, anticipato in 126, è sottrarre una baseline b(st)b(s_t) alla return, ottenendo un advantage At=Rtb(st)A_t = R_t - b(s_t) a varianza ridotta senza introdurre bias. La domanda lasciata aperta era: quale baseline?

Se la baseline è Vπ(st)V^\pi(s_t) — il valore atteso dello stato sotto la policy corrente — allora At=RtVπ(st)A_t = R_t - V^\pi(s_t) è esattamente l’advantage in senso strretto: quanto questa azione ha fatto meglio di quanto mi aspettassi in media da questo stato. Ma VπV^\pi non si conosce a priori: va stimato. Se lo si stima parametricamente, in parallelo all’actor, da una rete VϕV_\phi addestrata su target TD, si ha l’architettura actor-critic. L’actor sceglie l’azione, il critic giudica lo stato, l’advantage misura la sorpresa positiva o negativa.

Tre motivi per cui conta. Il primo è di filiazione: la catena Andrew Barto-Richard Sutton-Charles Anderson 1983 → REINFORCE-with-baseline 1992 → Konda-Tsitsiklis 2003 → A3C 2016 → PPO 2017 → InstructGPT 2022 → GRPO 2024 è una storia continua di quarant’anni in cui le stesse due reti si specializzano, si fondono, si separano. Il secondo è operativo: ogni algoritmo di deep reinforcement learning visto in produzione fra 2016 e 2026 — A3C, A2C, ACER, ACKTR, DDPG, TD3, SAC, IMPALA, PPO, GRPO — è una variazione sul tema actor-critic. Capire l’architettura una volta basta a leggere ottanta percento della letteratura. Il terzo è il punto di contatto con i large language model: la pipeline RLHF di Ouyang e colleghi 2022, che ha prodotto InstructGPT e poi ChatGPT, è actor-critic con shared backbone (il transformer pre-trained), policy head (i logits sul vocabolario) e value head (un nuovo proiettore scalare aggiunto sopra). Capire actor-critic è capire il fine-tuning con feedback.

La promessa esecutiva: alla fine si saprà derivare A2C dal policy gradient con baseline, leggere il loop RLHF separando reward, advantage, KL penalty, scrivere un actor-critic minimal in PyTorch, e capire perché DDPG fa overshoot, perché SAC è stabile, perché GRPO si chiede se il critic serva davvero per LLM.

Il grafo concettuale ha quattro radici e un punto di confluenza moderno.

Cybernetica del controllo adattivo, anni ‘70. Ian H. Witten (informatico britannico/neozelandese, allora Edinburgh, oggi noto per data mining), in “An adaptive optimal controller for discrete-time Markov environments” (Information and Control, 1977), descrive uno schema di controllo adattivo a due moduli: uno stimatore del valore e un selettore di azione. È un proto-actor-critic ante litteram, in epoca pre-RL, dentro la tradizione del controllo ottimo stocastico.

ACE/ASE su cart-pole, 1983. Andrew Barto (informatico statunitense, University of Massachusetts Amherst, padre del moderno RL con Sutton), Richard Sutton (allora suo dottorando, oggi University of Alberta e DeepMind), Charles Anderson (allora dottorando UMass) pubblicano in “Neuronlike adaptive elements that can solve difficult learning control problems” (IEEE Transactions on Systems, Man, and Cybernetics SMC-13, 1983) l’architettura ACE/ASE. ACE (Adaptive Critic Element) è una rete che impara una stima del valore dello stato via temporal-difference learning. ASE (Associative Search Element) è una policy stocastica che perturba l’azione e ne aumenta la probabilità in proporzione al “reinforcement signal” prodotto da ACE. Il task è bilanciare un’asta sopra un carrello su rotaie. È letteralmente actor-critic moderno in forma proto-tipica, e nella prosa del paper compaiono già il termine “critic” e l’idea che il critic produca un “internal reinforcement signal” che disaccoppia l’actor dal reward esterno sparso.

Score function e baseline. Ronald Williams in REINFORCE 1992 (visto in 126) include esplicitamente la possibilità di una baseline b(s)b(s) sottratta dal return per ridurre la varianza dello stimatore. Quando si sceglie b(s)=Vπ(s)b(s) = V^\pi(s) stimato da una rete separata, si ha la versione più semplice di actor-critic. La differenza con un actor-critic “pieno” è che VV qui non è bootstrappato (TD), ma stimato come Monte Carlo dalle return: niente backup di Bellman, niente vantaggio di varianza dal bootstrap.

Two-timescale stochastic approximation. Vijay Konda (allora MIT operations research, oggi industria) e John Tsitsiklis (operations researcher MIT, una delle voci storiche di stochastic approximation) in “Actor-Critic Algorithms” (NIPS 1999, versione completa SIAM Journal on Control and Optimization, 2003) producono il primo risultato di convergenza per actor-critic con function approximation lineare. La struttura della prova è due-timescale: il critic si aggiorna su scala temporale veloce (impara VπV^\pi velocemente per la π\pi corrente), l’actor si aggiorna su scala lenta (vede un critic quasi-converged). TEOREMA: sotto compatibilità del feature space del critic (il critic deve poter rappresentare ogni VπθV^{\pi_\theta} ammissibile) e step-size αtactor/αtcritic0\alpha_t^{actor} / \alpha_t^{critic} \to 0, l’actor converge a un punto stazionario di J(θ)J(\theta). È il risultato fondante.

Salto deep, 2016. Volodymyr Mnih (informatico DeepMind, primo autore di DQN) e colleghi pubblicano “Asynchronous Methods for Deep Reinforcement Learning” (ICML 2016). L’algoritmo principale è A3C (Asynchronous Advantage Actor-Critic): NN worker processi mantengono ciascuno una copia del modello globale, esplorano l’ambiente in parallelo su CPU, calcolano gradienti su rollout n-step e li applicano in modo asincrono al modello globale con la tecnica Hogwill (lock-free update). Niente replay buffer, niente target network: la diversità delle traiettorie viene dalla parallel exploration. Performance Atari paragonabile a DQN, su CPU, in metà del tempo. Mnih nello stesso paper introduce anche A2C, la versione sincrona, per ablation. OpenAI baseline (2017) mostrerà che su GPU A2C eguaglia A3C: l’asincronia non è essenziale, è la parallelizzazione. EQUIVALENZA argomentabile sotto ipotesi (GPU, batched forward economico): A2C \equiv A3C senza asincronia.

Continuous control deep. Timothy Lillicrap (DeepMind, neuroscienziato di formazione) e colleghi nel 2015, in “Continuous control with deep reinforcement learning” (ICLR 2016), introducono DDPG (Deep Deterministic Policy Gradient). Idea: per azioni continue, parametrizza la policy come funzione deterministica μθ(s)a\mu_\theta(s) \to a (no Gaussian sampling, niente softmax); il critic è Qϕ(s,a)Q_\phi(s, a); il gradiente actor passa per la regola di catena θμθaQϕ(s,a)a=μθ(s)\nabla_\theta \mu_\theta \cdot \nabla_a Q_\phi(s, a)|_{a = \mu_\theta(s)}. Si appoggia al teorema DPG (Deterministic Policy Gradient) di David Silver (DeepMind, principale di AlphaGo) e colleghi del 2014. DDPG eredita target network e replay buffer da DQN, è la prima soluzione deep credibile per MuJoCo continuous. Ma è notoriamente fragile: hyperparameter sensitive, overestimation di QQ, divergenze occasionali.

Twin critic e TD3. Scott Fujimoto (allora McGill, oggi Mila), Herke van Hoof, David Meger nel 2018, in “Addressing Function Approximation Error in Actor-Critic Methods” (ICML 2018), pubblicano TD3 (Twin Delayed DDPG). Tre fix sistematici dei bug DDPG: (1) twin critic — addestra due reti Qϕ1,Qϕ2Q_{\phi_1}, Q_{\phi_2}, usa min(Qϕ1,Qϕ2)\min(Q_{\phi_1}, Q_{\phi_2}) come target per evitare overestimation bias; (2) delayed policy update — l’actor si aggiorna ogni dd critic step (default d=2d=2), così l’actor vede critic più stabile; (3) target policy smoothing — aggiunge clipped Gaussian noise alle target action, smussando la stima Bellman ed evitando sharp peaks artificiosi.

Maximum entropy. Tuomas Haarnoja (allora Berkeley, oggi DeepMind) e colleghi nel 2018, in “Soft Actor-Critic: Off-Policy Maximum Entropy Deep Reinforcement Learning with a Stochastic Actor” (ICML 2018), introducono SAC. L’objective non è E[R]\mathbb{E}[R] ma E[trt+αH(π(st))]\mathbb{E}\big[\sum_t r_t + \alpha \cdot \mathcal{H}(\pi(\cdot|s_t))\big]: massimizza il return e l’entropia della policy. Risultato: policy stocastica con entropia naturale, esplorazione robusta, twin Q critic. Una versione successiva (Haarnoja et al. 2018b) auto-tuna la temperatura α\alpha via Lagrangiano. SAC diventa lo standard in robotica per stabilità.

Distribuito. Lasse Espeholt (DeepMind) e colleghi nel 2018 in “IMPALA: Scalable Distributed Deep-RL with Importance Weighted Actor-Learner Architectures” (ICML 2018) costruiscono un’architettura a learner centrale + actor remoti che producono traiettorie. Le traiettorie arrivano leggermente off-policy (delay tra collect e use sul learner). V-trace è la correzione importance-sampling truncated che gestisce il gap, con clipping che limita la varianza. Permette scaling a centinaia di worker, base per gli esperimenti di scala DeepMind tipo AlphaStar.

Innesto LLM, 2022. Long Ouyang (OpenAI) e colleghi in “Training language models to follow instructions with human feedback” (NeurIPS 2022) descrivono il pipeline che porta InstructGPT e quindi ChatGPT. Tre fasi: SFT, reward model, PPO. La terza fase è actor-critic: il modello SFT è il backbone shared; sopra ci sono due head, l’LM head (riusato dal pretraining, è l’actor) e una value head freshly init (il critic). Reward esterno dal reward model congelato, KL penalty contro reference SFT. Vedi chatgpt-2022 per la cornice storica e instruction-rlhf-era per l’adozione standard.

Anti-pattern, 2024. Zhihong Shao e DeepSeek-AI in “DeepSeekMath” (arXiv:2402.03300) introducono GRPO (Group Relative Policy Optimization). Per ogni prompt, campionano KK completion (es. K=64K=64). La baseline diventa la media empirica delle reward sul gruppo. Niente value head, niente critic parametrico. Costo memoria 1-1 modello, performance comparabile o superiore in setting LLM. Il critic, in RLHF su LLM con gruppi grandi, sembra ridondante. Ne riparliamo in “Dove si rompe”.

Una nota di differenziazione rispetto ai capitoli precedenti per evitare doppioni. In 122 si è dato l’MDP, in 123 Bellman, in 124 VI/PI con modello, in 125 Q-learning ha rimosso il modello e ha imparato QQ^*, in 126 si è separato la policy come oggetto autonomo da ottimizzare via gradient ascent. Qui — capitolo 127 — si uniscono i due paradigmi: l’actor ottimizza direttamente πθ\pi_\theta, il critic stima VπV^\pi o QπQ^\pi, l’advantage A=GVA = G - V è il glue. Non è un capitolo “in più”: è il punto in cui l’algoritmo standard di tutto il deep RL moderno prende forma.

diagramma di filiazione storica: ACE/ASE 1983, REINFORCE+baseline 1992, Konda-Tsitsiklis 2003, A3C 2016, DDPG 2015, TD3 2018, SAC 2018, IMPALA 2018, PPO/InstructGPT 2017-2022, GRPO 2024 — con frecce di derivazione e cluster colorati per famiglia (on-policy stocastico, off-policy deterministico, max-entropy, LLM-RLHF)

Tre angoli prima del formalismo. I primi due sono didattici e diversi nel modo in cui inquadrano l’idea; il terzo è la lettura moderna in chiave LLM.

Angolo 1 — L’attore e il critico (analogia teatrale)

Sezione intitolata “Angolo 1 — L’attore e il critico (analogia teatrale)”

ANALOGIA, didattica e non causale. Pensa a un giovane attore che recita su un palcoscenico. Sceglie il tono, il gesto, la pausa. Dopo ogni scena, un critico in platea — non il pubblico, un critico di mestiere — gli dice quanto è stato buono. Non gli dice cosa fare, gli dà solo un giudizio numerico: “questa scena vale 7, quella 3”. L’attore non riparte da zero ogni sera: aggiusta i gesti spingendoli verso i pattern che il critico ha valutato meglio della media.

Due cose vanno notate. La prima: il critico non sostituisce il pubblico vero (il reward dell’ambiente). Il critico è un’approssimazione interna, addestrata su quello che il pubblico ha detto in passato. La seconda: l’attore si aggiusta in base a quanto il critico è stato sorpreso, non in base al voto assoluto. Se il critico si aspettava 5 e ha visto 7, è un’azione da rinforzare; se si aspettava 8 e ha visto 7, è un’azione da scoraggiare. Questo “scarto” è esattamente l’advantage A=RVA = R - V. È quanto tu hai fatto meglio di quanto un osservatore informato si aspettasse. Marca la classe: ANALOGIA. Il critico non è un agente intenzionale, l’attore non capisce le sue motivazioni. La somiglianza è cognitiva, didattica.

Angolo 2 — Bootstrapping per ridurre la varianza

Sezione intitolata “Angolo 2 — Bootstrapping per ridurre la varianza”

In REINFORCE puro, l’aggiornamento dei parametri della policy ha la forma θθ+αθlogπθ(atst)Gt\theta \leftarrow \theta + \alpha \cdot \nabla_\theta \log \pi_\theta(a_t|s_t) \cdot G_t, dove Gt=k=0γkrt+kG_t = \sum_{k=0}^\infty \gamma^k r_{t+k} è il return Monte Carlo. Il problema, già discusso in 126, è che GtG_t è un’osservazione rumorosa del valore atteso E[Gtst,at]\mathbb{E}[G_t | s_t, a_t]. Una traiettoria fortunata produce GtG_t alto; una sfortunata, basso. Se la varianza di GtG_t è alta (e su orizzonti lunghi cresce con tt), il gradiente oscilla.

C’è un secondo problema, già visto in 125: il return Monte Carlo richiede di aspettare la fine dell’episodio per essere calcolato. Su episodi lunghi (un agent LLM con 100 turni di tool use, una partita di Go con 300 mosse) significa update infrequenti.

Il critic risolve entrambi. Una rete Vϕ(s)V_\phi(s) stima il valore atteso dello stato. Si possono allora costruire stime ibride del return:

  • 1-step bootstrap: G^t=rt+γVϕ(st+1)\hat G_t = r_t + \gamma V_\phi(s_{t+1})
  • n-step bootstrap: G^t=k=0n1γkrt+k+γnVϕ(st+n)\hat G_t = \sum_{k=0}^{n-1} \gamma^k r_{t+k} + \gamma^n V_\phi(s_{t+n})
  • Generalized Advantage Estimator (GAE): media esponenziale di tutti gli n-step estimator

Le stime bootstrap hanno bias (perché VϕV_\phi è imperfetto) ma varianza più bassa (perché un solo rtr_t è meno rumoroso di una somma di rewards stocastici). Il bilanciamento bias-varianza, vecchia conoscenza dalla statistica (vedi bias-varianza (111)), torna qui in chiave operativa: nn piccolo o λ\lambda piccolo (in GAE) significano alto bias e bassa varianza; nn grande o λ1\lambda \to 1 significano basso bias e alta varianza.

Actor-critic è la macchina che permette di scegliere il punto giusto su questa curva.

curva bias-varianza dell'advantage estimator parametrizzata da \lambda in GAE: asse x lambda da 0 a 1, asse y MSE dello stimatore decomposto in bias^2 e varianza, con il minimo MSE a un valore intermedio dipendente dalla qualità del critic

Angolo 3 — Il twin head di un LLM è un actor-critic

Sezione intitolata “Angolo 3 — Il twin head di un LLM è un actor-critic”

L’angolo moderno, tagliato per il lettore che ha già visto un transformer. Un large language model post-trained come InstructGPT, ChatGPT, Claude è, dal punto di vista dell’architettura RLHF, un actor-critic con backbone condiviso. Il transformer (decoder-only, NN layer) trasforma token in stati nascosti hth_t. Sopra l’ultimo layer ci sono due proiezioni:

  • LM head: htWLMhtlogits su vocabh_t \to W_{LM} h_t \to \text{logits su vocab}. È l’actor, πθ(atst=(prompt,y<t))\pi_\theta(a_t | s_t = (\text{prompt}, y_{<t})). Riusa la matrice di unembedding del pretraining (often tied con embedding matrix).
  • Value head: htWVhtRh_t \to W_V h_t \to \mathbb{R}. È il critic, Vϕ(st)V_\phi(s_t). Linear layer freshly initialized aggiunto per RLHF.

Durante PPO, ad ogni rollout la value head produce una stima Vϕ(st)V_\phi(s_t) per ogni token-stato. Il reward viene dal reward model esterno (un’altra rete, congelata) sull’intera completion. GAE combina rewards e VV per ottenere advantage. Loss totale: clipped surrogate per l’actor, MSE per il critic, KL contro la reference policy come regularizer.

EQUIVALENZA argomentabile, sotto ipotesi: questa pipeline è actor-critic standard con reward shaping (il termine KL è un reward shaping additivo βlog(πθ/πref)-\beta \log(\pi_\theta / \pi_{ref})). Vale come equivalenza nel caso di reward terminale o token-decomposto coerentemente. Marca la classe: equivalenza, non identità formale generale.

Tre angoli, una sola macchina.

MDP S,A,P,r,γ\langle \mathcal{S}, \mathcal{A}, P, r, \gamma \rangle, traiettorie τ=(s0,a0,r0,s1,)\tau = (s_0, a_0, r_0, s_1, \dots). Policy parametrizzata πθ(as)\pi_\theta(a|s). Value function parametrizzata Vϕ(s)V_\phi(s). Due reti, opzionalmente con backbone condiviso.

Si vuole che Vϕ(s)V_\phi(s) stimi Vπθ(s)V^{\pi_\theta}(s). Si usa un target TD costruito dai rollout:

Vttarget=k=0n1γkrt+k+γnVϕ(st+n).V^{target}_t = \sum_{k=0}^{n-1} \gamma^k r_{t+k} + \gamma^n V_\phi(s_{t+n}).

Loss del critic:

Lcritic(ϕ)=1BtB(VttargetVϕ(st))2.\mathcal{L}_{critic}(\phi) = \frac{1}{|B|} \sum_{t \in B} \big( V^{target}_t - V_\phi(s_t) \big)^2.

Update: ϕϕηϕϕLcritic\phi \leftarrow \phi - \eta_\phi \nabla_\phi \mathcal{L}_{critic}. Il target VttargetV^{target}_t va detach-ato (no gradiente verso il target), tipicamente con target network o con stop-gradient.

L’advantage stimato è A^t=VttargetVϕ(st)\hat A_t = V^{target}_t - V_\phi(s_t) nella forma n-step. La forma GAE (Schulman 2016, ICLR) introduce un parametro λ[0,1]\lambda \in [0,1]:

δt=rt+γVϕ(st+1)Vϕ(st),\delta_t = r_t + \gamma V_\phi(s_{t+1}) - V_\phi(s_t), A^tGAE(γ,λ)=l=0(γλ)lδt+l.\hat A_t^{GAE(\gamma, \lambda)} = \sum_{l=0}^{\infty} (\gamma \lambda)^l \delta_{t+l}.

Con λ=0\lambda = 0: A^t=δt\hat A_t = \delta_t, TD(0), bias alto, varianza bassa. Con λ=1\lambda = 1: A^t=GtVϕ(st)\hat A_t = G_t - V_\phi(s_t), Monte Carlo, bias zero, varianza alta. In pratica λ[0.9,0.99]\lambda \in [0.9, 0.99].

Loss policy gradient con baseline:

Lactor(θ)=1BtBlogπθ(atst)A^t,\mathcal{L}_{actor}(\theta) = - \frac{1}{|B|} \sum_{t \in B} \log \pi_\theta(a_t | s_t) \cdot \hat A_t,

con A^t\hat A_t detached (no gradiente verso ϕ\phi via A^\hat A). Con entropy bonus per esplorazione:

Ltotal=Lactor+c1Lcriticc2H(πθ(st)).\mathcal{L}_{total} = \mathcal{L}_{actor} + c_1 \mathcal{L}_{critic} - c_2 \cdot \overline{\mathcal{H}(\pi_\theta(\cdot|s_t))}.

Coefficienti tipici c1=0.5c_1 = 0.5, c2=0.01c_2 = 0.01.

inizializza pi_theta, V_phi
ripeti:
raccogli rollout di T step da N worker paralleli
per ogni rollout:
calcola V_phi(s_t) per ogni t in [0, T-1]
calcola V_phi(s_T) per il bootstrap finale
per t da T-1 a 0:
delta_t = r_t + gamma * V_phi(s_{t+1}) - V_phi(s_t)
A_t = delta_t + gamma * lambda * A_{t+1}
V_target_t = A_t + V_phi(s_t)
L_critic = mean((V_target_t - V_phi(s_t))^2)
L_actor = - mean(log pi_theta(a_t|s_t) * A_t.detach())
L_entropy = mean(entropy(pi_theta(.|s_t)))
L_total = L_actor + 0.5 * L_critic - 0.01 * L_entropy
grad step su L_total

Ogni linea ha un ruolo. La double-recursion da T1T-1 a 0 è il modo efficiente di computare GAE in tempo lineare nella lunghezza del rollout. Il detach() su AtA_t nella loss dell’actor è critico: senza, il gradiente fluirebbe nel critic via l’advantage, accoppiando i due update e rompendo la separazione concettuale.

flowchart LR
    A[N worker paralleli] -->|rollout T step| B[Traiettorie: s,a,r,s']
    B --> C[Calcola V_phi su tutti gli stati]
    C --> D[Calcola advantage GAE A_t]
    D --> E[Actor loss: -log pi · A.detach]
    D --> F[Critic loss: MSE V vs V_target]
    E --> G[Loss totale + entropy bonus]
    F --> G
    G --> H[Backprop, optimizer step]
    H -->|aggiorna parametri| A

Figura 5 — pipeline di training A2C dai rollout paralleli alla backprop, con i contributi di actor loss, critic loss ed entropy bonus

Per azioni continue, la policy è una funzione deterministica μθ(s)aRd\mu_\theta(s) \to a \in \mathbb{R}^d. Il critic stima Qϕ(s,a)Q_\phi(s, a) (azione come input, non solo stato). La radice formale è il teorema DPG (Silver 2014):

θJ(θ)=Esρμ[θμθ(s)aQμ(s,a)a=μθ(s)].\nabla_\theta J(\theta) = \mathbb{E}_{s \sim \rho^\mu}\big[\nabla_\theta \mu_\theta(s) \cdot \nabla_a Q^\mu(s, a)|_{a = \mu_\theta(s)}\big].

In pratica: backprop attraverso QϕQ_\phi valutato in μθ(s)\mu_\theta(s), fai gradient ascent su θ\theta. Il critic si addestra come in DQN con target r+γQϕ(s,μθ(s))r + \gamma Q_{\phi'}(s', \mu_{\theta'}(s')) usando target network slow-moving.

Objective:

J(π)=E[trt+αH(π(st))].J(\pi) = \mathbb{E}\bigg[\sum_t r_t + \alpha \cdot \mathcal{H}(\pi(\cdot|s_t))\bigg].

Policy stocastica Gaussiana con reparametrization trick: a=μθ(s)+σθ(s)ϵa = \mu_\theta(s) + \sigma_\theta(s) \cdot \epsilon, ϵN(0,I)\epsilon \sim \mathcal{N}(0, I). Twin Q critic Qϕ1,Qϕ2Q_{\phi_1}, Q_{\phi_2} per overestimation. La temperatura α\alpha è auto-tunata via Lagrangiano per soddisfare un’entropia target Hˉ\bar{\mathcal{H}}.

Tre fix sintetici:

  1. Twin critic, target r+γmin(Qϕ1(s,a~),Qϕ2(s,a~))r + \gamma \min(Q_{\phi'_1}(s', \tilde a'), Q_{\phi'_2}(s', \tilde a')).
  2. Actor update ogni d=2d=2 critic update.
  3. Target action smoothed: a~=μθ(s)+clip(N(0,σ),c,c)\tilde a' = \mu_{\theta'}(s') + \text{clip}(\mathcal{N}(0, \sigma), -c, c).

Cambia poco di codice, fixa molto di stabilità.

Per LLM PPO (Ouyang 2022), il loop per ogni step:

batch di prompt x_i (i=1..B)
per ogni prompt x_i:
rollout y_i ~ pi_theta(.|x_i), token by token
per ogni token t in y_i:
s_t = (x_i, y_i_<t)
log_prob_old_t = log pi_theta_old(y_i_t | s_t) # frozen snapshot
V_phi_t = value_head(backbone(s_t))
kl_t = log pi_theta(y_i_t|s_t) - log pi_ref(y_i_t|s_t)
r_terminal_i = reward_model(x_i, y_i)
# reward shaping: KL penalty per token
r_t = -beta * kl_t per t < T_i
r_{T_i} += r_terminal_i
# GAE
delta_t = r_t + gamma * V_{t+1} - V_t
A_t = delta_t + (gamma * lambda) * A_{t+1}
per K epoch:
per minibatch in batch:
ratio_t = exp(log pi_theta(a_t|s_t) - log_prob_old_t)
L_clip = min(ratio_t * A_t, clip(ratio_t, 1-eps, 1+eps) * A_t)
L_actor = - mean(L_clip)
L_critic = mean((V_target_t - V_phi(s_t))^2)
L = L_actor + 0.5 * L_critic
backward, optimizer step

Quattro modelli vivono in memoria simultaneamente: πθ\pi_\theta (training), πref\pi_{ref} (frozen, per KL), rψr_\psi (frozen, reward model), VϕV_\phi (trainable, critic). Su LLM da decine di miliardi di parametri il costo è dominante. Da qui la pressione a semplificare: DPO elimina il rollout PPO; GRPO elimina il critic.

pipeline RLHF actor-critic: backbone transformer condiviso, LM head come actor, value head come critic, reward model esterno congelato, KL contro reference, frecce di gradient flow

Tre angoli eterogenei: numerico a mano, codice eseguibile, scenario reale di scala produttiva.

Esempio 1 — Actor-critic numerico su 3-state MDP

Sezione intitolata “Esempio 1 — Actor-critic numerico su 3-state MDP”

Stati {s0,s1,s2}\{s_0, s_1, s_2\} con s2s_2 terminale. Azioni {a,b}\{a, b\} in s0,s1s_0, s_1. Transizioni deterministiche (per semplicità):

  • s0as1s_0 \xrightarrow{a} s_1, reward r=1r = 1
  • s0bs2s_0 \xrightarrow{b} s_2, reward r=0r = 0
  • s1as2s_1 \xrightarrow{a} s_2, reward r=2r = 2
  • s1bs2s_1 \xrightarrow{b} s_2, reward r=1r = -1

Discount γ=0.9\gamma = 0.9. Una traiettoria osservata sotto la policy corrente: s0as1as2s_0 \to a \to s_1 \to a \to s_2, rewards (1,2,0)(1, 2, 0).

Return Monte Carlo:

G0=1+0.92+0.810=2.8,G1=2+0.90=2.0.G_0 = 1 + 0.9 \cdot 2 + 0.81 \cdot 0 = 2.8, \quad G_1 = 2 + 0.9 \cdot 0 = 2.0.

Critic corrente (supponiamo iniziale): Vϕ(s0)=1.0V_\phi(s_0) = 1.0, Vϕ(s1)=1.5V_\phi(s_1) = 1.5, Vϕ(s2)=0V_\phi(s_2) = 0.

Advantage Monte Carlo:

A^0=G0Vϕ(s0)=2.81.0=1.8,\hat A_0 = G_0 - V_\phi(s_0) = 2.8 - 1.0 = 1.8, A^1=G1Vϕ(s1)=2.01.5=0.5.\hat A_1 = G_1 - V_\phi(s_1) = 2.0 - 1.5 = 0.5.

Advantage TD(0):

δ0=r0+γVϕ(s1)Vϕ(s0)=1+0.91.51.0=1.35,\delta_0 = r_0 + \gamma V_\phi(s_1) - V_\phi(s_0) = 1 + 0.9 \cdot 1.5 - 1.0 = 1.35, δ1=r1+γVϕ(s2)Vϕ(s1)=2+01.5=0.5.\delta_1 = r_1 + \gamma V_\phi(s_2) - V_\phi(s_1) = 2 + 0 - 1.5 = 0.5.

Advantage GAE con λ=0.9\lambda = 0.9 (calcolato all’indietro):

A^1GAE=δ1=0.5,\hat A_1^{GAE} = \delta_1 = 0.5, A^0GAE=δ0+γλA^1GAE=1.35+0.810.5=1.755.\hat A_0^{GAE} = \delta_0 + \gamma \lambda \hat A_1^{GAE} = 1.35 + 0.81 \cdot 0.5 = 1.755.

Si noti come l’advantage GAE per s0s_0 (1.755) sia tra il TD(0) (1.35) e il Monte Carlo (1.8): è esattamente lo scopo del parametro λ\lambda.

Update:

  • Actor: spinge logπθ(as0)\log \pi_\theta(a|s_0) verso l’alto con peso A^0GAE=1.755\hat A_0^{GAE} = 1.755 e logπθ(as1)\log \pi_\theta(a|s_1) con peso 0.50.5.
  • Critic: Vϕ(s0)Vϕ(s0)+η(V0targetVϕ(s0))V_\phi(s_0) \leftarrow V_\phi(s_0) + \eta \cdot (V^{target}_0 - V_\phi(s_0)) con V0target=A^0GAE+Vϕ(s0)=2.755V^{target}_0 = \hat A_0^{GAE} + V_\phi(s_0) = 2.755. Idem per s1s_1.

Una traiettoria, tre numeri, un’iterazione. Su scala è quello che gira nei rollout di A2C, PPO, RLHF.

Un’implementazione minimale leggibile in un colpo. CartPole-v1 (Gym/Gymnasium): bilanciare un’asta su un carrello, stato 4D continuo, azione 2 discrete (sinistra, destra), reward +1+1 per ogni passo, episodio max 500 step.

import torch
import torch.nn as nn
import torch.nn.functional as F
import gymnasium as gym
class ActorCritic(nn.Module):
def __init__(self, obs_dim, act_dim, hidden=128):
super().__init__()
self.backbone = nn.Sequential(
nn.Linear(obs_dim, hidden), nn.Tanh(),
nn.Linear(hidden, hidden), nn.Tanh(),
)
self.actor_head = nn.Linear(hidden, act_dim)
self.value_head = nn.Linear(hidden, 1)
def forward(self, s):
h = self.backbone(s)
return self.actor_head(h), self.value_head(h).squeeze(-1)
def compute_gae(rewards, values, dones, last_value, gamma=0.99, lam=0.95):
advantages = torch.zeros_like(rewards)
last_adv = 0.0
for t in reversed(range(len(rewards))):
next_value = last_value if t == len(rewards) - 1 else values[t + 1]
non_terminal = 1.0 - dones[t]
delta = rewards[t] + gamma * next_value * non_terminal - values[t]
last_adv = delta + gamma * lam * non_terminal * last_adv
advantages[t] = last_adv
returns = advantages + values
return advantages, returns
env = gym.make("CartPole-v1")
net = ActorCritic(4, 2)
opt = torch.optim.Adam(net.parameters(), lr=3e-4)
T = 128 # rollout length
for update in range(2000):
obs_buf, act_buf, rew_buf, done_buf, val_buf, logp_buf = [], [], [], [], [], []
s, _ = env.reset()
for t in range(T):
s_t = torch.tensor(s, dtype=torch.float32)
logits, v = net(s_t)
dist = torch.distributions.Categorical(logits=logits)
a = dist.sample()
s2, r, term, trunc, _ = env.step(a.item())
obs_buf.append(s_t); act_buf.append(a); rew_buf.append(r)
done_buf.append(float(term or trunc)); val_buf.append(v); logp_buf.append(dist.log_prob(a))
s = s2 if not (term or trunc) else env.reset()[0]
rewards = torch.tensor(rew_buf, dtype=torch.float32)
dones = torch.tensor(done_buf, dtype=torch.float32)
values = torch.stack(val_buf)
logps = torch.stack(logp_buf)
with torch.no_grad():
last_v = net(torch.tensor(s, dtype=torch.float32))[1]
adv, ret = compute_gae(rewards, values.detach(), dones, last_v)
adv = (adv - adv.mean()) / (adv.std() + 1e-8)
L_actor = -(logps * adv).mean()
L_critic = F.mse_loss(values, ret)
entropy = -(F.softmax(net(torch.stack(obs_buf))[0], dim=-1) *
F.log_softmax(net(torch.stack(obs_buf))[0], dim=-1)).sum(-1).mean()
loss = L_actor + 0.5 * L_critic - 0.01 * entropy
opt.zero_grad(); loss.backward(); opt.step()

Convergenza tipica: dopo 200\sim 200 update il reward medio per episodio raggiunge il massimo (500). Note didattiche: il values.detach() nel calcolo dell’advantage scollega l’actor dal gradient flow del critic; la normalizzazione di adv (mean 0, std 1) è un trucco standard per stabilità che non cambia la direzione del gradiente, riduce solo la scala. L’entropy bonus mantiene la policy stocastica nelle prime fasi.

Esempio 3 — RLHF di InstructGPT come actor-critic

Sezione intitolata “Esempio 3 — RLHF di InstructGPT come actor-critic”

Ouyang 2022 cap. 3.5: “We use the value function from the RM as our value function VV, but we found that value function tracking the reward model leads to instabilities, so we use a separate value function”. Traduzione: il critic in RLHF è una rete separata, freshly initialized, non è il reward model.

Numeri (paper):

  • Modello base: GPT-3 175B (anche varianti 1.3B, 6B).
  • Reward model: 6\sim 6B parameter, addestrato su 33k preferenze pairwise, loss Bradley-Terry.
  • Value head: linear layer aggiunto sopra il transformer trainable, freshly init.
  • PPO: 4 epoch per batch, batch size 512 prompt, GAE λ=0.95\lambda = 0.95, γ=1.0\gamma = 1.0 (no discount, episodi corti).
  • KL coefficient β\beta inizializzato a 0.02, target KL adaptive 6\sim 6 nat.
  • Rollout length: completion intera, fino a 256 token.

Risultato: il modello PPO 1.3B (InstructGPT-1.3B) è preferito da labeler umani al modello GPT-3 plain 175B (zero-shot) il 70% delle volte. È la dimostrazione che alignment via actor-critic batte scaling brutale per task instruction-following.

Sono i numeri di scala. La macchina algoritmica è la stessa di CartPole.

flowchart LR
    A[N worker paralleli] -->|rollout T step| B[Traiettorie: s,a,r,s']
    B --> C[Calcola V_phi su tutti gli stati]
    C --> D[Calcola advantage GAE A_t]
    D --> E[Actor loss: -log pi · A.detach]
    D --> F[Critic loss: MSE V vs V_target]
    E --> G[Loss totale + entropy bonus]
    F --> G
    G --> H[Backprop, optimizer step]
    H -->|aggiorna parametri| A

Figura 5 — schermata stilizzata di rollout PPO su un singolo prompt: token generati, V(st)V(s_t) per ogni stato, reward scalare alla fine, KL token-by-token, advantage GAE che combina tutto

RLHF in produzione. Tutte le pipeline di fine-tuning con feedback umano in scala — InstructGPT, ChatGPT, GPT-4, Claude originale (Anthropic 2022-2023), Gemini (Google DeepMind 2023+), Llama 2 chat (Meta 2023) — usano una qualche forma di PPO actor-critic. Differenze stanno nel reward model (single vs ensemble vs constitutional), nel KL schedule, nel numero di epoch, nel reward shaping. La struttura backbone + LM head + value head è invariante. Vedi instruction-rlhf-era.

Reasoning RL post-2024. Modelli “thinking” come o1 (OpenAI 2024), o3 (2025), DeepSeek-R1 (2025), Claude reasoning sono fine-tuned con RL su reasoning traces. DeepSeek-R1 in particolare usa GRPO (Shao 2024), una variante actor-critic-senza-critic. La ragione per cui GRPO funziona è discussa in “Dove si rompe”.

Robotica continuous control. SAC è lo standard per real-robot RL: bracci robotici (Berkeley/Google), locomotion (legged robots, ETH Zurich), manipulation. Robust to hyperparameter, off-policy efficient. DDPG/TD3 sopravvivono in domini specifici. Vedi i lavori di Sergey Levine (Berkeley) e Marc Toussaint per overview.

Game playing distribuito. AlphaGo (vedi alphago-2016) e AlphaZero usano una rete a due head — policy head + value head — sopra un backbone CNN/ResNet. La policy guida il MCTS, il value valuta i nodi terminali della search. Architetturalmente è actor-critic con shared backbone, anche se l’algoritmo di training è diverso (self-play + supervised su MCTS visit counts e rollout outcomes, non TD policy gradient). EQUIVALENZA argomentabile sotto ipotesi: l’objective di AlphaZero è una forma di policy iteration generalizzata in cui il MCTS è il “critic” amplificato. AlphaStar (StarCraft II), OpenAI Five (Dota 2) usano IMPALA-style distributed actor-critic per training su scala.

Fine-tuning di agent per tool use. Lavori recenti (Trial-and-Error, ReST-MCTS, agentic RL) applicano actor-critic a LLM-agent che fanno tool use multi-turn. Il critic stima il valore di uno stato s=(conversation history,tool outputs fin qui)s = (\text{conversation history}, \text{tool outputs fin qui}); l’actor produce la prossima azione (token o tool call). Le sfide sono Markov assumption, lunghezza dello stato, sparse reward (success/failure a fine episodio). Vedi era-agenti-2024 per il contesto.

RLAIF e Constitutional AI. Anthropic ha proposto Constitutional AI (Bai et al. 2022) come variante in cui il reward model è addestrato non su preferenze umane dirette ma su preferenze AI guidate da una “costituzione” testuale. La fase RL è ancora actor-critic con PPO o equivalente; cambia l’origine del segnale di reward. Variante: RLAIF (RL from AI Feedback), che sostituisce parzialmente o totalmente l’umano nel loop di preferenze.

Sezione ampia, perché actor-critic è diventato lo standard ma ha modi specifici di fallire che vanno conosciuti.

Se VϕV_\phi è mal addestrato — perché il backbone è freshly init, perché i target TD sono rumorosi, perché il learning rate del critic è troppo basso — l’advantage A^t=GtVϕ(st)\hat A_t = G_t - V_\phi(s_t) è una stima distorta. L’actor riceve gradiente con direzione sbagliata. Su rollout iniziali RLHF è il sintomo classico: la value head freshly init produce V0V \approx 0 ovunque, l’advantage degenera a GtG_t puro (REINFORCE), si perde varianza ridotta. Mitigazione: warmup del critic con value-only update prima del primo actor step; clip dei target; usa target network con polyak averaging.

Su MDP con reward sparso (Montezuma’s Revenge, agent task con success terminale), la varianza del return rimane alta nonostante il critic. Se il critic non ha mai visto un reward positivo, la sua stima è V0V \approx 0 ovunque, e il primo segnale che arriva domina con varianza enorme. Actor-critic vanilla fallisce. Soluzioni: intrinsic motivation (curiosity-driven exploration, RND), hindsight experience replay (HER), curriculum learning. In RLHF di LLM lo sparse reward è terminale (il reward model produce uno scalare a fine completion), gestito grazie alle long completion e al token-level KL shaping che distribuisce un segnale denso lungo il rollout.

Tre bug noti, già menzionati. (1) Overestimation di QQ: il target r+γQϕ(s,μθ(s))r + \gamma Q_{\phi'}(s', \mu_{\theta'}(s')) tende a sovrastimare a causa del max implicito (in DDPG, sebbene la policy sia deterministica, l’overestimation sopravvive per il bias positivo dell’errore di approssimazione). (2) Co-update di actor e critic ogni step: gradient feedback loop instabile. (3) Sharp peaks artificiosi in QQ: la policy esploita pattern di noise nel critic. TD3 fixa tutto e tre, ed è la versione che si dovrebbe usare oggi al posto di DDPG plain.

Soft actor-critic ha un coefficiente α\alpha per l’entropia. Se fisso e troppo alto, la policy resta troppo random e non migliora; troppo basso, mode collapse, la policy diventa quasi deterministica e perde l’esplorazione. La versione con auto-tuning (Lagrangiano su entropia target Hˉ=dim(A)\bar{\mathcal{H}} = -\dim(\mathcal{A}) è scelta tipica) risolve in pratica, ma introduce un nuovo hyperparameter (Hˉ\bar{\mathcal{H}} stesso) e un’altra rete da training (non triviale).

Il reward model rψr_\psi è addestrato su preferenze pairwise generate da rollout SFT (la policy iniziale). Durante PPO la policy πθ\pi_\theta drift dalla SFT; le sue rollout escono dalla distribuzione di train del RM. Conseguenza: rψr_\psi produce valori unreliable, spesso troppo alti (Goodhart: il modello esplora regioni dove il RM ha estrapolazione spuria positiva). Sintomo classico: il reward sale ma la quality umana scende. Mitigazione: KL penalty contro πref\pi_{ref} limita drift; ensemble di RM con varianza-penalty; periodic refresh del RM con rollout della policy corrente etichettati.

Troppo alto: πθ\pi_\theta resta incollata a πref\pi_{ref}, niente apprendimento. Troppo basso: drift libero, reward hacking, mode collapse, output ripetitivi o degenerati. InstructGPT usa adaptive β\beta con target KL: misura KL^\hat{KL} a runtime, alza β\beta se KL^>2target\hat{KL} > 2 \cdot \text{target}, abbassa se <0.5target< 0.5 \cdot \text{target}. È una euristica, non una soluzione formale; la calibrazione resta arte.

Quando si fa RL off-policy con dataset fisso DD — niente nuova esplorazione — il critic viene interrogato su (s,a)(s, a) fuori dal supporto di DD. Per stati visti ma azioni mai visitate, Qϕ(s,a)Q_\phi(s, a) è estrapolazione, e l’errore compounding (Bellman backup itera l’errore) può divergere. CQL (Kumar 2020), BCQ, IQL nascono come fix: penalty su QQ fuori supporto, constraint sulla policy verso il supporto. È un tema attivo di ricerca, rilevante per RLHF offline (DPO è uno spostamento radicale verso questa direzione).

Shao 2024 (DeepSeek) propone GRPO: per ogni prompt xx, campiona KK completion (es. K=64K=64). Per ogni rollout yiy_i calcola ri=rψ(x,yi)r_i = r_\psi(x, y_i). La baseline è la media empirica rˉ=1Kri\bar r = \frac{1}{K} \sum r_i. L’advantage è A^i=rirˉ\hat A_i = r_i - \bar r (con std normalization). Niente value head, niente critic parametrico. Su DeepSeek-R1 GRPO eguaglia o supera PPO e libera memoria per modelli più grandi.

La domanda aperta: il critic, in RLHF di LLM con KK grandi, era ridondante? Una possibile lettura: con KK grande, la varianza di rˉ\bar r come stima di Vπθ(x)V^{\pi_\theta}(x) diventa abbastanza piccola da rendere il critic parametrico inutile; il costo memoria del critic non vale il guadagno di varianza. Per RL classico (singolo rollout per stato, esplorazione stato-action ampia), il critic resta indispensabile. EQUIVALENZA argomentabile sotto ipotesi: GRPO con KK \to \infty converge a actor-critic con critic perfetto. Marca la classe: equivalenza al limite, non identità.

Per un LLM-agent multi-turn (reasoning + tool use), lo “stato” è l’intera conversation history. Il critic dovrebbe stimare VV su un input variabile e cresente nel tempo. Tre problemi concreti: (1) la state space è effettivamente continuous infinite, VV è una mappa ΣR\Sigma^* \to \mathbb{R}; (2) la Markov assumption è ferocemente violata (ciò che è successo kk turni fa influenza ancora); (3) il backbone transformer ha context length finito, quindi state truncation introduce non-stationarity ulteriore. Soluzioni in produzione: state compression (summary memory), hierarchical actor-critic con high-level critic su goal e low-level critic su tool sub-action. Sono palliativi.

In MDP con reward solo a fine episodio (success/failure binario, reasoning task con check finale), il critic riceve target uguale al return della traiettoria intera; perde il vantaggio del bootstrap parziale. Si ricade efficacemente a REINFORCE-with-baseline. PRM (Process Reward Model) sono una risposta: si addestra un secondo reward model che valuta passi intermedi, distribuendo segnale lungo la traiettoria. Lavori OpenAI 2023-2024 e DeepMind su outcome vs process reward sono il riferimento.

Il teorema di convergenza di Konda-Tsitsiklis 2003 vale per FA lineare. Per FA non-lineare (rete neurale deep), non ci sono garanzie globali. Risultati locali (convergenza al “compatible function approximation” set, sotto ipotesi forti) esistono, ma in pratica la stabilità è empirica. Sintomo: training divergence rare ma reali; serve clip grad norm, learning rate schedule, eventualmente target network.

  • probabilita-base — distribuzioni, valore atteso, varianza: il linguaggio in cui sono scritti VπV^\pi, advantage e baseline.
  • entropia-cross-entropy — entropy bonus dell’actor e KL penalty in RLHF stanno qui, non sono accidenti notazionali.
  • gradienti-intuito — actor e critic sono entrambi addestrati con gradient descent, le intuizioni geometriche valgono per entrambi.
  • discesa-gradiente — Adam, momentum, learning rate schedule sono ingredienti operativi essenziali di ogni actor-critic.
  • bias-varianza — l’intero argomento del capitolo è una scelta di trade-off bias-varianza nello stimatore di advantage.
  • markov-decision-process — il framework formale.
  • equazione-bellman — il critic loss è MSE su un target che è una versione rilassata di Bellman.
  • value-iteration-policy-iteration — actor-critic è “policy iteration generalizzata”: l’actor migliora la policy, il critic valuta la policy corrente, in alternanza.
  • q-learning — Q-learning è il caso “solo critic”; DDPG/TD3/SAC adattano l’idea alla famiglia actor-critic.
  • policy-gradient — il fondamento immediato; tutto qui parte da REINFORCE-with-baseline.
  • ppo-trpo (in preparazione) — la versione clipped surrogate di actor-critic, standard in RLHF.
  • alphago-2016 — AlphaGo/AlphaZero come architettura twin-head antesignana di RLHF in domini di game playing.
  • chatgpt-2022 — la cornice storica del momento in cui RLHF actor-critic diventa pubblicamente noto.
  • instruction-rlhf-era — l’adozione standard del paradigma in tutti i frontier lab.
  • era-agenti-2024 — agent LLM come dominio dove actor-critic incontra Markov assumption violata.
  • Sutton & Barto, “Reinforcement Learning: An Introduction”, 2nd ed. (MIT Press, 2018), cap. 13.5–13.7. Trattazione pedagogica completa di REINFORCE-with-baseline → one-step actor-critic → eligibility traces → continuous actor-critic. Punto di partenza obbligato.
  • Achiam, “Spinning Up in Deep RL” (OpenAI, 2018, https://spinningup.openai.com). Implementazioni pulite di VPG, A2C, DDPG, TD3, SAC, PPO con teoria a fianco. Il riferimento operativo per chi vuole scrivere codice.
  • Schulman et al., “High-Dimensional Continuous Control Using Generalized Advantage Estimation” (ICLR 2016, arXiv:1506.02438). Il paper di GAE, da leggere per capire bias-varianza nel concreto.
  • Haarnoja et al., “Soft Actor-Critic Algorithms and Applications” (arXiv:1812.05905, 2018). Versione estesa di SAC con auto-tuning di α\alpha; è la versione che si usa in pratica.
  • Ouyang et al., “Training language models to follow instructions with human feedback” (NeurIPS 2022, arXiv:2203.02155). Per leggere RLHF actor-critic in scala produttiva, dal primo lavoro che lo ha reso standard.