CoolFace
Modelpublic

Doopeworld/Qwen3.8-27B-DSpark-vLLM

sourceHugging Faceotherupdated 1mo agoView on Hugging Face
15likes9kdownloads
Model Card

Qwen3.8-27B-DSpark — vLLM-ready

This is `RadixArk/Qwen3.8-27B-DSpark` with one line changed in `config.json` so that vLLM loads it.

The weights are byte-identical to the original. All credit for the drafter goes to RadixArk — this repo exists only so the checkpoint works with vLLM without a manual edit.

What was changed

diff
- "architectures": ["DSparkDraftModel"]
+ "architectures": ["Qwen3DSparkModel"]

That's it.

Why it was needed

vLLM already supports this model natively — vllm/model_executor/models/qwen3_dspark.py plus a DSpark speculator have been in main for a while. But the registry has two DSpark entries:

python
"DSparkDraftModel": ("vllm.models.deepseek_v4", "DSparkDeepseekV4ForCausalLM"),
"Qwen3DSparkModel": ("qwen3_dspark", "Qwen3DSparkForCausalLM"),

The original checkpoint declares DSparkDraftModel, which routes to the DeepSeek-V4 class. vllm/config/speculative.py then rewrites model_type to deepseek_v4, and loading fails. Declaring Qwen3DSparkModel selects the Qwen3 implementation instead.

Every other field the original ships — dflash_config (target_layer_ids, mask_token_id, projector_type), markov_rank, enable_confidence_head, confidence_head_with_markov, layer_types, head_dim — is already exactly what Qwen3DSparkForCausalLM expects.

Usage

bash
vllm serve /path/to/Qwen3.8-27B-GPTQ-Int4 \
  --dtype bfloat16 \
  --max-model-len 16384 \
  --max-num-seqs 16 \
  --gpu-memory-utilization 0.90 \
  --kv-cache-dtype fp8 \
  --block-size 64 \
  --trust-remote-code \
  --speculative-config '{
    "method": "dspark",
    "model": "/path/to/Qwen3.8-27B-DSpark-vLLM",
    "num_speculative_tokens": 7,
    "draft_sample_method": "probabilistic"
  }'

Measured results

Intel Arc Pro B70 32 GB, single card, vLLM 0.26.1rc1.dev799 XPU backend, V2 model runner. Target: Qwen3.8-27B GPTQ-Int4 (W4A16). Benchmarked with llama-benchy --pp 4096.

Configt/s (tg32)Mean acceptance
no speculation28
Qwen3.8 built-in MTP, k=250~2.8
DSpark, k=7, greedy421.94 – 2.67
DSpark, k=7, probabilistic522.45 – 2.79

Per-position acceptance at k=7 (probabilistic): 0.76, 0.45, 0.31, 0.14, 0.10, 0.02, 0.00

Tuning notes

Use `"draft_sample_method": "probabilistic"`. It measured ~23% faster than greedy on otherwise identical settings (52 vs 42 t/s). Greedy exact-match is a much harsher acceptance criterion than the sampling the published figures used.

Do not shrink the block, even though the acceptance curve says you should. Positions 6 and 7 accept ~2% and 0%, so trimming looks obviously correct. It isn't — k=4 and k=6 both measured worse than k=7. Per-step overhead dominates per-drafted-token cost, so amortising over more accepted tokens wins. Measure before trimming.

`enable_adaptive_verification` does not work with Qwen3.8. Its GDN linear-attention layers use GDNAttentionBackend, which vLLM rejects at startup:

ValueError: Adaptive verification trims verification requests on device, which
the GDNAttentionBackend attention backend does not support.

Architectural, not a misconfiguration — so the confidence head in this checkpoint currently goes unused under vLLM.

Acceptance is strongly workload-dependent

Measured in a standalone harness against the FP8 target, greedy exact-match:

Prompt typeMean acceptance length
general prose / instruction2.18
step-by-step math reasoning4.79

This matches what the SGLang team reported (≈5.2 on gsm8k vs ≈2.9 on poetry). A single benchmark figure for this drafter is close to meaningless — reasoning-heavy traffic does substantially better than a generic tg32 benchmark suggests.

Target quantisation

The drafter reads target hidden states at layers 4/16/28/40/52. Those are bf16 activations regardless of how the target's weights are stored, so FP8, GPTQ-int4, AWQ and MXFP4 targets should all load.

Acceptance is a separate question: this drafter was trained against Qwen3.8-27B-FP8, and heavier quantisation perturbs the very hidden states it learned to read. GPTQ-int4 measured 2.45–2.79 here, but that isn't a like-for-like comparison with the published 3.39 (different sampling method and workloads). MXFP4 and AWQ are untested.

Limitations

  • Verified on Intel Arc / XPU only. Nothing in the change is XPU-specific and CUDA should behave the same or better, but this is untested.
  • Qwen3.8-27B only. The drafter's fc expects 5 × 5120 and taps layer indices up to 52, so other sizes in the family will not load.
  • The FP8 target does not fit a single 32 GB card alongside the 2.7 GB drafter — no room is left for KV cache. Int4 leaves comfortable headroom.

Credit

All model weights and the DSpark method belong to RadixArk and the DSpark / SpecForge authors. This repo contributes a one-line config change and benchmark data on Intel Arc.