Oltre il Next-Token Prediction: Come RLVR e GRPO Insegnano il Ragionamento Logico agli LLM

Nel ciclo di vita di un Large Language Model (LLM), il pretraining rappresenta solo il primo passo. Durante questa fase iniziale, il modello apprende unicamente a prevedere il token successivo all’interno di un testo, basandosi sulla distribuzione di probabilità calcolata su un corpus di dati gigantesco. Questo processo fornisce al modello una straordinaria conoscenza enciclopedica e una forte comprensione linguistica, ma non lo rende intrinsecamente utile, sicuro o focalizzato.

Per trasformare un modello statistico in un assistente affidabile, è necessario guidarlo verso comportamenti specifici. Il modello deve imparare a rispondere in modo educato, a evitare argomenti sensibili o pericolosi e a essere fattualmente corretto. Tra questi comportamenti desiderati, uno dei più cruciali per espandere le capacità cognitive dell’intelligenza artificiale è l’adozione della Chain of Thought (CoT), ovvero la capacità di scomporre un problema complesso in passaggi logici intermedi prima di fornire la risposta finale.

Per stimolare e consolidare questa abilità di ragionamento, i ricercatori utilizzano tecniche avanzate basate sull’apprendimento per rinforzo. Tra le metodologie più innovative ed efficienti emerse recentemente spiccano RLVR e GRPO.


Gli Acronimi del Ragionamento: RLVR e GRPO

  • RLVR sta per Reinforcement Learning from Verifiable Rewards(Apprendimento per Rinforzo da Ricompense Verificabili).
  • GRPO sta per Group Relative Policy Optimization(Ottimizzazione della Politica Relativa di Gruppo).

Queste tecniche intervengono per ottimizzare il comportamento del modello spingendolo a “pensare” prima di rispondere. Ma come funzionano esattamente sotto il cofano, e qual è la sfida ingegneristica associata?


La Gestione dell’Underflow Numerico: Il Ruolo della Log-Probability

Quando un LLM genera una sequenza di testo, produce una serie di risposte alternative. Per ciascuna di esse viene calcolata la probabilità complessiva della sequenza. Tuttavia, operare direttamente con le probabilità pure comporta un grave problema ingegneristico: il rischio di underflow numerico (sottoflusso).

La probabilità di una frase è il prodotto delle probabilità dei singoli token che la compongono. Poiché ogni token ha una probabilità compresa tra 0 e 1, moltiplicare continuamente migliaia di valori decimali piccoli (0.qualcosa) porta il risultato finale a tendere rapidamente verso lo zero assoluto, superando il limite di precisione della memoria del computer (floating-point).

Per risolvere questo problema, gli algoritmi di ottimizzazione non utilizzano la probabilità diretta, ma la log-probability (logp). Sfruttando la proprietà fondamentale dei logaritmi, l’operazione di moltiplicazione tra probabilità si trasforma in una somma di logaritmi:

(log(P(A)timesP(B))=log(P(A))+log(P(B))(log (P(A)times P(B))=log (P(A))+log (P(B))

Questo accorgimento matematico stabilizza il calcolo numerico e consente di alimentare in modo efficiente la funzione di loss (funzione di perdita) durante l’addestramento. La funzione di loss confronta la logp della risposta generata con i feedback ricevuti, aggiornando i pesi del modello per penalizzare i percorsi logici errati e premiare quelli corretti.


Il Flusso Algoritmico e il grafo Computazionale

Per comprendere come un LLM aggiorni i suoi pesi tramite l’apprendimento per rinforzo basato su gruppi o confronti (la logica alla base di GRPO e RLVR), possiamo isolare cinque macro-fasi essenziali che avvengono a ogni iterazione di addestramento:

  1. Generazione dei Logits e Log-Probability: Il modello riceve un prompt e genera diverse varianti di risposta. L’output nativo della rete è composto dai logits (punteggi grezzi). Per evitare l’underflow, lo strato algoritmico successivo applica direttamente la funzione LogSoftmax per ottenere le logp delle sequenze, saltando il calcolo delle probabilità pure.
  2. Assegnazione del Reward: Un modulo di validazione esterno esamina le risposte e assegna a ciascuna un punteggio numerico (reward).
  3. Calcolo dei Vantaggi Relativi (Normalizzazione): Per capire quali risposte siano andate meglio della media del gruppo, si calcola il vantaggio. Si sottrae la media dei reward dal reward della singola frase e si divide per la deviazione standard del gruppo. Viene aggiunto un valore piccolissimo epsilon al denominatore per evitare la divisione per zero nel caso in cui tutte le risposte abbiano ottenuto lo stesso punteggio.
  4. Calcolo della Loss con Grafico Computazionale: La funzione di perdita moltiplica la logp di ciascuna frase per il rispettivo vantaggio normalizzato. In questa fase, PyTorch non calcola un semplice numero isolato, ma mappa l’intera catena di operazioni in un grafo Computazionale (Computational Graph). Questo albero genealogico matematico tiene traccia esatta di quali coefficienti e pesi della rete neurale hanno contribuito a generare quelle specifiche risposte.
  5. Backpropagation e Aggiustamento dei Pesi: Chiamando il metodo di retropropagazione, il framework ripercorre il grafico computazionale a ritroso. Calcola i gradienti e aggiorna i pesi del modello: le risposte con vantaggio positivo vedranno la loro probabilità aumentare, mentre quelle con vantaggio negativo verranno penalizzate.

L’Implementazione Pratica in Python e PyTorch

Di seguito viene proposto un esempio di codice lineare e riproducibile (grazie al seed bloccato) che simula l’intero ciclo di ottimizzazione:

Nota concettuale: a differenza dell’apprendimento supervisionato dove la loss calcola la differenza con una risposta ideale, nel Reinforcement Learning la loss moltiplica la probabilità per il vantaggio. La ‘differenza’ è già racchiusa nel vantaggio stesso, che misura lo scarto tra il reward ottenuto e la media del gruppo.”

python

import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F

# Per garantire che l'output sia esattamente riproducibile ad ogni esecuzione
torch.manual_seed(42)

# 1. Definiamo un modello ultra-semplificato per scopi illustrativi
# Rappresenta l'architettura logica di un LLM che genera punteggi di testo
class MiniLLM(nn.Module):
    def __init__(self):
        super().__init__()
        # Strato lineare che simula la generazione dei logits per 4 varianti di testo
        self.backbone = nn.Linear(10, 4) 
        
    def forward(self, prompts):
        # Il modello restituisce i LOGITS grezzi (numeri da -inf a +inf)
        return self.backbone(prompts)

# Inizializziamo il modello e l'ottimizzatore
model = MiniLLM()
optimizer = optim.Adam(model.parameters(), lr=0.01)

# Input di esempio: 1 prompt tradotto in embedding vettoriale
prompt_simulato = torch.randn(1, 10)

# --- INIZIO DEL CICLO DI ADDESTRAMENTO ---
optimizer.zero_grad()

# Fase 1: Il modello genera i logits grezzi per le 4 risposte del gruppo
logits = model(prompt_simulato).squeeze(0) 

# Uno strato algoritmico calcola le log-probabilities direttamente dai logits
log_probs = F.log_softmax(logits, dim=-1)

# Fase 2: Assegnazione dei reward da parte di un validatore esterno

# ! Importante: qui ci sara la vera magia: 
# il validatore esterno (funzione che confronta il risultato predetto con quello atteso) 
# che ha le risposte deterministiche valide, 
# assegnerà lo score di utilita da cui deriverà la funzione di loss

# Supponiamo che la seconda e la terza risposta siano corrette (reward alto) e le altre errate
rewards = torch.tensor([0.1, 0.9, 0.8, 0.2])

# Fase 3: Calcolo dei vantaggi normalizzati del gruppo (Media e Deviazione Standard)
epsilon = 1e-8
mean_reward = rewards.mean()  # Media: 0.5000
std_reward = rewards.std()    # Deviazione Standard: 0.4082

# Formula del vantaggio relativo: (reward_i - media) / (std + epsilon)
advantages = (rewards - mean_reward) / (std_reward + epsilon)

print("--- OUTPUT DELLE FASI DI PREPARAZIONE ---")
print(f"Logits grezzi sputati dal modello:       {logits.tolist()}")
print(f"Log-probabilities (logp) calcolate:     {log_probs.tolist()}")
print(f"Rewards assegnati dal validatore:        {rewards.tolist()}")
print(f"Vantaggi relativi normalizzati:          {advantages.tolist()}\n")

# Fase 4: Calcolo della Loss (Policy Gradient) ancorata al grafo Computazionale
# Il segno meno serve perché PyTorch minimizza la loss per ottimizzare i pesi
loss = - (log_probs * advantages).mean()

print("--- OUTPUT DELL'OTTIMIZZAZIONE ---")
print(f"Loss calcolata nel grafico computazionale: {loss.item():.4f}")

# Fase 5: Backpropagation e aggiustamento dei pesi
loss.backward()      # PyTorch ripercorre il grafico e calcola i gradienti per ogni coefficiente
optimizer.step()     # L'ottimizzatore corregge i pesi del modello

print("Pesi del modello aggiornati con successo tramite backpropagation.")

L’Output atteso in Console

Eseguendo lo script, la console mostrerà esattamente la seguente progressione numerica:

text

--- OUTPUT DELLE FASI DI PREPARAZIONE ---

Logits grezzi sputati dal modello:       [-0.34400516748428345, 0.17064374685287476, -0.16010531783103943, -0.4284898340702057]

Log-probabilities (logp) calcolate:     [-1.4939, -0.9792, -1.3100, -1.5784]

Rewards assegnati dal validatore:        [0.10000000149011612, 0.8999999761581421, 0.800000011920929, 0.20000000298023224]

Vantaggi relativi normalizzati:          [-0.9797958731651306, 0.9797958731651306, 0.7348469495773315, -0.7348469495773315]

--- OUTPUT DELL'OTTIMIZZAZIONE ---

Loss calcolata nel grafico computazionale: -0.1558

Pesi del modello aggiornati con successo tramite backpropagation.

L’Efficacia nei Domini Verificabili: Matematica e Programmazione

L’apprendimento per rinforzo applicato al ragionamento mostra la sua massima efficacia in ambiti logico-formali, come la matematica e la programmazione informatica. Il motivo è semplice: in questi contesti il risultato è oggettivamente verificabile. Un codice o compila ed esegue i test unitari correttamente, o fallisce; un’equazione matematica o porta al risultato corretto, o è sbagliata.

Questa binarietà permette al sistema di assegnare ricompense (rewards) precise e prive di ambiguità, accelerando l’ottimizzazione del modello rispetto a domini più fluidi e soggettivi come la scrittura creativa o l’opinione filosofica.

Come evidenziato dall’esperto Sebastian Raschka nel suo libro “Reasoning Models from Scratch”, l’apprendimento per rinforzo non viene usato semplicemente per premiare la risposta esatta in sé, ma per ricompensare i modelli che dimostrano un chiaro e soliso processo di ragionamento passo dopo passo. Per supportare questo processo, i dataset di addestramento mostrano una quantità massiccia di esempi strutturati in cui le risposte descrivono dettagliatamente ogni singolo passaggio logico intermediario.


Un’Evoluzione Possibile per la Stabilità: La Divergenza di Kullback-Leibler (KL)

Mentre il meccanismo appena descritto è incredibilmente potente per spingere il modello verso le risposte corrette, nasconde una seria insidia: il rischio di collasso della policy o reward hacking. Se premiamo ciecamente e unicamente il modello per i suoi ragionamenti corretti, questo potrebbe iniziare a modificare i propri pesi in modo drastico. Nel tentativo di massimizzare il reward, l’LLM rischia di dimenticare come si parla correttamente o di perdere la fluidità linguistica acquisita durante il pretraining, generando risposte ripetitive, sconnesse o prive di senso.

Per evitare questa deriva, gli algoritmi avanzati introducono una miglioria teorica fondamentale: una penalità basata sulla Divergenza di Kullback-Leibler (KL).

La divergenza di KL è una misura matematica che quantifica quanto una distribuzione di probabilità si allontani da un’altra. Nel contesto del Reinforcement Learning per gli LLM, durante l’addestramento si mantengono in memoria due versioni del modello:

  1. Il modello attivo, che stiamo addestrando e modificando.
  2. Il modello di riferimento originario (immutato, ereditato dalle fasi precedenti).

A ogni iterazione, la funzione di loss non guarda solo al vantaggio calcolato con i reward, ma calcola anche la divergenza di KL tra i token prodotti dal modello attivo e quelli che avrebbe prodotto il modello originale sul medesimo prompt. Se il modello attivo si allontana troppo dal modo di esprimersi del modello di riferimento originario, scatta una penalità nella loss.

In parole semplici, la divergenza di KL funge da “ancora di sicurezza” o “guinzaglio invisibile”: costringe l’LLM a ottimizzare le sue capacità di ragionamento matematico e logico, ma ponendo come vincolo invalicabile il mantenimento delle eccezionali doti linguistiche e della stabilità espressiva di partenza.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *