Sparkulator-Qwen3.6-27B

An NVFP4 re-quantization of the MTP speculative-decoding head inside nvidia/Qwen3.6-27B-NVFP4, built to make speculative decoding cheaper on an NVIDIA DGX Spark (GB10, 128 GB unified LPDDR at ~273 GB/s). It is a community artifact from How To Spark β€” not an official NVIDIA or Qwen release.

Speculative decoding is verified, so the draft cannot change what the target model outputs β€” only how fast it gets there. That is why quantizing it aggressively is safe: the only thing at risk is the draft's acceptance rate, and here acceptance held.

What this is

nvidia/Qwen3.6-27B-NVFP4 is a mixed-precision ModelOpt export: the MLPs and lm_head are NVFP4, all attention is FP8 β€” and the 15 mtp.* tensors of the native MTP draft head are left BF16, listed in the checkpoint's own ignore list. On a dense 27B target that draft is 0.791 GiB, and at the recipe's tuned num_speculative_tokens: 5 it is read five times per accepted step. That makes it roughly a fifth of the bytes moved per decode step β€” the largest un-quantized thing left in an otherwise-quantized checkpoint.

This repo holds those 8 linears re-quantized to W4A16 NVFP4, group size 16 β€” the exact scheme and on-disk layout ModelOpt already uses for the MLPs in the same file, so vLLM loads it through the existing path with no patch.

BF16 draft this draft
mtp.* block on disk 0.791 GiB 0.222 GiB (3.55x smaller)
vLLM Model loading took 20.8 GiB 20.24 GiB

Quantized: mtp.fc, mtp.layers.0.self_attn.{q,k,v,o}_proj, mtp.layers.0.mlp.{gate,up,down}_proj. Left BF16: all norms (input_layernorm, post_attention_layernorm, q_norm, k_norm, norm, pre_fc_norm_hidden, pre_fc_norm_embedding). The draft ships no lm_head or embed_tokens of its own β€” vLLM shares the target's, which are already NVFP4.

Measured on two DGX Sparks (2026-07-27)

vLLM 0.26.0, single node, k=5, --max-num-seqs 4, full 262,144-token context, greedy, concurrency 1, code workload, thinking off, warm. Counterbalanced: Spark-1 ran NVFP4-draft β†’ BF16, Spark-2 ran BF16 β†’ NVFP4. Medians over 6/10/6 repeats.

prompt node BF16 draft this draft Ξ”
512 Spark-1 35.99 tok/s 40.62 tok/s +12.9%
2,048 Spark-1 35.54 tok/s 36.94 tok/s +3.9%
8,192 Spark-1 27.12 tok/s 31.09 tok/s +14.6%
512 Spark-2 36.80 tok/s 40.24 tok/s +9.3%
2,048 Spark-2 31.81 tok/s 38.11 tok/s +19.8%
8,192 Spark-2 26.85 tok/s 29.58 tok/s +10.2%

Six of six arms favour the quantized draft. The size of the win matches the byte census: dropping 0.57 GiB from a draft that is read 5x per step removes ~2.8 GiB from a ~25 GiB step, i.e. ~11% β€” and the measured median gain is ~+10%.

Acceptance held. On a fixed 3-prompt set (identical requests in both arms): 70.60% β†’ 71.29% on Spark-1, 69.85% β†’ 67.85% on Spark-2. Over the benchmark windows: 62.00% β†’ 61.57% and 61.04% β†’ 61.92%. Data-free RTN cost this draft nothing measurable β€” the speed came from bytes, not from drafting better.

One caveat, stated plainly. A third boot of this configuration on Spark-2 produced a sustained stall β€” individual requests at 8–17 tok/s against a ~30 tok/s median, per-request sd 6.0 where every other boot measured 0.5–2.4 β€” and its medians (34.39 / 27.95 / 15.52) would have read as a large regression. It did not reproduce on a re-boot of the identical configuration and the pathology is visible in the per-request samples, so the table above uses the clean boot. If you benchmark this yourself and see numbers below the BF16 arm, re-boot the server before believing them.

Using it

Graft the tensors back onto the base checkpoint (they are a drop-in replacement for the BF16 mtp.* tensors in model-00003-of-00003.safetensors), and merge quantization_config.json into the checkpoint's config.json:

# see quantize_mtp_nvfp4.py β€” it rebuilds the whole variant directory from the
# base checkpoint in about a minute, hardlinking the two shards it does not touch.
python3 quantize_mtp_nvfp4.py \
  --src ~/models/hf/Qwen3.6-27B-NVFP4 \
  --out ~/models/hf/Qwen3.6-27B-NVFP4-MTP-NVFP4

Then serve the variant directory exactly as you would the original:

vllm serve ~/models/hf/Qwen3.6-27B-NVFP4-MTP-NVFP4 \
  --served-model-name qwen3.6-27b \
  --max-model-len 262144 \
  --gpu-memory-utilization 0.90 \
  --kv-cache-memory-bytes 15032385536 \
  --max-num-seqs 4 --max-num-batched-tokens 8192 \
  --speculative-config '{"method":"mtp","num_speculative_tokens":5}'

Confirm it actually loaded: Model loading took 20.24 GiB (not 20.8). If it reads 20.8 the packed tensors were skipped and you are running the BF16 draft.

The one thing that will bite you

This checkpoint carries its quantization config in two places β€” config.json's quantization_config and the legacy hf_quant_config.json β€” and vLLM prefers config.json. Patch only hf_quant_config.json and vLLM builds mtp.fc unquantized, then dies at load with assert self.data.shape == loaded_weight.shape. Both files must declare the 8 layers W4A16_NVFP4 and drop mtp* from the exclude/ignore list.

Credit

The base model is Qwen/Qwen3.6-27B (Apache-2.0); the mixed-precision NVFP4 export this is built from is nvidia/Qwen3.6-27B-NVFP4 by NVIDIA ModelOpt. All this repo adds is a quantization of the draft head they left in BF16, plus the measurement of what that is worth on a Spark. The deployment recipe lives at howtospark.com/recipes/qwen3-6-27b-nvfp4.

Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support

Model tree for sapidlabs/Sparkulator-Qwen3.6-27B

Base model

Qwen/Qwen3.6-27B
Quantized
(5)
this model