sapidlabs/Sparkulator-Laguna-S-2.1-NVFP4
Sparkulator-Laguna-S-2.1-NVFP4 (W4A16 DFlash draft for the NVFP4 target)
A W4A16-quantized DFlash speculator for `poolside/Laguna-S-2.1`, tuned for single-user speculative decoding on the NVIDIA DGX Spark (GB10, sm_121).
It is a group-128 symmetric-int4 (W4A16, compressed-tensors pack-quantized) quant of poolside's `Laguna-S-2.1-DFlash-NVFP4` draft. Draft weights shrink 2.08 GiB → 0.82 GiB (~2.5×); measured resident cost inside vLLM falls from 69.34 GiB → 68.08 GiB of total model memory, i.e. 1.26 GiB handed back.
⚠️ Target precision matters — use this one with the NVFP4 target
DFlash drafts ship no `lm_head` of their own — they share the target's and are calibrated against the target's hidden states — so a draft only works with the target precision it was built for. Cross-pairing gives 0% acceptance (a silent failure: output stays correct, decode drops below the no-draft baseline).
Measured
1× DGX Spark, vLLM 0.25.1, `poolside/Laguna-S-2.1-NVFP4` target (71.9 GB, one node), k=6, `--max-num-seqs 4`, KV pinned to 12 GiB, temp 0, concurrency 1, warm, thinking off, code-continuation workload, 12 repeats per cell. Both arms were run on both Sparks with the arm order counterbalanced (Spark-1 ran BF16 first, Spark-2 ran W4A16 first), on 2026-07-27:
All six comparisons favour the quantized draft, against a per-request stdev of 1.7–6.0%. Pooled, it is worth roughly +5% single-stream decode.
Acceptance is unchanged, which is the point — spec-decode is verified, so the draft can only cost speed, never quality, and the gate is whether the quant damaged the draft's guesses:
(Warm-up requests were subtracted from the /metrics counters before differencing — they accept far worse than real work and otherwise drag the ratio down.)
Against the same recipe's no-draft baseline (18.9 tok/s at a 2,048-token prompt), this draft is worth about 2.4×.
How it was made
Data-free group-128 symmetric RTN over the raw safetensors — no calibration, no model class, no GPU — emitting a standard compressed-tensors pack-quantized checkpoint that vLLM loads through its marlin path.
- Quantized: every layer's
mlp.{gate,up,down}_proj,self_attn.o_proj, and the DFlashfcencoder. - Left BF16:
self_attn.qkv_proj— vLLM's_build_context_kv_buffersreadsqkv_proj.weightdirectly with no dequant path — and the tiny softplus gateself_attn.g_proj. - The
ignorelist is written asre:regexes, because vLLM matches ignore entries against the prefixed module name (model.layers.N…); literal names silently miss and the layer gets quantized anyway, thenKeyErrors on.weight.
This draft has 6 layers, which is why data-free RTN is enough: quantization error has somewhere to wash out. A 1-layer EAGLE3-style head given the same treatment loses several points of acceptance.
Serving on a DGX Spark (vLLM 0.25.1)
vllm serve poolside/Laguna-S-2.1-NVFP4 \
--max-model-len 262144 \
--gpu-memory-utilization 0.85 \
--kv-cache-memory-bytes 12884901888 \
--max-num-seqs 4 --max-num-batched-tokens 8192 \
--speculative-config '{"method":"dflash","model":"sapidlabs/Sparkulator-Laguna-S-2.1-NVFP4","num_speculative_tokens":6}'*One vLLM patch is needed for a quantized DFlash draft to load* (0.25.1 assumes an unquantized/FP8 draft), on every node — in vllm/model_executor/models/laguna_dflash.py, guard the FP8-only get_cache_scale call:
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)):CompressedTensorsConfig does not implement that method. Keeping qkv_proj in BF16 (as this checkpoint does) is the second half of the fix.
If you A/B two drafts of different quantization on one node, point VLLM_CACHE_ROOT at a fresh directory per variant, or serve --enforce-eager — vLLM's compile cache does not re-key on draft quantization and you will hit KeyError: 'weight_packed'.
License & attribution
Derived from poolside/Laguna-S-2.1-DFlash-NVFP4; released under the same OpenMDW-1.1. All credit for the base model and the DFlash speculator design to poolside. This is not an official poolside release — it only re-encodes their draft weights to 4-bit for the DGX Spark. Built and measured by How To Spark.
