Lab 03-02: La scala delle quantizzazioni¶
Obiettivo¶
Produrre con llama quantize tre quantizzazioni dello stesso modello (Q4_K_M, Q4_0, Q2_K) partendo dal Q8_0
già in cache, e misurare per ciascuna dimensione, bit per peso, velocità (llama bench) e perplexity
su un breve testo italiano. Il risultato è una tabella che mostra dal vivo il compromesso qualità / memoria /
velocità del modulo 00.
Prerequisiti¶
- Modello di prova in cache (lab 02-01);
llama quantize,llama bench,llama perplexityfunzionanti (llama help allli elenca). - ~2 GB liberi su disco per i tre file (ognuno 400-550 MB) e ~2 GB di RAM libera.
- Aver letto le sezioni 3 e 5 del modulo.
Materiale¶
| Cosa | Dove | Dimensione |
|---|---|---|
ggml-org/Qwen3.5-0.8B-GGUF, Qwen3.5-0.8B-Q8_0.gguf (Apache 2.0): il sorgente |
cache HF | 785 MiB |
testo-it.txt: 384 parole di italiano generico (caffè, storia, preparazione) |
in questa cartella | 2,5 KB |
quantizza-e-misura.sh: quantizza, misura e scrive risultati.md |
in questa cartella | – |
Il sorgente è il Q8_0 già in cache: è quasi lossless (+0,003 di perplexity su un 8 B) e per un esperimento didattico è un punto di partenza corretto; per pubblicare un modello si parte dal F16. llama quantize però lo rifiuta di default: serve --allow-requantize.
Procedura¶
-
Trova il sorgente e prova
--dry-run:SRC=$(ls ~/.cache/huggingface/hub/models--ggml-org--Qwen3.5-0.8B-GGUF/snapshots/*/Qwen3.5-0.8B-Q8_0.gguf) mkdir -p ~/llama-lab/quant llama quantize --dry-run $SRC Q4_K_M 2>&1 | tail -4Output (0,6 s):
llama_model_quantize_impl: model size = 784.52 MiB (8.52 BPW) llama_model_quantize_impl: quant size = 506.34 MiB (5.50 BPW)Il dry-run calcola la dimensione finale senza scrivere nulla: comodo per decidere prima di aspettare.
-
Prima quantizzazione a mano, per leggere il log:
llama quantize $SRC ~/llama-lab/quant/Qwen3.5-0.8B-Q4_K_M.gguf Q4_K_M 4 2>&1 | tee ~/llama-lab/quant/quant-Q4_K_M.log | tail -5Senza
--allow-requantizesi ferma subito conllama_model_quantize: failed to quantize: requantizing from type q8_0 is disabled. Aggiungilo:llama quantize --allow-requantize $SRC ~/llama-lab/quant/Qwen3.5-0.8B-Q4_K_M.gguf Q4_K_M 4 2>&1 | tee ~/llama-lab/quant/quant-Q4_K_M.log | tail -5Ora scorrono 335 righe, una per tensore. Cerca nel log (
grep -E "token_embd|blk.0\." …) e osserva il mix:token_embd.weight … converting to q6_K,blk.0.attn_qkv.weight → q6_K,blk.0.ffn_down.weight → q6_K,blk.0.ffn_gate.weight → q4_K, le*_norm.weightrestanof32. In coda:model size = 784.52 MiB (8.52 BPW),quant size = 506.34 MiB (5.50 BPW), tempo 20-60 s. -
Tutto il resto con lo script, che quantizza ogni tipo, poi misura con
llama bench -p 32 -n 16 -t 3 -r 1ellama perplexity -c 128sul testo italiano (un processo alla volta):bash quantizza-e-misura.sh $SRC Q4_K_M Q4_0 Q2_K # T=4 bash … per usare 4 thread cat ~/llama-lab/quant/risultati.mdRisultato su una macchina a 6 vCPU senza GPU, 3 thread (le velocità sono indicative e dipendono dalla CPU):
Tipo MiB bpw pp32 t/s tg16 t/s PPL ( -c 128, 4 blocchi)Q8_0(sorgente)795 8,52 39,7 10,6 11,50 ± 1,81 Q4_K_M517 5,50 53,8 7,2 12,50 ± 1,97 Q4_0490 5,20 38,9 13,5 14,66 ± 2,34 Q2_K410 4,34 41,0 8,3 154,9 ± 30,4 (Il totale dura circa 4 minuti; i MiB sono di
du, quindi leggermente diversi dai MiB "del modello" nel log.) -
Leggi la tabella:
- Dimensione: da 795 a 410 MiB, ma non "8 bit → 2 bit = un quarto": l'embedding da 248 320 × 1 024 resta a
6 bit e da solo pesa 200 MiB. Su un 8 B (vocabolario proporzionalmente piccolo)
Q2_Ksarebbe 2,96 GB contro 7,96 diQ8_0. - Perplexity:
Q4_K_M+9 % (accettabile),Q4_0+28 % (si sente),Q2_K×13 (inutilizzabile). Le barre d'errore (± nel log) dipendono dal numero di blocchi: con più testo si stringono, l'ordine fra i tipi non cambia. Un modello da 0,8 B soffre i pochi bit molto più di un 8 B (tabella del modulo:Q2_Ksu Llama-3-8B è +3,5, cioè +60 %). - Velocità: con
-r 1ogni valore è una misura singola: le velocità in tabella vanno lette come ordine di grandezza, non confrontate al decimale. La tendenza da leggere: generazione più veloce quanto più il file è piccolo (banda di memoria) eQ4_0particolarmente rapido grazie al repacking dei kernel CPU; prompt processing meno sensibile al tipo. Ripeti con-r 5e-t= core fisici per numeri stabili (modulo 05).
- Dimensione: da 795 a 410 MiB, ma non "8 bit → 2 bit = un quarto": l'embedding da 248 320 × 1 024 resta a
6 bit e da solo pesa 200 MiB. Su un 8 B (vocabolario proporzionalmente piccolo)
-
Prova con le mani. Stessa domanda a
--temp 0ai quattro file:for f in $SRC ~/llama-lab/quant/*.gguf; do echo "== $f"; llama cli -m $f -st -rea off --temp 0 -n 40 -t 4 -p "Elenca tre città italiane sul mare." 2>&1 | sed -n '/^> /,/Prompt:/p'; doneIl
Q2_Kdi solito produce testo sconnesso o ripetitivo;Q4_0eQ4_K_Mrisposte plausibili; confronta con ilQ8_0. -
Pulisci. Tieni solo ciò che serve al lab 03-03 (il
Q2_K), cancella il resto:
Verifica del risultato¶
-
--dry-runha previsto 506,34 MiB e il fileQ4_K_Mreale li conferma (5.50 BPWnel log). - Sai spiegare, dal log, perché
Q4_K_Mnon è "tutto a 4 bit". -
risultati.mdha quattro righe con MiB, bpw, pp, tg e PPL. - Le perplexity crescono nell'ordine
Q8_0 < Q4_K_M < Q4_0 << Q2_K. - Hai visto con i tuoi occhi la differenza di qualità del
Q2_K.
Domande e varianti¶
- Perché il primo tentativo senza
--allow-requantizeè stato rifiutato, e perché la documentazione sconsiglia comunque di requantizzare? - Quantizza con
--pure(Q4_K_M --pure) e confronta bpw e perplexity: quanto vale il mix? - Aggiungi
Q6_K,Q5_K_M,Q3_K_M,IQ4_XSalla lista dello script (attenzione allo spazio su disco: ~500 MB ciascuno). --token-embedding-type q4_0 --output-tensor-type q4_0suQ4_K_M: quanti MiB risparmi e quanto costa in PPL? Su questo modello l'embedding è metà del file: è il caso in cui la scelta pesa di più.- Variante lunga: scarica Wikitext-2 (
scripts/get-wikitext-2.shdei sorgenti) e misura la PPL "vera" con-c 512su un modello che ti interessa (ore su CPU: fallo di notte, o con GPU).
Consegna¶
risultati.md prodotto dallo script, più: le 6 righe di log del punto 2 che mostrano il mix; le quattro risposte del
punto 5; un paragrafo che dica quale dei quattro file useresti su un telefono con 2 GB liberi, quale su un portatile,
e perché.