Sparkulator-GLM-5.2
A W4A16-quantized DSpark speculator for zai-org/GLM-5.2-FP8, tuned for
memory-bandwidth-bound hardware β specifically a two-node NVIDIA DGX Spark
(GB10) cluster running GLM-5.2 at TP2.
It is a quantization of RedHatAI/GLM-5.2-speculator.dspark
(epoch-3). The weights were not retrained β only their precision changed.
Measured: +8.7% decode throughput at no measurable cost in draft acceptance.
Why this exists
On a DGX Spark the binding constraint is memory bandwidth, and a speculative drafter is essentially a weight read: it streams its own parameters once per speculative cycle. Direct profiling put the drafter at 15.88 ms of an ~89 ms cycle β around 18% of decode time spent reading 7 GiB of BF16 weights.
Quantizing the drafter's hot weights to 4 bits cuts that read ~4Γ. Because speculative decoding is lossless, a worse drafter cannot corrupt output β it can only propose tokens that get rejected. So the only thing quantization can cost is acceptance, and that is the number to watch.
Results
Measured on 2Γ DGX Spark (GB10, 121 GiB unified LPDDR each), TP2 over 200 Gb
ConnectX/RoCE, GLM-5.2 753B MoE, p2048/o256/c1, 15 repeats per arm measured
back-to-back in one session.
| BF16 (epoch-3) | this model (W4A16) | |
|---|---|---|
| decode, mean | 20.21 Β± 0.35 tok/s | 21.97 Β± 0.51 tok/s |
| decode, median | 20.09 | 21.72 |
| acceptance | 0.5166 | 0.5084 |
| acceptance @+0 | 0.6460 | 0.6345 |
| acceptance @+1 | 0.3872 | 0.3822 |
| tokens / verify | 2.0331 | 2.0167 |
| checkpoint | 7.09 GiB | 4.57 GiB |
- Throughput: +8.7%, 2.8Ο, 95% CI +0.55β¦+2.97 tok/s.
- Acceptance: β0.008, 0.7Ο on ~3,800 draft tokens per arm β not significant.
- Speculative cycle time fell ~8.8 ms, against ~7.9 ms predicted from the byte reduction alone. For a bandwidth-bound drafter the naive weight-read model turned out to be close to right.
K=2 and K=3 measured equivalent (+0.5%, 0.1Ο); K=2 is the recommended
default. On the BF16 drafter K=2 was clearly better than K=3, so cheaper
drafting did shift the optimum deeper β just not far enough to change the answer.
What is quantized
Symmetric group-wise RTN, group size 128, compressed-tensors
pack-quantized, served through marlin kernels.
| tensor group | precision | why |
|---|---|---|
layers.*.self_attn.{q,k,v,o}_proj |
W4A16 | hot, 0.94 GiB |
layers.*.mlp.{gate,up,down}_proj |
W4A16 | hot, 2.11 GiB |
fc |
W4A16 | hot, 0.35 GiB |
embed_tokens |
BF16 | a gather, not a matmul β quantizing buys no speed |
lm_head |
BF16 | see below |
markov_head, confidence_head |
BF16 | low-rank / tiny, sensitive |
lm_head is deliberately left dense. It is 1.77 GiB and is read every
draft step, so it looks like the biggest remaining win. It is not: quantizing it
was measured at +0.22 tok/s (~0.2Ο, i.e. nothing) while acceptance fell to 0.4885
β 2.5Ο below BF16. It has the highest quantization error of any tensor in the
model (rel_err 0.1196) and it emits the draft logits directly, so the bytes saved
come straight back as rejected tokens. Don't.
Requirements β read this before downloading
This checkpoint will not run correctly on stock vLLM. It needs the DSpark
port and the quantized-drafter fixes from
Sapid-Labs/vLLM-Moet (branch
spark-gb10, see dspark-port/).
Two code paths in qwen3_dflash.py bypassed quantized dispatch by touching
.weight directly. Under a quantized checkpoint that attribute either does not
exist (marlin stores weight_packed) or is transposed. One of them fails
loudly; the other silently computes garbage. Both are fixed in that port.
git clone -b spark-gb10 https://github.com/Sapid-Labs/vLLM-Moet.git
./vLLM-Moet/dspark-port/apply.sh /path/to/venv/lib/python3.12/site-packages/vllm
Serving (both nodes, Ray cluster up, speculator at the same path on each):
--speculative-config '{"method": "dspark",
"model": "<path to this repo>",
"num_speculative_tokens": 2}'
Gotcha: vLLM's torch.compile cache key does not include the drafter's
quantization. Swapping a BF16 drafter for this one without clearing
~/.cache/vllm/torch_compile_cache/<hash>/rank_*/eagle_head (and the matching
torch_aot_compile/<sha>/) reloads a graph compiled against the BF16 parameter
list and dies with ValueError: too many values to unpack. Clear those, or set
VLLM_DISABLE_COMPILE_CACHE=1.
Honest scope
- The numbers above are for one hardware/serving configuration (2Γ DGX Spark, TP2, this GLM-5.2 build with NVFP4 big-3 attention + 2-bit MoE expert planes at top-k 4). The win comes from being memory-bandwidth-bound; on a bandwidth-rich GPU a 4-bit drafter may buy little or nothing.
- Quantization is data-free RTN β no calibration set was used. AWQ/GPTQ were not attempted. Acceptance held, so there may be little left to recover, but the ceiling is untested.
- Acceptance was measured over ~3,800 draft tokens per arm on benchmark prompts, not on a task suite. It is a proposal-quality metric, not a quality metric β greedy speculative decoding is lossless, so output quality is unchanged by construction.
- Absolute throughput on this stack varies day to day by well over 10%. Only same-session paired comparisons are meaningful; every number here is from one session.
Reproducing the quantization
Produced directly from the base checkpoint's safetensors β the DSpark
architecture has no HF modeling class, so AutoModelForCausalLM (and therefore
llmcompressor) cannot load it. Script:
quantize_raw_w4a16.py
python3 quantize_raw_w4a16.py \
--model GLM-5.2-speculator.dspark \
--out Sparkulator-GLM-5.2 \
--targets 'layers\.\d+\.(self_attn|mlp)\..*_proj' 'fc' \
--group-size 128
Credits & license
MIT, inherited from the base model. The drafter was trained by Red Hat AI β
all model quality is theirs; this repo contributes only the quantization and the
inference fixes needed to run it. Base model: zai-org/GLM-5.2-FP8.
- Downloads last month
- 24
Model tree for sapidlabs/Sparkulator-GLM-5.2
Base model
zai-org/GLM-5.2-FP8