Molti utenti pensano che impostare la temperatura a zero sia una garanzia di coerenza. La verità è più sottile e, per chi lavora con modelli di grandi dimensioni, leggermente inquietante. Anche con gli stessi input e lo stesso seed, i transformer come quelli alla base di ChatGPT possono restituire risposte diverse. Non si tratta di magia, né di un capriccio dell’intelligenza artificiale. Il colpevole è la fisica del calcolo parallelo e l’aritmetica floating-point non associativa.
Nei processori moderni, le operazioni sono suddivise tra centinaia o migliaia di thread. Ogni thread lavora su una porzione di dati e alla fine i risultati vengono ridotti in una somma finale. Qui entra in gioco la non associatività dei numeri in virgola mobile: cambiare l’ordine delle somme produce piccole differenze numeriche. Un esempio classico: (0.1 + 1e20) – 1e20 non è lo stesso di 0.1 + (1e20 – 1e20). A prima vista sembra un dettaglio ridicolo, ma nei modelli di linguaggio questa minima discrepanza si propaga token dopo token, trasformandosi in output osservabilmente diversi.
La vera rivelazione arriva quando si guarda ai kernel utilizzati dai Transformer. RMSNorm, prodotto matriciale e meccanismi di attention dipendono da riduzioni numeriche. Nei kernel standard, la riduzione avviene secondo un ordine che dipende dal batch, dal numero di core e persino dal modo in cui le operazioni sono schedulate. Risultato: anche query identiche possono produrre decine di risposte diverse. Non è un problema di modello, né di training, ma di calcolo parallelo.
Thinking Machines Lab ha sperimentato una soluzione chiamata kernel batch-invariant. In pratica, si fissa l’ordine delle riduzioni chiave: RMSNorm calcola le somme nello stesso ordine indipendentemente dal batch, i prodotti matriciali seguono un ordine costante, e l’attenzione viene suddivisa in blocchi di dimensione fissa. Il risultato è sorprendente: testando 1000 completions della stessa query, i kernel standard producono fino a 80 output diversi, mentre i kernel batch-invariant restituiscono tutte le volte la stessa risposta.
Il compromesso è inevitabile. Garantire determinismo significa rinunciare a parte della parallelizzazione più aggressiva, e quindi aumentare i tempi di calcolo. Ma in contesti dove la replicabilità è critica – documenti legali generati automaticamente, sistemi di customer support predittivo, modelli di simulazione scientifica – questa rinuncia diventa necessaria.
Curioso notare come qualcosa di apparentemente tecnico, come l’ordine delle somme in una GPU, possa avere un impatto pratico così tangibile. La non determinismo dei Transformer non è un bug: è una conseguenza naturale della combinazione tra calcolo parallelo e floating-point. Risolverlo richiede attenzione ai dettagli più minuti e una buona dose di disciplina numerica.
Molti sviluppatori e ingegneri sottovalutano questo aspetto. Nei grandi modelli open source, la replicabilità dei risultati è spesso più un sogno che una realtà. Documenti scientifici, benchmark e strumenti di testing devono fare i conti con questa variabilità latente. Kernel batch-invariant offrono una via concreta, ma la strada verso modelli deterministici e scalabili resta lunga e costosa.
Ironia della sorte: abbiamo creato macchine che possono simulare il ragionamento umano in linguaggio naturale, capaci di generare poesia, analisi finanziarie e codici complessi, eppure ancora inciampano sulla matematica più elementare delle GPU. Chi si occupa di intelligenza artificiale avanzata sa che il diavolo non è nei dataset o nei pesi dei modelli, ma nei dettagli più invisibili dell’hardware.
A chi lavora con grandi modelli conviene guardare oltre il training, oltre l’ottimizzazione degli algoritmi e dei parametri, fino a quello che accade nel silenzio dei thread e delle somme parziali. Non è fantascienza, è ingegneria pura: capire perché la stessa domanda genera risposte diverse può fare la differenza tra un sistema affidabile e uno imprevedibile.
Alla fine, la morale tecnologica è chiara: se volete che ChatGPT o i vostri modelli generino sempre la stessa risposta, non basta impostare la temperatura o fissare il seed. Serve un approccio radicale: kernel batch-invariant, attenzione alla floating-point non associativa e disciplina nella parallelizzazione. Solo così la promessa della replicabilità diventa realtà, e possiamo finalmente lasciare le scuse agli utenti curiosi che si chiedono perché la stessa domanda produca mille risposte diverse.