Quantizzare in pratica: pesi soli, o pesi e attivazioni?

Sullo stesso modello trovi sei versioni quantizzate con sigle diverse e nessuna spiegazione di quale ti serva. La scelta si riduce a una domanda sola — cosa stai cercando di risparmiare — e da lì AWQ e SmoothQuant si separano nettamente. Con il codice per produrle, e la libreria giusta: quella di prima è stata archiviata.

Cerchi un modello da sette miliardi di parametri e ne trovi nove versioni: una in FP16, due marcate GPTQ, una AWQ, tre GGUF con sigle come Q4_K_M, una FP8 e una W8A8. Nessuna spiega a chi serve. È il momento in cui la maggior parte delle persone scarica quella con più download e spera bene — scelta ragionevole, che però spreca prestazioni tutte le volte in cui il proprio caso non assomiglia a quello della maggioranza.

La scelta è meno arbitraria di come appare. Si riduce a una domanda sola: che cosa ti sta costando di più, la memoria o il calcolo? Le due grandi famiglie di quantizzazione post-addestramento rispondono a due bisogni diversi, e confonderle produce lavoro sprecato.

Due famiglie, due colli di bottiglia diversi. Il moltiplicatore resta in virgola mobile a sinistra, diventa intero a destra: è tutta lì la differenza. Solo i pesi (AWQ, GPTQ) pesi 4 bit attivazioni 16 bit i pesi si srotolano a 16 bit appena prima di moltiplicare risparmia MEMORIA un utente per volta, GPU piccola Pesi e attivazioni (W8A8) pesi 8 bit attivazioni 8 bit la moltiplicazione avviene fra interi, sui tensor core risparmia CALCOLO molte richieste insieme, server Ostacolo comune: pochi valori enormi che allargano la griglia e rovinano tutti gli altri

A sinistra la quantizzazione dei soli pesi: il modello occupa meno spazio, ma il conto vero si fa ancora in virgola mobile. A destra pesi e attivazioni insieme: il conto passa agli interi, e con esso il guadagno di velocità.

La domanda che decide: memoria o calcolo

Con una sola richiesta alla volta — un assistente sul portatile, un servizio interno con pochi utenti — la GPU passa la maggior parte del tempo a leggere i pesi dalla memoria, non a moltiplicare. Rimpicciolire i pesi accorcia proprio quella lettura, e il modello che prima non entrava nella scheda ora ci entra. È il caso della quantizzazione dei soli pesi.

Con molte richieste servite insieme il quadro si rovescia: i pesi si leggono una volta e si riusano per tutto il lotto, mentre le moltiplicazioni si moltiplicano con esso. Lì il guadagno viene dal far lavorare le unità intere della GPU invece di quelle in virgola mobile, e questo richiede che anche le attivazioni siano a 8 bit.

Qui si sceglie e si esegue; che cosa succede davvero quando si passa da sedici bit a quattro — la griglia, il fattore di scala, l’errore che si introduce — è il capitolo del libro sull’efficienza.

Leggi «Meno bit» nel libro →

Solo i pesi: AWQ

AWQ sta per Activation-aware Weight Quantization (Lin e altri, 2023). L’idea che gli dà il nome: non tutti i pesi contano allo stesso modo, e quelli che contano non si riconoscono guardando i pesi — si riconoscono guardando le attivazioni che li attraversano. Gli autori riportano che basta proteggere all’incirca l’1% dei pesi, individuati così, per abbattere di molto l’errore di quantizzazione; e riportano una velocità circa tripla rispetto all’implementazione FP16 di Hugging Face, su GPU sia desktop sia mobili, con Llama-2 da 70 miliardi di parametri portato a girare su GPU mobili.

Attenzione alla libreria. Quasi tutti i tutorial in circolazione usano AutoAWQ, che è stata archiviata nel maggio 2025 e non è più mantenuta; la documentazione di vLLM lo dichiara e indirizza altrove. Il posto giusto oggi è llm-compressor, dove la stessa funzione è stata adottata dal progetto vLLM.

pip install llmcompressor
from transformers import AutoModelForCausalLM, AutoTokenizer
from llmcompressor import oneshot
from llmcompressor.modifiers.awq import AWQModifier
from llmcompressor.modifiers.quantization import QuantizationModifier

modello_id = "meta-llama/Meta-Llama-3-8B-Instruct"
modello = AutoModelForCausalLM.from_pretrained(modello_id, torch_dtype="auto")
tok = AutoTokenizer.from_pretrained(modello_id)

ricetta = [
    AWQModifier(),                       # calcola le scale guardando le attivazioni
    QuantizationModifier(                # e poi quantizza davvero
        targets=["Linear"], scheme="W4A16_ASYM", ignore=["lm_head"],
    ),
]

oneshot(model=modello, recipe=ricetta, dataset="…", num_calibration_samples=512)
modello.save_pretrained("Llama-3-8B-AWQ", save_compressed=True)
tok.save_pretrained("Llama-3-8B-AWQ")

Due dettagli che nel codice sembrano rumore e non lo sono. ignore=["lm_head"] lascia in virgola mobile l’ultimo strato, quello che produce un punteggio per ogni token del vocabolario: è grande, è delicato, e quantizzarlo costa in qualità più di quanto renda in spazio. E la calibrazione — quei 512 esempi — non è addestramento: serve solo a far passare del testo attraverso il modello per osservare quali attivazioni sono grandi. Ma osservare testo inglese generico e poi servire clienti italiani su documenti tecnici significa proteggere i pesi sbagliati: la calibrazione va fatta sul proprio dominio.

Pesi e attivazioni: SmoothQuant

Portare anche le attivazioni a 8 bit è più difficile, e la ragione è asimmetrica: i pesi di un modello linguistico sono distribuiti in modo ragionevole, le attivazioni no. In alcuni canali compaiono valori enormi rispetto agli altri, e una griglia a 8 bit che debba contenerli schiaccia tutto il resto vicino allo zero.

SmoothQuant (Xiao e altri, 2022; ICML 2023) risolve con una mossa elegante: sposta la difficoltà. Divide le attivazioni per un fattore per canale e moltiplica per lo stesso fattore i pesi corrispondenti — una trasformazione matematicamente equivalente, che lascia il risultato identico ma rende le attivazioni docili e i pesi appena più ruvidi, che è un buon scambio perché i pesi partivano facili. Gli autori riportano fino a 1,56 volte di velocità e metà della memoria con perdita di accuratezza trascurabile, e un modello da 530 miliardi di parametri servito da un solo nodo.

from llmcompressor.modifiers.quantization import GPTQModifier
from llmcompressor.modifiers.transform.smoothquant import SmoothQuantModifier

ricetta = [
    SmoothQuantModifier(smoothing_strength=0.8),   # sposta la difficoltà
    GPTQModifier(targets="Linear", scheme="W8A8", ignore=["lm_head"]),
]

smoothing_strength è il parametro con cui si decide quanta difficoltà spostare: a zero non si sposta nulla e le attivazioni restano intrattabili, a uno si scarica tutto sui pesi e a soffrire diventano loro. Lo 0,8 dell’esempio ufficiale è un punto di partenza, non una costante di natura: su modelli diversi conviene provarne due o tre e misurare.

Misurare sul proprio compito, non sulla classifica

Il collaudo che quasi tutti fanno è la perplexity su un testo di riferimento, ed è utile perché costa poco: se peggiora molto, qualcosa è andato storto in modo evidente. Ma è una media su testo generico, e le medie nascondono esattamente ciò che ti interessa. Un modello quantizzato può conservare la perplexity e perdere la capacità di produrre JSON valido, o di seguire istruzioni lunghe, o di ragionare in italiano invece che scivolare in inglese.

Il collaudo che conta è cinquanta esempi del tuo compito reale, fatti girare sul modello prima e dopo, confrontati a mano. Costa un’ora e trova regressioni che nessun benchmark aggregato mostra. Vale la pena misurare anche la velocità nella tua condizione d’uso: una quantizzazione che dà tre volte la velocità con un utente può darne una e mezza sotto carico, o viceversa, e il numero del paper è stato ottenuto su hardware che quasi certamente non è il tuo.

Cosa portarti a casa

La regola pratica sta in due righe. Se il problema è farci stare il modello — un portatile, una scheda da 24 GB, un utente per volta — prendi la quantizzazione dei soli pesi a 4 bit, AWQ o GPTQ. Se il problema è quanto costa servirlo a molti utenti insieme, guarda W8A8 con SmoothQuant, o le varianti FP8 dove l’hardware le supporta.

Non esiste la versione «quantizzata bene» di un modello: esiste quella giusta per il collo di bottiglia che hai tu.

E vale la pena rifare il giro ogni tanto, perché è un settore in cui gli strumenti muoiono in fretta: la libreria che ogni tutorial del 2024 dava per standard è archiviata da più di un anno, e il codice che si trova copiando dai post più letti installa oggi un pacchetto che nessuno aggiorna più. Sono i casi in cui leggere la documentazione, invece del primo risultato del motore di ricerca, fa una differenza misurabile in ore.

I commenti sono riservati agli iscritti.

Accedi per commentare