🇮🇹 Italiano
Ambiente
macOS, Apple Silicon (M-series), 128 GB unified memory, SSD interno (~18 GB/s random read misurato con iobench).
GLM-5.2-FP8 convertito con i default (--ebits 4 --io-bits 8); testa MTP aggiunta con convert_fp8_to_int4.py --mtp (quindi anch'essa int4).
Decode greedy (TOPK=0 TOPP=0).
Osservazione
La testa MTP viene caricata correttamente (MTP ATTIVA (draft=3)), ma l'accettazione dei
draft è quasi nulla, anche su testo banalmente prevedibile, quindi la guardia adattiva
disabilita la speculazione dopo 24 proposte e non si ottiene alcun guadagno (tok/fw ≈ 1.0).
Prosa ("Explain how a hash map works."):
MTP acceptance 0% (0/24) -> draft disattivati
128 token in 139.86s (0.92 tok/s) | speculazione 1.01 token/forward
Testo massimamente prevedibile ("Count from one to fifty: one, two, three, ..."):
MTP acceptance 4% (1/24) -> draft disattivati
113 token in 117.64s (0.96 tok/s) | speculazione 1.01 token/forward
4% su un conteggio da 1 a 50 è sorprendentemente basso: con decode greedy una buona testa
draft dovrebbe azzeccare il token successivo molto più spesso.
Ipotesi
La testa MTP a int4 è troppo lossy per predire con accuratezza: i draft sbagliano quasi
sempre, quindi la speculazione non si attiva mai.
Esperimento: testa MTP a int8
Rigenerata SOLO la testa a precisione più alta (--mtp --ebits 8), il resto del modello
invariato (la testa è un solo layer, costo di memoria trascurabile):
MTP acceptance 59% (72/123) <-- era 4% a int4 / was 4% at int4
113 token in 130.14s (0.87 tok/s) | speculazione 2.76 token/forward
L'accettazione è balzata da 4% a 59% e la speculazione da 1.01 a 2.76 token/forward:
la testa int4 era davvero troppo lossy per fare draft.
Secondo datapoint, prosa ("Explain how a hash map works."):
MTP acceptance 39% (69/177) | speculazione 2.17 token/forward
128 token in 202.56s (0.63 tok/s) | hit 15% | expert/token 1183 (baseline ~660)
Nota onesta e importante: su questa macchina il tok/s con MTP peggiora su cache
fredda (0.63–0.87 vs ~1.0 senza MTP). Motivo: ogni forward speculativo verifica ~2–3 token,
e quei token di draft instradano ai loro expert → il forward tocca molti più expert
(expert/token ~660 → ~1024–1183). Su un motore disk-bound con cache piccola/fredda questo
amplificazione del caricamento expert costa più di quanto si risparmi facendo meno
forward. L'accettazione è sana (39–59%): il collo di bottiglia è lo streaming degli expert,
non la qualità del draft. Da notare: il motore disabilita il draft se l'accettazione è bassa,
ma non se una buona accettazione rallenta comunque per via dell'amplificazione su disco.
Si potrebbe pensare che il guadagno serva solo con cache calda e grande (working set
speculativo residente) — ma l'A/B a caldo qui sotto mostra che anche così MTP perde; su
disco lento (~1 GB/s) l'effetto negativo sarebbe ancora più marcato.
A/B pulito (stesso prompt "count to fifty", stessa cache fredda cap=8, solo MTP cambia):
MTP=0 : 0.85 tok/s | hit 36% | expert/token 738 | 1.00 tok/fw
MTP=1 : 0.61 tok/s | hit 24% | expert/token 1024 | 2.76 tok/fw | accettazione 59%
MTP è ~28% più lento a parità di tutto: la speculazione gonfia il working set degli
expert (+39% expert/token) e abbassa la hit-rate (36%→24%), quindi i download da disco
superano il risparmio di forward. Con 59% di accettazione, e comunque perde.
A/B a CALDO (chat, cap=48, cache scaldata con turni ripetuti via :reset, hit ~71–78%):
MTP=0 : 0.61 tok/s (hit 78%)
MTP=1 : 0.47 tok/s (hit 71%)
Anche a caldo MTP è ~23% più lento. Qui il disco non c'entra più (expert in cache): il
decode è matmul/banda-bound, e la speculazione verifica ~3 token per forward, quindi
AUMENTA il matmul per forward invece di ridurlo — risparmia solo il numero di forward, che
non è il collo di bottiglia. Conclusione: su questo motore MoE in streaming la testa MTP
funziona (accettazione sana a int8) ma è un calo netto, sia a freddo sia a caldo.
Suggerimento
Due punti distinti:
Precisione della testa. A int4 la speculazione non si aggancia mai (testa peso morto);
a int8 sì (accettazione ~40–60%). Se MTP deve esistere, la testa andrebbe int8 di
default (o almeno documentare --ebits 8 per --mtp). La testa è un solo layer: costo
RAM/disco minimo.
Convenienza su questo motore. Anche con testa int8 e accettazione sana, la speculazione
è un calo netto a freddo e a caldo su CPU + streaming MoE (matmul-bound): aumenta il
matmul per forward invece di ridurlo. Quindi forse conviene MTP OFF di default su questo
tipo di hardware, e/o una guardia che spenga il draft se rallenta nonostante buona
accettazione (oggi la guardia scatta solo per accettazione bassa). Su HW diverso
(forward-dispatch bound) potrebbe invece aiutare — vale la pena misurarlo.
🇬🇧 English
Environment
macOS, Apple Silicon (M-series), 128 GB unified memory, internal SSD (~18 GB/s random read, measured with iobench).
GLM-5.2-FP8 converted with defaults (--ebits 4 --io-bits 8); MTP head added with convert_fp8_to_int4.py --mtp (so also int4).
Greedy decode (TOPK=0 TOPP=0).
Observation
The MTP head loads fine (MTP ATTIVA (draft=3)), but draft acceptance is near zero, even
on trivially predictable text, so the adaptive guard disables speculation after 24 proposals
and there is no gain (tok/fw ≈ 1.0).
Prose ("Explain how a hash map works."):
MTP acceptance 0% (0/24) -> draft disabled
128 tokens in 139.86s (0.92 tok/s) | speculation 1.01 tokens/forward
Maximally predictable text ("Count from one to fifty: one, two, three, ..."):
MTP acceptance 4% (1/24) -> draft disabled
113 tokens in 117.64s (0.96 tok/s) | speculation 1.01 tokens/forward
4% on counting to fifty is surprisingly low — with greedy decode a good draft head should
predict the next token far more often.
Hypothesis
The int4 MTP head is too lossy to predict accurately: drafts almost always miss, so
speculation never engages.
Experiment: int8 MTP head
Regenerated ONLY the head at higher precision (--mtp --ebits 8), rest of the model
unchanged (the head is a single layer, so the memory cost is negligible):
MTP acceptance 59% (72/123) <-- was 4% at int4
113 tokens in 130.14s (0.87 tok/s) | speculation 2.76 tokens/forward
Acceptance jumped from 4% to 59% and speculation from 1.01 to 2.76 tokens/forward:
the int4 head really was too lossy to draft.
Second datapoint, prose ("Explain how a hash map works."):
MTP acceptance 39% (69/177) | speculation 2.17 tokens/forward
128 tokens in 202.56s (0.63 tok/s) | hit 15% | experts/token 1183 (baseline ~660)
Honest and important note: on this machine tok/s with MTP actually gets worse on a
cold cache (0.63–0.87 vs ~1.0 without MTP). Reason: each speculative forward verifies ~2–3
tokens, and those draft tokens route to their own experts → the forward touches many more
experts (experts/token ~660 → ~1024–1183). On a disk-bound engine with a small/cold cache
this expert-load amplification costs more than the fewer-forwards saving. Acceptance is
healthy (39–59%): the bottleneck is expert streaming, not draft quality. Note the engine
disables draft when acceptance is low, but not when good acceptance still slows things
down via that amplification on a disk-bound run. One might expect the gain to appear only with a warm, large cache (speculative working set
resident) — but the warm A/B below shows even that loses; on a slow disk (~1 GB/s) the
negative effect would be even more pronounced.
Clean A/B (same "count to fifty" prompt, same cold cap=8 cache, only MTP toggled):
MTP=0 : 0.85 tok/s | hit 36% | experts/token 738 | 1.00 tok/fw
MTP=1 : 0.61 tok/s | hit 24% | experts/token 1024 | 2.76 tok/fw | acceptance 59%
MTP is ~28% slower with everything else equal: speculation inflates the expert working
set (+39% experts/token) and drops hit-rate (36%→24%), so disk reads outweigh the saved
forwards. 59% acceptance and it still loses.
WARM A/B (chat, cap=48, cache warmed over repeated turns via :reset, hit ~71–78%):
MTP=0 : 0.61 tok/s (hit 78%)
MTP=1 : 0.47 tok/s (hit 71%)
Even warm, MTP is ~23% slower. Disk is out of the picture now (experts are cached): decode
is matmul/bandwidth-bound, and speculation verifies ~3 tokens per forward, so it increases
matmul per forward rather than reducing it — it only saves the number of forwards, which was
never the bottleneck. Conclusion: on this CPU streaming-MoE engine the MTP head works
(healthy acceptance at int8) but is a net loss, both cold and warm.
Suggestion
Two separate points:
Head precision. At int4 speculation never engages (head is dead weight); at int8 it
does (~40–60% acceptance). If MTP is to exist at all, the head should be int8 by default
(or at least document --ebits 8 for --mtp). The head is a single layer, so the RAM/disk
cost is minimal.
Whether it's worth it on this engine. Even with an int8 head and healthy acceptance,
speculation is a net loss cold and warm on CPU + streaming MoE (matmul-bound): it
increases matmul per forward instead of reducing it. So it may be worth MTP OFF by
default on this class of hardware, and/or a guard that disables draft when it slows
things down despite good acceptance (today the guard only triggers on low acceptance). On
different HW (forward-dispatch bound) it might help instead — worth measuring.
🇮🇹 Italiano
Ambiente
macOS, Apple Silicon (M-series), 128 GB unified memory, SSD interno (~18 GB/s random read misurato con iobench).
GLM-5.2-FP8 convertito con i default (--ebits 4 --io-bits 8); testa MTP aggiunta con convert_fp8_to_int4.py --mtp (quindi anch'essa int4).
Decode greedy (TOPK=0 TOPP=0).
Osservazione
La testa MTP viene caricata correttamente (MTP ATTIVA (draft=3)), ma l'accettazione dei
draft è quasi nulla, anche su testo banalmente prevedibile, quindi la guardia adattiva
disabilita la speculazione dopo 24 proposte e non si ottiene alcun guadagno (tok/fw ≈ 1.0).
Prosa ("Explain how a hash map works."):
MTP acceptance 0% (0/24) -> draft disattivati
128 token in 139.86s (0.92 tok/s) | speculazione 1.01 token/forward
Testo massimamente prevedibile ("Count from one to fifty: one, two, three, ..."):
MTP acceptance 4% (1/24) -> draft disattivati
113 token in 117.64s (0.96 tok/s) | speculazione 1.01 token/forward
4% su un conteggio da 1 a 50 è sorprendentemente basso: con decode greedy una buona testa
draft dovrebbe azzeccare il token successivo molto più spesso.
Ipotesi
La testa MTP a int4 è troppo lossy per predire con accuratezza: i draft sbagliano quasi
sempre, quindi la speculazione non si attiva mai.
Esperimento: testa MTP a int8
Rigenerata SOLO la testa a precisione più alta (--mtp --ebits 8), il resto del modello
invariato (la testa è un solo layer, costo di memoria trascurabile):
MTP acceptance 59% (72/123) <-- era 4% a int4 / was 4% at int4
113 token in 130.14s (0.87 tok/s) | speculazione 2.76 token/forward
L'accettazione è balzata da 4% a 59% e la speculazione da 1.01 a 2.76 token/forward:
la testa int4 era davvero troppo lossy per fare draft.
Secondo datapoint, prosa ("Explain how a hash map works."):
MTP acceptance 39% (69/177) | speculazione 2.17 token/forward
128 token in 202.56s (0.63 tok/s) | hit 15% | expert/token 1183 (baseline ~660)
Nota onesta e importante: su questa macchina il tok/s con MTP peggiora su cache
fredda (0.63–0.87 vs ~1.0 senza MTP). Motivo: ogni forward speculativo verifica ~2–3 token,
e quei token di draft instradano ai loro expert → il forward tocca molti più expert
(expert/token ~660 → ~1024–1183). Su un motore disk-bound con cache piccola/fredda questo
amplificazione del caricamento expert costa più di quanto si risparmi facendo meno
forward. L'accettazione è sana (39–59%): il collo di bottiglia è lo streaming degli expert,
non la qualità del draft. Da notare: il motore disabilita il draft se l'accettazione è bassa,
ma non se una buona accettazione rallenta comunque per via dell'amplificazione su disco.
Si potrebbe pensare che il guadagno serva solo con cache calda e grande (working set
speculativo residente) — ma l'A/B a caldo qui sotto mostra che anche così MTP perde; su
disco lento (~1 GB/s) l'effetto negativo sarebbe ancora più marcato.
A/B pulito (stesso prompt "count to fifty", stessa cache fredda cap=8, solo MTP cambia):
MTP=0 : 0.85 tok/s | hit 36% | expert/token 738 | 1.00 tok/fw
MTP=1 : 0.61 tok/s | hit 24% | expert/token 1024 | 2.76 tok/fw | accettazione 59%
MTP è ~28% più lento a parità di tutto: la speculazione gonfia il working set degli
expert (+39% expert/token) e abbassa la hit-rate (36%→24%), quindi i download da disco
superano il risparmio di forward. Con 59% di accettazione, e comunque perde.
A/B a CALDO (chat, cap=48, cache scaldata con turni ripetuti via :reset, hit ~71–78%):
MTP=0 : 0.61 tok/s (hit 78%)
MTP=1 : 0.47 tok/s (hit 71%)
Anche a caldo MTP è ~23% più lento. Qui il disco non c'entra più (expert in cache): il
decode è matmul/banda-bound, e la speculazione verifica ~3 token per forward, quindi
AUMENTA il matmul per forward invece di ridurlo — risparmia solo il numero di forward, che
non è il collo di bottiglia. Conclusione: su questo motore MoE in streaming la testa MTP
funziona (accettazione sana a int8) ma è un calo netto, sia a freddo sia a caldo.
Suggerimento
Due punti distinti:
Precisione della testa. A int4 la speculazione non si aggancia mai (testa peso morto);
a int8 sì (accettazione ~40–60%). Se MTP deve esistere, la testa andrebbe int8 di
default (o almeno documentare --ebits 8 per --mtp). La testa è un solo layer: costo
RAM/disco minimo.
Convenienza su questo motore. Anche con testa int8 e accettazione sana, la speculazione
è un calo netto a freddo e a caldo su CPU + streaming MoE (matmul-bound): aumenta il
matmul per forward invece di ridurlo. Quindi forse conviene MTP OFF di default su questo
tipo di hardware, e/o una guardia che spenga il draft se rallenta nonostante buona
accettazione (oggi la guardia scatta solo per accettazione bassa). Su HW diverso
(forward-dispatch bound) potrebbe invece aiutare — vale la pena misurarlo.
🇬🇧 English
Environment
macOS, Apple Silicon (M-series), 128 GB unified memory, internal SSD (~18 GB/s random read, measured with iobench).
GLM-5.2-FP8 converted with defaults (--ebits 4 --io-bits 8); MTP head added with convert_fp8_to_int4.py --mtp (so also int4).
Greedy decode (TOPK=0 TOPP=0).
Observation
The MTP head loads fine (MTP ATTIVA (draft=3)), but draft acceptance is near zero, even
on trivially predictable text, so the adaptive guard disables speculation after 24 proposals
and there is no gain (tok/fw ≈ 1.0).
Prose ("Explain how a hash map works."):
MTP acceptance 0% (0/24) -> draft disabled
128 tokens in 139.86s (0.92 tok/s) | speculation 1.01 tokens/forward
Maximally predictable text ("Count from one to fifty: one, two, three, ..."):
MTP acceptance 4% (1/24) -> draft disabled
113 tokens in 117.64s (0.96 tok/s) | speculation 1.01 tokens/forward
4% on counting to fifty is surprisingly low — with greedy decode a good draft head should
predict the next token far more often.
Hypothesis
The int4 MTP head is too lossy to predict accurately: drafts almost always miss, so
speculation never engages.
Experiment: int8 MTP head
Regenerated ONLY the head at higher precision (--mtp --ebits 8), rest of the model
unchanged (the head is a single layer, so the memory cost is negligible):
MTP acceptance 59% (72/123) <-- was 4% at int4
113 tokens in 130.14s (0.87 tok/s) | speculation 2.76 tokens/forward
Acceptance jumped from 4% to 59% and speculation from 1.01 to 2.76 tokens/forward:
the int4 head really was too lossy to draft.
Second datapoint, prose ("Explain how a hash map works."):
MTP acceptance 39% (69/177) | speculation 2.17 tokens/forward
128 tokens in 202.56s (0.63 tok/s) | hit 15% | experts/token 1183 (baseline ~660)
Honest and important note: on this machine tok/s with MTP actually gets worse on a
cold cache (0.63–0.87 vs ~1.0 without MTP). Reason: each speculative forward verifies ~2–3
tokens, and those draft tokens route to their own experts → the forward touches many more
experts (experts/token ~660 → ~1024–1183). On a disk-bound engine with a small/cold cache
this expert-load amplification costs more than the fewer-forwards saving. Acceptance is
healthy (39–59%): the bottleneck is expert streaming, not draft quality. Note the engine
disables draft when acceptance is low, but not when good acceptance still slows things
down via that amplification on a disk-bound run. One might expect the gain to appear only with a warm, large cache (speculative working set
resident) — but the warm A/B below shows even that loses; on a slow disk (~1 GB/s) the
negative effect would be even more pronounced.
Clean A/B (same "count to fifty" prompt, same cold cap=8 cache, only MTP toggled):
MTP=0 : 0.85 tok/s | hit 36% | experts/token 738 | 1.00 tok/fw
MTP=1 : 0.61 tok/s | hit 24% | experts/token 1024 | 2.76 tok/fw | acceptance 59%
MTP is ~28% slower with everything else equal: speculation inflates the expert working
set (+39% experts/token) and drops hit-rate (36%→24%), so disk reads outweigh the saved
forwards. 59% acceptance and it still loses.
WARM A/B (chat, cap=48, cache warmed over repeated turns via :reset, hit ~71–78%):
MTP=0 : 0.61 tok/s (hit 78%)
MTP=1 : 0.47 tok/s (hit 71%)
Even warm, MTP is ~23% slower. Disk is out of the picture now (experts are cached): decode
is matmul/bandwidth-bound, and speculation verifies ~3 tokens per forward, so it increases
matmul per forward rather than reducing it — it only saves the number of forwards, which was
never the bottleneck. Conclusion: on this CPU streaming-MoE engine the MTP head works
(healthy acceptance at int8) but is a net loss, both cold and warm.
Suggestion
Two separate points:
Head precision. At int4 speculation never engages (head is dead weight); at int8 it
does (~40–60% acceptance). If MTP is to exist at all, the head should be int8 by default
(or at least document --ebits 8 for --mtp). The head is a single layer, so the RAM/disk
cost is minimal.
Whether it's worth it on this engine. Even with an int8 head and healthy acceptance,
speculation is a net loss cold and warm on CPU + streaming MoE (matmul-bound): it
increases matmul per forward instead of reducing it. So it may be worth MTP OFF by
default on this class of hardware, and/or a guard that disables draft when it slows
things down despite good acceptance (today the guard only triggers on low acceptance). On
different HW (forward-dispatch bound) it might help instead — worth measuring.