Sparkulator-Laguna-XS-2.1
A W4A16-quantized DFlash speculator for
poolside/Laguna-XS-2.1-NVFP4,
tuned for memory-bandwidth-bound hardware β specifically a single NVIDIA DGX Spark
(GB10, sm_121) serving Laguna-XS 2.1 on one node.
It is a quantization of poolside/Laguna-XS-2.1-DFlash.
The weights were not retrained β only their precision changed.
Measured on a DGX Spark: +8.1% decode throughput at a 2K code prompt, with draft acceptance unchanged (65.0% β 65.5%).
Why this exists
Speculative decoding is verified: at temperature 0 a draft token survives only if it equals the target's argmax, otherwise the target's own token is used. So the draft cannot change what the model says β it can only change how fast it says it. That makes the draft a free target for aggressive compression: the only thing at risk is acceptance rate.
On a DGX Spark the binding constraint is memory bandwidth, and the drafter is essentially
a weight read repeated k times per verification step. Shrinking it 2.34Γ shrinks that
read.
Target assignment
Use this draft with an NVFP4 Laguna-XS 2.1 target. DFlash drafts ship no lm_head of
their own β they share the target's and are calibrated against its hidden states β so a
draft is specific to the target it was built for. This one was built from, and measured
against, poolside/Laguna-XS-2.1-NVFP4. (Unlike Laguna-S, poolside publishes a single
Laguna-XS-2.1-DFlash rather than per-dtype variants.)
How it was made
Data-free group-wise symmetric RTN (group size 128) applied directly to the raw
safetensors, emitting a standard compressed-tensors pack-quantized checkpoint that
vLLM loads through its marlin W4A16 path. No calibration data, no GPU, no model class.
| Quantized | layers.{0..4}.mlp.{gate,up,down}_proj, layers.{0..4}.self_attn.o_proj, fc β 21 tensors |
| Left BF16 | self_attn.qkv_proj, self_attn.g_proj, all norms |
| Size | 0.861 GiB β 0.368 GiB (42.7%) |
| Mean relative weight error | 0.099 β 0.114 per tensor (worst: mlp.down_proj) |
qkv_proj stays BF16 deliberately: vLLM's DFlash proposer reads qkv_proj.weight
directly when it precomputes the context-KV buffer, with no dequantization path, so
quantizing it fails the load with
AttributeError: 'QKVParallelLinear' object has no attribute 'weight'.
Measured results
One DGX Spark (GB10, 128 GB unified), vLLM 0.25.1, target poolside/Laguna-XS-2.1-NVFP4,
num_speculative_tokens=6, --max-num-seqs 2, KV pinned to 12 GiB, temperature 0,
concurrency 1, thinking off, code-continuation workload, warm. Both arms measured
back-to-back in the same session with identical flags β only the draft differs.
| Prompt | BF16 draft | This draft (W4A16) | Ξ |
|---|---|---|---|
| 512 tok | 131.15 tok/s | 136.97 tok/s | +4.4% |
| 2,048 tok | 123.52 tok/s | 133.55 tok/s | +8.1% |
| 8,192 tok | 114.54 tok/s | 121.19 tok/s | +5.8% |
Acceptance over the measured window (spec_decode_num_accepted_tokens_total /
_num_draft_tokens_total from /metrics):
| BF16 draft | This draft | |
|---|---|---|
| Overall acceptance | 65.0% | 65.5% |
| Per position (0β5) | 0.90 / 0.80 / 0.70 / 0.60 / 0.49 / 0.43 | 0.90 / 0.82 / 0.72 / 0.62 / 0.53 / 0.44 |
Acceptance is not degraded by the quantization β the difference is inside run-to-run noise. Weights loaded: 21.14 GiB (BF16 draft) β 20.64 GiB, i.e. exactly the 0.50 GiB the quantization saves.
Serving it
hf download sapidlabs/Sparkulator-Laguna-XS-2.1 \
--local-dir ~/models/hf/Sparkulator-Laguna-XS-2.1
VLLM_USE_DEEP_GEMM=0 vllm serve ~/models/hf/Laguna-XS-2.1-NVFP4 \
--served-model-name laguna-nvfp4 \
--max-model-len 262144 \
--gpu-memory-utilization 0.5 \
--kv-cache-memory-bytes 12884901888 \
--max-num-seqs 2 \
--max-num-batched-tokens 8192 \
--speculative-config '{"method":"dflash","model":"'$HOME'/models/hf/Sparkulator-Laguna-XS-2.1","num_speculative_tokens":6}' \
--host 0.0.0.0 --port 8000
k=6 is the measured peak for this target on a Spark β decode is not monotonic in k.
One patch you need
vLLM 0.25.1's laguna_dflash.py calls self.quant_config.get_cache_scale(name)
unconditionally while loading. That method is FP8-only; CompressedTensorsConfig does not
have it, so a W4A16 draft dies on load. Guard it (on every node β each has its own
site-packages):
# vllm/model_executor/models/laguna_dflash.py
if self.quant_config is not None and hasattr(self.quant_config, "get_cache_scale") and (
scale_name := self.quant_config.get_cache_scale(name)
):
If you switch between drafts of different quantization without a fresh
VLLM_CACHE_ROOT, vLLM reloads a stale compiled graph and dies with
KeyError: 'weight_packed' β the compile cache does not re-key on draft quantization.
Credit
All the modelling work is poolside's. poolside/Laguna-XS-2.1-DFlash is their speculator
for their model; this repo only changes its numeric precision so it reads fewer bytes per
token on a bandwidth-bound box. This is not an official poolside release.
Built as part of How To Spark β see the Laguna-XS 2.1 NVFP4 recipe.
- Downloads last month
- 22