Due documenti, due modi di decidere quanto contano
Un gruppo prepara documenti di dominio per adattare un modello AI. Alcuni sono brevi, altri molto lunghi. Se dichiariamo che ogni documento è ugualmente importante, basta mescolarli nello stesso batch e fare la media della loss? Non sempre: una media su tutte le posizioni supervisionate dà più peso ai documenti che ne contengono di più. La scelta del denominatore è parte dell’obiettivo di apprendimento, non un dettaglio cosmetico del programma.
La domanda è quale quantità stiamo mediando e come cambia il gradiente. Useremo due gruppi sintetici, con 2 e 8 posizioni valide, un modello binario con un unico parametro e un calcolo completo della cross-entropy, cioè entropia incrociata. Aggiungeremo poi posizioni di padding, inserite soltanto per allineare le lunghezze. Non addestriamo un modello linguistico: isoliamo con un modello controllabile un meccanismo che conta anche nell’adattamento di modelli verticali.
Che cosa misura una singola loss
Un token è un’unità della rappresentazione testuale; una posizione supervisionata è un punto in cui chiediamo una previsione e disponiamo di un bersaglio. Per questo esempio non servono parole reali o un particolare tokenizer. Ogni posizione ha etichetta y uguale a 0 oppure 1. Il modello assegna la stessa probabilità p alla classe 1 in tutte le posizioni. È volutamente semplice: non deve imparare il linguaggio, ma mostrarci l’effetto delle regole di aggregazione.
theta è il logit, un numero reale che il modello può modificare. Quando theta vale 0, p vale 0,5. Il logaritmo è naturale, quindi la loss si esprime in nat. Se y=1 penalizziamo una probabilità p piccola; se y=0 penalizziamo una probabilità 1−p piccola. La loss non è una percentuale di risposte corrette. Possiamo avere lo stesso valore numerico della loss e gradienti differenti quando cambiamo i pesi delle osservazioni.
La media globale sceglie implicitamente il peso dei documenti
Indichiamo con n_i il numero di posizioni valide del documento i e con L_i la media delle sue loss. La media per token somma tutte le loss e divide per il totale delle posizioni valide. La media per documento calcola prima ogni L_i e poi assegna lo stesso peso ai documenti. Nella prima, il coefficiente di L_i è proporzionale a n_i. Nella seconda, è lo stesso per tutti, purché ogni documento abbia almeno una posizione valida.
D è il numero di documenti. Con n_A=2 e n_B=8, la media per token è 0,2 L_A+0,8 L_B; quella per documento è 0,5 L_A+0,5 L_B. Il secondo documento pesa quattro volte il primo nel primo obiettivo, ma non nel secondo. Questo non rende automaticamente sbagliata la media per token: è coerente se vogliamo dare uguale importanza a ogni posizione. Diventa incoerente con l’intenzione dichiarata soltanto se vogliamo invece pesare ugualmente i documenti.
Il gradiente rende visibile la differenza
Ora assegniamo etichetta 1 a entrambe le posizioni del documento A ed etichetta 0 alle otto posizioni del documento B. Sono bersagli costruiti, non frequenze osservate in un corpus. Per capire come cambierà theta dobbiamo derivare la loss rispetto a quel parametro. La derivata della sigmoid è p(1−p); sostituendola nella derivata dei logaritmi, i termini si semplificano e rimane p−y. Il gradiente indica la direzione locale di aumento della loss.
Con theta=0 e p=0,5, il gradiente per token vale 0,3; quello per documento vale 0. Un passo di discesa sottrae al parametro il gradiente moltiplicato per un passo positivo: il primo criterio spinge theta verso valori negativi, il secondo è già in equilibrio. Le due loss iniziali valgono entrambe log 2, circa 0,693147 nat. Guardare soltanto quel numero non rivelerebbe che i due criteri stanno suggerendo aggiornamenti diversi.
Possiamo trovare anche gli ottimi. Poiché il gradiente è p meno la frazione pesata di etichette 1, si annulla a p=0,2 nel criterio per token e a p=0,5 in quello per documento. La derivata seconda è p(1−p), positiva per probabilità strettamente tra 0 e 1, quindi in questo modello scalare gli ottimi sono unici e finiti. Non abbiamo dimostrato che un grande modello linguistico abbia un paesaggio di loss convesso: la conclusione riguarda soltanto il modello dichiarato.
Il padding non è un nuovo esempio di classe zero
Per ottenere due righe di lunghezza 8 aggiungiamo sei posizioni artificiali ad A. Queste posizioni non hanno un bersaglio del compito: servono a organizzare i tensori. Se però le etichettiamo 0 e le includiamo nella loss come dati veri, il totale diventa 16 posizioni, soltanto 2 positive. L’ottimo passa a p=2/16=0,125. Non è cambiato il contenuto dei due documenti; abbiamo introdotto sei esempi inventati nella funzione obiettivo.
Una maschera m uguale a 1 nelle posizioni valide e 0 nel padding deve agire sia sul numeratore sia sul denominatore della media. Se aggiungiamo altri spazi artificiali con maschera 0, il valore della loss corretta e il suo gradiente rimangono invariati. Il programma verifica questa proprietà con 0,1,6 e 20 posizioni aggiunte e tre valori di theta. È una proprietà sui dati costruiti, non una misura di robustezza di un modello sul campo.
Un secondo errore elimina correttamente le loss del padding dal numeratore, ma continua a dividere per 16. Il risultato è 10/16 della loss corretta. A theta=0 scende da 0,693147 a 0,433217 senza che nessuna probabilità sia migliorata; il gradiente scende da 0,3 a 0,1875. L’ottimo scalare rimane p=0,2 perché abbiamo moltiplicato tutta la funzione per una costante positiva. Cambia però la scala del passo: un numero minore sul grafico non prova una previsione migliore.
Un terzo errore usa il valore 0 come sinonimo di padding e ignora tutte le etichette 0, comprese le otto supervisioni legittime del documento B. Rimangono soltanto due etichette 1: il gradiente iniziale diventa−0,5 e spinge p verso 1. In questo caso il minimo è un limite, raggiunto mentre theta cresce senza limite, non un ottimo finito. Bisogna distinguere il valore di una classe dal ruolo artificiale di una posizione: una maschera deve descrivere quel ruolo.
| Criterio | Loss a theta=0(nat) | Gradiente a theta=0 | p ottimo |
|---|---|---|---|
| Media per token | 0.693147 | 0.3000 | 0.200 |
| Media per documento | 0.693147 | 0.0000 | 0.500 |
| Padding incluso | 0.693147 | 0.3750 | 0.125 |
| Denominatore errato | 0.433217 | 0.1875 | 0.200 |
| Classe zero ignorata | 0.693147 | -0.5000 | 1(limite) |
I valori della tabella descrivono funzioni obiettivo diverse, non cinque addestramenti valutati sullo stesso test. La prima distinzione, token contro documento, è una scelta esplicita di pesatura. Le altre righe introducono errori rispetto alla definizione concordata di dati validi. Con un fattore di scala costante si potrebbe compensare il passo di ottimizzazione; se la quota di padding cambia tra batch, quel fattore varia e cambia anche il peso relativo dei contributi durante l’aggiornamento.

Dividere il batch non deve cambiare di nascosto l’obiettivo
Supponiamo di elaborare A e B in due microbatch, cioè due porzioni successive, per ridurre la memoria necessaria. A theta=0 i gradienti medi delle due porzioni sono−0,5 e+0,5. Farne la media semplice dà 0: abbiamo ricostruito il criterio per documento. Per riprodurre la media globale per token occorre pesare ciascun gradiente medio con il suo numero di posizioni valide. Otteniamo(2 ×−0,5+8 × 0,5)/10=0,3, lo stesso valore del batch intero.
B qui indica il numero di microbatch. Le due formule coincidono se le numerosità valide sono uguali, oppure in altri casi particolari in cui i contributi si compensano. Non basta che i tensori abbiano la stessa lunghezza dopo il padding. Questo è un controllo dell’algebra dell’accumulo, non la denuncia di un difetto in una particolare versione di Trainer o di un framework. Un’implementazione deve essere confrontata con il suo obiettivo dichiarato e con le regole di riduzione effettive.
Dalla formula alla libreria, senza confondere i livelli
La documentazione ufficiale PyTorch 2.14 di CrossEntropyLoss distingue bersagli come indici di classe e bersagli come distribuzioni di probabilità. Nel caso con indici, ignore_index esclude bersagli dalla loss e dal gradiente; senza pesi di classe, la media usa il numero dei bersagli non ignorati. Il nostro esempio considera proprio etichette discrete e nessun peso di classe. Non estendiamo quella formula senza modifiche a etichette probabilistiche o ad altre scelte di pesatura.
In un modello linguistico causale, le posizioni valide dipendono anche dall’allineamento tra ingresso e bersaglio successivo e dalla scelta di supervisionare prompt, risposte o entrambi. La lunghezza completa del documento non coincide necessariamente con n_i. Una maschera usata dall’attenzione e una usata dalla loss rispondono a domande diverse, anche quando un’implementazione le collega. Prima di applicare i conteggi bisogna definire quali previsioni contribuiscono realmente all’obiettivo, non soltanto contare i token presenti nel tensore.
Se non rimane nessuna posizione valida, la media ha denominatore zero e non è definita dalla nostra formula. Il programma segnala esplicitamente questa condizione; non restituisce zero fingendo una previsione perfetta. Anche un documento senza bersagli rende indefinita la sua media L_i: escluderlo o trattarlo in altro modo richiede una politica dichiarata. Non attribuiamo il comportamento del nostro codice a tutte le librerie, che possono gestire questi casi in modi diversi.
Come riprodurre il ragionamento senza addestrare un LLM
Il programma usa soltanto la libreria matematica di Python per la loss e per il gradiente analitico. Calcola i logaritmi mediante una forma numericamente stabile e salva i cinque criteri confrontati. Verifica l’invarianza al padding correttamente mascherato e confronta il gradiente con una differenza finita centrale a theta=0,3. L’errore nel controllo eseguito è circa 4,1 × 10⁻¹¹, sotto la tolleranza 1 × 10⁻⁸scelta per quel controllo: non è una prova di correttezza di un sistema di autodifferenziazione.
Nel frammento breve, lengths descrive quante posizioni contribuiscono e gradients contiene il contributo medio di ciascun documento. Le due ultime medie ricostruiscono i diversi obiettivi: non richiedono GPU, pesi di modelli o dati esterni. Il costo di una somma sulle posizioni è lineare nel numero di posizioni elaborate, ma questo conteggio non misura il costo dell’inferenza o del training. La parte onerosa di un modello reale non è simulata da questa operazione scalare.
Quale unità di importanza vogliamo ottimizzare?
La lunghezza cambia l’addestramento quando cambia il peso dei contributi nella funzione obiettivo. Dare lo stesso peso ai documenti richiede una media per documento o una pesatura equivalente; dare lo stesso peso alle posizioni richiede la media per token. Nessuna delle due è universalmente migliore. Padding e bersagli validi vanno però distinti in ogni scelta, e dividere i dati in microbatch non dovrebbe introdurre una nuova pesatura non dichiarata. I risultati del modello reale richiedono infine una valutazione indipendente, che questo esempio non sostituisce.
Fonte e materiali riproducibili
import math
p=0.5
lengths=[2,8]
labels=[1,0]
gradients=[p-y for y in labels]
token_gradient=sum(n*g for n,g in zip(lengths,gradients))/sum(lengths)
document_gradient=sum(gradients)/len(gradients)
assert abs(token_gradient-0.3)<1e-12
assert document_gradient==0
print(token_gradient,document_gradient)
Codice, dati e istruzioni · JSON. Calcoli didattici eseguiti con Python 3.14.0; figure con Matplotlib 3.11.2. Analisi con assistenza AI, senza dichiarare peer review o revisione umana. Copertina originale ImageGen, illustrativa: non documenta persone, sedi o installazioni EL-AI. Fonti consultate il 21 ottobre 2026.

