Lab 05-03 · Decodifica speculativa¶
Obiettivo¶
Misurare quanto un modello bozza accelera un modello target su due tipi di testo (prosa e codice), capire da cosa dipende il tasso di accettazione e provare la variante senza modello bozza (n-gram) e quella a testa MTP.
Prerequisiti¶
- Modulo 05 letto (sezione "Decodifica speculativa") e lab 05-01 fatto.
- Per la parte principale: GPU con almeno 10 GB di VRAM (target da 7,7 GB + bozza), oppure pazienza su CPU con la coppia piccola.
- Per la variante MTP: 6 GB liberi (VRAM o RAM).
Materiale¶
| Ruolo | Repository | File | Dimensione | Licenza |
|---|---|---|---|---|
| Target (codice) | ggml-org/Qwen2.5-Coder-7B-Q8_0-GGUF |
qwen2.5-coder-7b-q8_0.gguf |
7,72 GB | Apache 2.0 |
| Bozza | ggml-org/Qwen2.5-Coder-0.5B-Q8_0-GGUF |
qwen2.5-coder-0.5b-q8_0.gguf |
506 MB | Apache 2.0 |
| Target piccolo (CPU) | ggml-org/Qwen2.5-Coder-1.5B-Q8_0-GGUF |
qwen2.5-coder-1.5b-q8_0.gguf |
1,57 GB | Apache 2.0 |
| Target con testa MTP | ggml-org/gemma-4-e4b-it-GGUF:Q4_0 |
gemma-4-E4B-it-Q4_0.gguf + mtp-gemma-4-E4B-it-Q4_0.gguf |
4,4 GB + 57 MB | Gemma |
| Metodi n-gram | qualsiasi modello, es. ggml-org/Qwen3.5-0.8B-GGUF |
Qwen3.5-0.8B-Q8_0.gguf |
795 MB | Apache 2.0 |
La coppia Qwen2.5-Coder 7B + 0.5B è quella "ufficiale": llama serve --fim-qwen-7b-spec la scarica e la configura da solo.
Bozza e target devono avere lo stesso vocabolario (stessa famiglia e generazione): Qwen2.5 con Qwen2.5, Gemma con la
propria testa MTP. Una coppia sbagliata dà errore all'avvio o accettazione zero.
Prepara due prompt in file di testo:
cat > prosa.txt <<'EOF'
Scrivi un racconto di 300 parole su un faro abbandonato, con un finale a sorpresa.
EOF
cat > codice.txt <<'EOF'
Scrivi in Python una classe LRUCache con metodi get e put, complessità O(1), con docstring e un piccolo test.
EOF
Procedura¶
-
Riferimento senza bozza. Genera 300 token per ciascun prompt e annota la riga finale
[ Prompt: … t/s | Generation: … t/s ]. Usa un seed fisso e temperatura 0 per confrontare testi uguali:T=$(ls ~/.cache/huggingface/hub/models--ggml-org--Qwen2.5-Coder-7B-Q8_0-GGUF/snapshots/*/qwen2.5-coder-7b-q8_0.gguf) D=$(ls ~/.cache/huggingface/hub/models--ggml-org--Qwen2.5-Coder-0.5B-Q8_0-GGUF/snapshots/*/qwen2.5-coder-0.5b-q8_0.gguf) llama cli -m "$T" -ngl all -st -f prosa.txt -n 300 --temp 0 -s 42 llama cli -m "$T" -ngl all -st -f codice.txt -n 300 --temp 0 -s 42 -
Con la bozza,
draft-simple. Stesso comando più-mde--spec-type:llama cli -m "$T" -md "$D" --spec-type draft-simple -ngl all -ngld all -st -f prosa.txt -n 300 --temp 0 -s 42 llama cli -m "$T" -md "$D" --spec-type draft-simple -ngl all -ngld all -st -f codice.txt -n 300 --temp 0 -s 42Valori indicativi su GPU: sul codice la generazione sale di 1,5-2,5×, sulla prosa di 1,2-1,6×; il rapporto esatto dipende dalla tua scheda. Il testo prodotto a temperatura 0 deve essere identico a quello del passo 1.
-
Quanti token proporre? Ripeti il prompt di codice con
--spec-draft-n-max 2,4,8,16:for k in 2 4 8 16; do echo "== n-max $k" llama cli -m "$T" -md "$D" --spec-type draft-simple -ngl all -st -f codice.txt -n 300 --temp 0 -s 42 2>/dev/null | tail -2 doneUn
ktroppo alto fa lavorare la bozza per niente (i token oltre il primo rifiuto vengono scartati); troppo basso lascia guadagno sul tavolo. Il default è 3. Segna il migliore. -
Temperatura alta. Rilancia il passo 2 con
--temp 1.0: l'accettazione cala perché il target "cambia idea" più spesso rispetto alla bozza. Quanto perdi? -
Sul server. Gli stessi flag valgono per
llama serve; il campotimingsdella risposta ti dàpredicted_per_secondsenza dover leggere il terminale:llama serve -m "$T" -md "$D" --spec-type draft-simple -ngl all --port 18104 curl -s localhost:18104/v1/chat/completions -H 'content-type: application/json' \ -d "{\"messages\":[{\"role\":\"user\",\"content\":\"$(cat codice.txt)\"}],\"max_tokens\":300,\"temperature\":0}" \ | python3 -c "import json,sys; t=json.load(sys.stdin)['timings']; print(t['predicted_n'], 'token a', round(t['predicted_per_second'],1), 't/s')" -
Senza bozza: n-gram. I metodi
ngram-*propongono token già visti nel contesto: nessun secondo modello, utili quando l'output ripete l'input (riscritture, ripetizioni). Esempio su CPU con il modello da 0,8 miliardi:M=$(ls ~/.cache/huggingface/hub/models--ggml-org--Qwen3.5-0.8B-GGUF/snapshots/*/Qwen3.5-0.8B-Q8_0.gguf) llama cli -m "$M" -st -n 80 -t 3 -rea off --spec-type ngram-simple \ -p "Scrivi la frase 'il gatto dorme sul divano' esattamente cinque volte, una per riga."Output atteso: le cinque righe e
[ Prompt: 11.2 t/s | Generation: 6.0 t/s ](su una macchina a 6 vCPU senza GPU). Ripeti senza--spec-typee confronta; poi prova un prompt senza ripetizioni e osserva che il guadagno sparisce. -
Variante MTP (Gemma 4). La bozza è una piccola testa nello stesso repository, il tipo è
draft-mtp:llama cli -hf ggml-org/gemma-4-e4b-it-GGUF:Q4_0 --hf-repo-draft ggml-org/gemma-4-e4b-it-GGUF:Q4_0 \ --spec-type draft-mtp -st -f codice.txt -n 300 --temp 0-hfcon--hf-repo-draftsullo stesso repository scarica il filemtp-*.ggufcome bozza. Confronta con lo stesso comando senza le due opzioni speculative.
Verifica del risultato¶
- Hai quattro numeri di tg: prosa e codice, con e senza bozza; il testo a temperatura 0 è identico nei due casi.
- Sai indicare il
--spec-draft-n-maxmigliore per il tuo hardware e il tuo tipo di testo. - Il test n-gram ha funzionato e sai spiegare quando aiuta.
- (Se fatta) la variante MTP parte e riporta una velocità maggiore del modello da solo.
Domande e varianti¶
- Perché il guadagno è maggiore sul codice che sulla prosa? Pensa a quanto è "prevedibile" il token successivo.
- Prova la coppia piccola su CPU (target 1.5B, bozza 0.5B,
-t= core fisici): il guadagno c'è ancora? Perché la banda di memoria è già satura anche con il target da solo? - Metti la bozza su CPU e il target su GPU (
-devd noneoppure-ngld 0): a volte conviene quando la VRAM è quasi piena. Misura. --spec-draft-p-min 0.5: la bozza propone solo token di cui è abbastanza sicura. Cambia l'accettazione? E la velocità?- Con
-lv 3cerca nel log le statistiche dei token accettati e calcola il tasso di accettazione medio.
Consegna¶
Una tabella con le righe {prosa, codice} × {senza bozza, draft-simple n-max 3, n-max migliore, n-gram, MTP se fatta} e le colonne t/s di generazione e note; più un paragrafo su quale configurazione useresti per un assistente di codice e quale per una chat generale, e perché.