Perché la quantizzazione è la leva più importante dell'AI locale
I pesi di un modello sono miliardi di numeri. Memorizzati nel modo di default — 16 bit ciascuno (FP16/BF16) — l'aritmetica è brutale: ogni miliardo di parametri costa ~2 GB di memoria. Un 7B richiede ~14 GB, un 70B ~140 GB, e questo prima della KV-cache e dell'overhead di runtime. Con questa matematica, l'AI locale finirebbe a 13B per quasi tutti.
La quantizzazione cambia l'equazione. Mappando ogni peso su un insieme più piccolo di valori — 8, 4, persino 2 bit — lo stesso 70B scende a ~40 GB in 4-bit. All'improvviso entra su due GPU consumer, o una scheda workstation, o un Mac Studio. Quasi tutto ciò che di interessante accade nel deployment on-premise e locale degli LLM discende da questa singola tecnica.
C'è un secondo effetto che sorprende: i modelli quantizzati sono di solito più veloci. L'inferenza LLM single-user è limitata dalla banda di memoria — la GPU passa la maggior parte del tempo a trasferire pesi dalla VRAM, non a fare calcoli. Dimezza i byte per peso e dimezzi circa i byte mossi per token, quindi i token/sec salgono anche se si aggiunge il lavoro di dequantizzazione. Su hardware povero di banda (GPU consumer, Apple Silicon), un modello Q4 può essere quasi due volte più veloce del suo genitore FP16.
Come funziona davvero (in cinque frasi)
Prendi un gruppo di pesi — diciamo 32 o 128. Registra l'intervallo che coprono (una scala, a volte più uno zero-point). Aggancia ogni peso al più vicino di 2N livelli in quell'intervallo, memorizzando solo l'indice del livello (N bit) più la scala condivisa. All'inferenza, moltiplica indietro: indice × scala ≈ peso originale. L'arte sta nei dettagli — dimensioni dei gruppi, tenere alcuni pesi "outlier" a precisione più alta, usare dati di calibrazione per decidere quali errori pesano meno — e quei dettagli sono esattamente ciò che separa i formati qui sotto.
Esistono due famiglie: la post-training quantization (PTQ) — quantizzi un modello finito, minuti/ore, ciò che usi il 99% delle volte — e la quantization-aware training (QAT), dove il modello viene addestrato sapendo che sarà quantizzato. La QAT dà la migliore qualità a pochi bit ma deve farla il creatore del modello; alcune release moderne (es. edizioni QAT di modelli open-weight) escono così, e vale la pena preferirle quando disponibili.
Livelli di quantizzazione: il compromesso qualità/dimensione
| Livello | Dim. vs FP16 | Esempio 70B | Qualità | Usa quando |
|---|---|---|---|---|
| FP16/BF16 | 1× | ~140 GB | Riferimento | training, ricerca, VRAM non è un vincolo |
| 8-bit (Q8/INT8/FP8) | ~0.50× | ~70 GB | Quasi lossless | serving quality-critical con VRAM in avanzo |
| 6-bit (Q6_K) | ~0.38× | ~54 GB | Eccellente | puoi permetterti più di Q4 ma non Q8 |
| 5-bit (Q5_K_M) | ~0.34× | ~48 GB | Molto buona+ | un margine di sicurezza sopra Q4 a piccolo costo |
| 4-bit (Q4_K_M/AWQ/GPTQ) | ~0.28× | ~40 GB | Molto buona | IL punto ideale di default |
| 3-bit (Q3_K/IQ3) | ~0.20× | ~28 GB | Perdita percepibile | per entrare in poca VRAM; preferisci imatrix/IQ |
| 2-bit (Q2_K/IQ2) | ~0.14× | ~20 GB | Perdita significativa | ultima risorsa; solo i quant IQ moderni sono usabili |
Dimensioni indicative (solo pesi, prima della KV-cache); la "qualità" descrive il comportamento tipico su modelli densi moderni — i modelli MoE e i molto piccoli (≤3B) degradano più in fretta a pochi bit.
La regola d'oro: grande-quantizzato batte piccolo-pieno
Il risultato pratico più utile dell'intero campo: fino al 4-bit, un modello più grande quantizzato batte quasi sempre uno più piccolo a precisione piena a parità di memoria. Un 70B a Q4 (~40 GB) supera comodamente un 13B a FP16 (~26 GB) su praticamente ogni benchmark e test soggettivo. Quando decidi cosa far girare, scegli prima il parametraggio più grande che il tuo hardware regge a Q4, poi spendi la VRAM avanzata in un quant migliore o più contesto — non in un modello più piccolo a precisione più alta.
La regola ha due limiti. Sotto ~3-bit il degrado accelera e può annullare il vantaggio della dimensione — un 70B a IQ2 può perdere contro un 32B a Q4 che usa la stessa memoria. E per i modelli minuscoli (≤3B) anche il 4-bit fa male in modo percepibile, perché c'è meno ridondanza ad assorbire l'errore.
Lo zoo dei quant GGUF, decodificato
Scarica un qualsiasi modello GGUF e ti troverai davanti a un muro di suffissi. Sono tutti lo stesso modello a punti qualità/dimensione diversi:
- Q8_0 — 8-bit semplice. Quasi lossless, file più grande. Per uso archivistico o quality-paranoid.
- Q6_K, Q5_K_M, Q4_K_M, Q3_K_M, Q2_K — la famiglia K-quant: quantizzazione a gruppi più intelligente che protegge i tensori più sensibili con bit extra. Le varianti M (medium) sono i default bilanciati; S (small) lima la dimensione a costo di qualità, L (large) il contrario.
- IQ4_XS, IQ3_M, IQ2_M… — i più recenti i-quant: metodi basati su importance-matrix che spremono qualità migliore dai bit-width molto bassi. A 2–3 bit, preferisci sempre IQ ai Q semplici se disponibili.
- Quant imatrix — qualsiasi livello costruito usando una importance matrix calcolata su testo di calibrazione, così il quantizzatore sa quali pesi contano. Sensibilmente migliori a Q3 e sotto, leggermente migliori a Q4.
Scelte pratiche: Q4_K_M come default; Q5_K_M/Q6_K quando hai VRAM in avanzo; IQ3/IQ2 imatrix solo quando non entra niente di più grande; Q8_0 quando la qualità è critica e la memoria no. Se per quel quant specifico sono pubblicati i numeri di perplexity, fidati di quelli più che del folklore — le differenze tra un Q4 e un Q5 ben fatti sono spesso più piccole delle differenze tra due fine-tune della stessa base.
Formati per serving GPU: GPTQ, AWQ, EXL2, FP8
- GPTQ — lo standard storico del 4-bit su GPU. Usa dati di calibrazione per minimizzare l'errore strato per strato. Ben supportato ovunque (vLLM, TGI, TensorRT-LLM). Qualità leggermente dietro AWQ a parità di bit nella maggior parte dei confronti moderni.
- AWQ (activation-aware) — osserva quali pesi vedono attivazioni grandi e li protegge. Di solito il miglior equilibrio qualità/velocità per il serving GPU a 4-bit, e oggi la scelta di default su vLLM in produzione.
- EXL2 — il formato di ExLlama, con bit-rate medi frazionari (es. 4.65 bit): mescola la precisione per strato per centrare un budget di memoria esatto. La scelta da power-user per spremere una singola GPU consumer (velocità single-stream più alte, controllo fine della dimensione); meno comune nei server multi-utente.
- FP8 — su GPU Hopper/Ada e successive (H100, RTX 40/50), 8-bit floating point per i pesi e a volte attivazioni/KV-cache. Quasi lossless con accelerazione hardware; sempre più il default enterprise per il serving quando la VRAM lo consente.
- bitsandbytes NF4 — quantizzazione 4-bit a load-time nell'ecosistema Hugging Face. Comoda per sperimentare ed è la base di QLoRA, ma più lenta di AWQ/GPTQ/EXL2 pre-quantizzati per il serving.
Non dimenticare la KV-cache
I pesi sono solo metà della storia della memoria. La KV-cache — le chiavi/valori di attenzione tenuti per ogni token nel contesto — cresce linearmente con la lunghezza del contesto e può superare i pesi: un modello classe 70B a 128K di contesto può richiedere decine di GB di cache a FP16. Se ti sei mai chiesto perché il tuo modello Q4 "da 40 GB" non si carica con contesto lungo su una scheda da 48 GB, il motivo è questo.
I runtime moderni permettono di quantizzare anche la cache: la cache Q8 è essenzialmente gratis (impatto di qualità trascurabile, dimezza la memoria della cache) e la cache Q4 è usabile con un piccolo costo, sentito soprattutto nel recall a contesto lungo. Attivare la KV-cache Q8 è spesso il singolo modo più facile per raddoppiare il contesto utilizzabile — controlla i flag del tuo runtime (llama.cpp --cache-type-k/v, opzioni KV-cache dtype di vLLM).
Cosa degrada davvero, e come giudicarlo
L'errore di quantizzazione non colpisce tutte le capacità allo stesso modo. In ordine approssimativo di fragilità: ragionamento multi-step e matematica cedono per primi, poi la precisione nella generazione di codice, poi le sfumature nell'instruction-following, il recall a contesto lungo, e infine la prosa fluente — la "sensazione" della chat sopravvive quasi a tutto, ed è per questo che un test casuale a Q2 può ingannarti facendoti credere che non si sia perso nulla.
I delta di perplexity sono la misura standard da laboratorio (un buon Q4_K_M sta tipicamente pochi punti percentuali sopra FP16), ma comprimono tutto in un numero. Se il tuo caso d'uso è tool-calling agentico, output JSON strutturato o RAG su documenti lunghi, testa quello prima di standardizzare su un quant: un modello che chatta perfettamente a Q3 può iniziare a emettere JSON malformato o sintassi di tool-call mancante allo stesso livello. Regola pratica per tutto ciò che è precision-sensitive: resta a Q4_K_M o sopra, preferisci Q5/Q6 per gli agenti.
Quantizzare un modello tuo
Raramente serve — per qualsiasi modello popolare, i quant della community (es. i noti repository GGUF su Hugging Face) compaiono a poche ore dalla release. Ti serve davvero quando hai fatto fine-tuning di un modello tuo o ti serve una dimensione che nessuno ha pubblicato:
- GGUF:
convert_hf_to_gguf.py(in llama.cpp) trasforma i pesi HF in GGUF FP16, poillama-quantizeproduce qualsiasi livello — minuti su CPU, nessuna GPU necessaria. Aggiungi un passo imatrix (calcolato su pochi MB di testo rappresentativo) per i target a pochi bit. - AWQ/GPTQ: librerie AutoAWQ / GPTQModel; servono una GPU e un piccolo set di calibrazione (qualche centinaio di campioni di testo simile al tuo workload — usare dati di calibrazione molto non rappresentativi peggiora la qualità in modo misurabile).
- Collegamento col fine-tuning: QLoRA addestra adapter LoRA sopra una base congelata quantizzata NF4 — è per questo che puoi fare fine-tuning di un 70B su una singola scheda da 48 GB. La quantizzazione non è solo un trucco da deployment; è ciò che rende il fine-tuning locale accessibile.
Errori comuni
- Confrontare quant di modelli diversi. "Modello A a Q4 vs modello B a Q5" confonde due variabili; giudica i livelli di quant solo all'interno dello stesso modello.
- Prendere i quant day-one di un'architettura nuova di zecca. Il supporto dei runtime spesso arriva dopo; i primi GGUF di nuove famiglie di modelli sono usciti rotti (tokenizer sbagliato, rope scaling sbagliato). Se un modello fresco si comporta in modo strano, prova l'ultima build del runtime e un quant rifatto prima di incolpare il modello.
- Ignorare la cache nel budget VRAM. "I pesi entrano quindi entra" è sbagliato a contesto lungo; metti a budget pesi + cache + ~1–2 GB di overhead di runtime.
- Assumere che la quantizzazione acceleri sempre. Nel batch serving compute-bound (molti utenti concorrenti su GPU datacenter), i formati a pochi bit possono strozzarsi sulla dequantizzazione; lì spesso vince FP8.
- Quantizzare duramente i modelli piccoli. Un 1–3B a Q3 è di solito un affare peggiore di un 7B quantizzato bene — i modelli piccoli non hanno ridondanza da sacrificare.
Come scegliere — matrice decisionale
- Mac / CPU / desktop, setup facile → GGUF Q4_K_M via Ollama o LM Studio; sali a Q5/Q6 se la RAM lo consente.
- Singola GPU consumer, massimo contesto/velocità → EXL2 a un bit-rate tarato sulla tua VRAM, o GGUF interamente in offload; KV-cache Q8 attiva.
- Serving GPU multi-utente in produzione → AWQ (o FP8 su H100/Ada+) su vLLM/TGI.
- Qualità critica, VRAM in avanzo → 8-bit (Q8_0 / FP8), o Q6_K come compromesso pragmatico.
- Entra a malapena → quant IQ3/IQ2 imatrix — e valuta se un modello più piccolo a Q4 non ti serva meglio.
- Fine-tuning in locale → QLoRA (NF4) per l'addestramento; poi quantizza il risultato merged nel tuo formato di serving.