Come ci può stare
Non è compressione, e non è che ci stiano: per ogni token ne serve una frazione
Il modello che uso occupa 22 gigabyte su disco e gira su una scheda che ne ha 8. Non perché sia compresso ancora di più, e non perché ci stia: i pesi restano nella memoria di sistema e arrivano sulla scheda quando servono. Quello vale per qualunque modello, denso compreso. Quello che vale solo per questo è quanto se ne deve spostare per ogni token, perché è costruito in modo che quasi nessuno di quei parametri serva alla parola che sta scrivendo adesso. Si chiama Mixture-of-Experts, ed è la ragione per cui questa serie esiste. Qui dentro: come funziona, quanto è quella frazione, e il conto che spiega perché il prezzo si paga altrove.
Nell'articolo precedente ho lasciato il paradosso sul tavolo: 35 miliardi di parametri, 70 gigabyte nella forma in cui vengono distribuiti, 22 nella versione quantizzata che uso. La scheda ne ha 8. E il modello risponde.
La tentazione è pensare a un trucco di compressione, o a un caricamento a pezzi che paga un'attesa a ogni parola. Non è nessuna delle due — ma non è nemmeno che ci stia. I pesi restano nella memoria di sistema e vengono portati sulla scheda quando servono: si chiama offloading, e non è una proprietà di questo modello. È quello che permette a qualunque modello troppo grande di girare su una scheda troppo piccola.
Il prezzo dell'offloading è il trasporto: quanti byte devono attraversare il collegamento fra le due memorie per ogni token prodotto. Per un LLM denso la risposta è brutale: deve trasportare praticamente sé stesso, a ogni parola. Girerebbe, e farebbe meno di un token al secondo. È il motivo per cui nessuno lo fa.
Qui la risposta è trentadue volte più bassa, e la ragione è nel modo in cui il modello è costruito. Si può dire in una riga: quasi nessuno di quei parametri serve per il token che sta producendo adesso.
Duecentocinquantasei specialisti, otto al lavoro
In un LLM denso, ogni token attraversa tutti i blocchi in fila, e ogni blocco lo elabora con gli stessi pesi. Sempre gli stessi, per qualunque testo. Se il blocco pesa un gigabyte, quel gigabyte va letto per ogni singolo token.
Un Mixture-of-Experts spezza quel blocco in tanti blocchi più piccoli — gli esperti — e ne accende solo alcuni per volta. Nel modello che uso ce ne sono 256 per livello, e per ogni token se ne accendono otto.
Chi sceglie gli otto è il router: una matrice piccola, davanti agli esperti, che dà un punteggio a tutti e 256 e passa il testo ai primi otto. Non è una regola scritta da qualcuno: è addestrato insieme al resto — quale esperto sappia fare cosa non lo ha deciso nessuno, e in generale non lo sa nessuno.
Due dettagli cambiano l'ordine di grandezza del problema, e nelle spiegazioni si perdono quasi sempre.
- La scelta si rifà a ogni livello. Non otto esperti per l'intero modello: otto per ciascuno dei 40 livelli. Sono 320 esperti per ogni token prodotto, pescati da un magazzino di 10.240.
- La scelta si rifà a ogni token. La parola successiva può attivare otto esperti completamente diversi. Non esiste un insieme stabile da tenere pronto: l'insieme cambia continuamente, ed è questo che rende il problema interessante invece che semplicemente grande.
C'è anche, in questo modello, un esperto condiviso che resta sempre acceso accanto agli otto scelti — la parte del lavoro che conviene fare sempre nello stesso modo. Pesa poco, e per il ragionamento che segue non cambia niente.
La scrivania e la libreria
Serve un'immagine, e questa regge fino in fondo.
La memoria della scheda video è una scrivania: piccola, ma tutto quello che ci sta sopra lo prendete senza alzarvi. La memoria di sistema è la libreria dietro di voi: ci sta tutto, ma per ogni libro dovete girarvi, cercare, tornare. Gli esperti sono i libri.
Sulla scrivania i libri che ci stanno sono 1.200 su 10.240: quasi il dodici per cento del magazzino. Il resto sta in libreria.
Ora mettete insieme i due numeri. Per ogni token servono 320 libri. Se sulla scrivania c'è un ottavo della biblioteca, la grande maggioranza di quei 320 bisogna andarla a prendere. Ogni volta.
Il prezzo, che non finisce nei titoli
Quantizzato come lo uso, un esperto pesa meno di due megabyte, e trecentoventi ne fanno 568 megabyte: è quello che un singolo token richiede. La scrivania ne copre poco più di un decimo — un decimo del magazzino, quindi in media un decimo anche di quei 320. Restano cinquecento megabyte tondi da trasportare, per ogni token prodotto.
Questo conto si può chiudere a mano. E chiudendolo salta fuori un problema.
La strada fra la libreria e la scrivania — il collegamento PCIe di cui parlavo nel primo articolo — sulla mia macchina trasporta dodici gigabyte al secondo, misurati. Cinquecento megabyte a quella velocità sono quarantadue millisecondi. Il che fissa un tetto: su quella strada, e solo su quella, non possono passare più di ventiquattro token al secondo.
Il modello, in quella configurazione, ne fa trentacinque.
Non è un tetto sfiorato: è un tetto sfondato. Per fare trentacinque token al secondo servirebbero diciassette gigabyte e mezzo al secondo di esperti consegnati alla GPU, su una strada che ne porta dodici.
Il conto non è sbagliato, e sta per esteso nel box in fondo. La conclusione è l'unica possibile: quella non è l'unica strada. Ce n'è una seconda, il motore la usa, e quale sia — con l'aggravante che a prima vista sembra la più lenta delle due — è tutto il prossimo articolo.
Trentacinque miliardi, ma di cosa
Fin qui ho usato "35 miliardi di parametri" come se fosse un blocco unico. Non lo è, e spacchettarlo — cosa che si fa con sei cifre del file di configurazione, senza aprire il modello — dice due cose che non mi aspettavo.
La prima: gli esperti sono il 92% del modello. Trentadue dei trentacinque miliardi di parametri stanno lì, ed è di quel 92% che per ogni token si accende il tre per cento. Tutto il resto — l'attenzione, il vocabolario, l'esperto condiviso — sono quasi tre miliardi, e sono sempre accesi.
La seconda è quella che mi ha fatto rifare il conto due volte. Dei parametri che si accendono per ogni token, il vocabolario da solo pesa quanto tutti gli esperti che si accendono per quel token, messi insieme: un miliardo e diciassette milioni contro un miliardo e sette. Questo modello ha 248.320 token di vocabolario, e la tabella che li traduce in numeri all'ingresso più quella che li ritraduce in parole all'uscita valgono, da sole, otto esperti per quaranta livelli.
Non è una curiosità da nota a piè di pagina. Se il grosso del modello si accende a sprazzi e il resto è sempre acceso, allora la parte "sempre accesa" è quella che deve stare sulla scheda a ogni costo — ed è la ragione per cui, nel primo articolo, il checkpoint riquantizzato faceva 29 token al secondo e quello pubblicato ne faceva 22. Non cambiava un esperto: cambiava quanto occupavano i parametri sempre accesi, e quindi quanto spazio restava alla scrivania.
Cosa si paga in cambio
Qualcosa si paga sempre, e vale dirlo prima che lo dica un commento.
Un modello a esperti non è un LLM denso da 35 miliardi ottenuto a sconto, e la distinzione più netta che ho trovato la fa un lavoro presentato a ICLR nel 2025, dal titolo che vale da solo: Mixture of Parrots. Tenendo fissi i parametri che si accendono e aumentando il numero di esperti, quello che migliora è la memoria — i compiti in cui bisogna ricordare qualcosa — mentre la capacità di ragionare smette di salire. Gli autori lo dimostrano anche in astratto: esistono problemi che nessun numero di esperti di una certa dimensione riesce a risolvere, e che un modello denso appena più largo risolve senza fatica.
Quel lavoro però è del 2024, e nel frattempo le architetture si sono mosse. Un benchmark presentato a EMNLP l'anno dopo prova a rispondere a una domanda più utile — non se un modello a esperti ragioni meno, ma da cosa dipende — e trova che è una questione di come lo si costruisce: il modo in cui si sceglie l'esperto e come si regolarizza l'addestramento cambiano la capacità di ragionamento in modo misurabile. Quel limite quindi non è una tara fissa dell'architettura: è una voce del progetto, e da lì in avanti si è saputo su quali leve mettere le mani.
Il confronto onesto quindi non è "35 miliardi contro 35 miliardi", è "35 totali con tre accesi contro tre accesi e basta" — e in quel confronto il modello a esperti vince largamente, ed è la ragione per cui questa architettura ha preso piede così in fretta.
E c'è un costo che si vede solo mettendolo sotto carico: due token diversi vogliono esperti diversi. Servire due conversazioni insieme non raddoppia il lavoro, lo moltiplica per il numero di esperti distinti che le due richiedono. Su una scheda da 8 gigabyte questo si traduce in una riga della configurazione — una richiesta alla volta — di cui parlerò nel quarto articolo, perché lì vale quasi un gigabyte.
Da qui in avanti: l'aritmetica e i comandi
[ ] La misura — i trentacinque miliardi, contati
Tutti i numeri di questa sezione stanno nel config.json del modello, che è pubblico. Le sei cifre che servono:
hidden_size 2.048 la larghezza del modello moe_intermediate_size 512 la larghezza di un esperto num_experts 256 quanti per livello num_experts_per_tok 8 quanti se ne accendono num_hidden_layers 40 quanti livelli vocab_size 248.320 quanti token conosce
Un esperto è composto da tre matrici che vanno dalla larghezza del modello a quella dell'esperto e ritorno:
un esperto 2.048 × 512 × 3 matrici = 3.145.728 pesi un livello 3.145.728 × 256 esperti = 805.306.368 tutti i livelli 805.306.368 × 40 = 32.212.254.720 ≈ 32,2 miliardi
Trentadue miliardi su trentacinque: il 92% del modello sono esperti. E quello che si accende per un token:
otto esperti, quaranta livelli 3.145.728 × 8 × 40 = 1.006.632.960
Un miliardo, cioè il tre per cento di quei 32,2. Il vocabolario, per confronto — la tabella d'ingresso più quella d'uscita, che in questo modello sono due matrici distinte:
248.320 token × 2.048 × 2 tabelle = 1.017.118.720
Un miliardo e diciassette milioni contro un miliardo e sette. Il vocabolario pesa quanto gli esperti che si accendono, e sta sulla scheda sempre.
Il trasporto, con l'esperto quantizzato a 1.775.616 byte come lo riporta il server su /v1/cache/status. Sopra il termine di confronto: lo stesso conto se ogni token avesse bisogno di tutti gli esperti, che è la condizione di un modello denso.
se servissero tutti gli esperti 256 esperti × 40 livelli × 1.775.616 B = 18,18 GB per token 18,18 GB ÷ 11,9 GB/s = 1,53 s -> 0,65 token/s
quelli che servono davvero: 32 volte meno 8 esperti × 40 livelli × 1.775.616 B = 568,2 MB richiesti per token scrivania piena all'11,7% (1.200/10.240) -> da trasportare = 501,6 MB 501,6 MB ÷ 11,9 GB/s (PCIe misurato) = 42,2 ms 1 ÷ 0,0422 s = 23,7 token al secondo ← il tetto ```
Misurati sul checkpoint ufficiale, stessa geometria: 35 token al secondo. Che richiederebbero:
501,6 MB × 35 /s = 17,6 GB/s di banda effettiva tetto PCIe misurato = 11,9 GB/s (gather reale) / 12,3 (copia lineare)
Il divario è il soggetto dell'articolo 3. E si noti che il profilo a contesto lungo, quello che serve a un agent, scende a 512 posti su 10.240 — il cinque per cento — e lì il tetto del solo PCIe cade a 22 token al secondo, che è quello che quella configurazione misura davvero. La strada in più si vede solo quando c'è margine per usarla.
[ ] Taratura — fatelo sul modello che vi interessa
Il conto qui sopra funziona su qualunque modello a esperti, e il file che serve è pubblico. Sostituite il nome del repository e leggete le sei cifre:
curl -s https://huggingface.co/Qwen/Qwen3-30B-A3B/raw/main/config.json \
| python3 -c '
import json,sys
c=json.load(sys.stdin); c=c.get("text_config",c)
e = c["hidden_size"] * c["moe_intermediate_size"] * 3
tot = e * c["num_experts"] * c["num_hidden_layers"]
att = e * c["num_experts_per_tok"] * c["num_hidden_layers"]
voc = c["vocab_size"] * c["hidden_size"] * (1 if c.get("tie_word_embeddings") else 2)
print(f"un esperto {e:>16,}")
print(f"esperti in totale {tot:>16,}")
print(f"accesi per token {att:>16,} ({att/tot*100:.1f}%)")
print(f"vocabolario {voc:>16,}")
'
Due cose da guardare. La prima è il rapporto fra la seconda e la terza riga: è quanto il modello spegne. La seconda è se il vocabolario sta nello stesso ordine di grandezza dei parametri che si accendono — nei modelli piccoli e nei multilingue lo supera, e allora la voce di costo principale dell'inferenza non è quella che vi aspettate.