Muse-Glimmer-30B-Heretic · NVFP4 + DFlash (MXFP8 draft) · text-only
Download one folder and it runs. NVFP4 main model with three DFlash draft heads bundled in. Built to get 128k context and high throughput on two 16 GB consumer cards (TP2) at the same time.
Vision-capable variant →
Muse-Glimmer-30B-Heretic-VL-NVFP4-DFlash-MXFP8
Measured (2×RTX 5070Ti 16GB · sm_120 · TP2 · vLLM 0.26.1)
| Metric | Value |
|---|---|
| Decode speed (single stream, 7 prompts, mean) | 93.4 tok/s |
| KV pool | 700,880 tokens |
| Concurrency at 131,072 context | 5.35x |
| DFlash accept_len (K=15) | 3.28 |
| Headroom per card | ~1.25 GiB |
★ The KV pool number is meaningful here. A 16 GB card is a constrained system: whatever is
left after weights, draft head and activations is the KV pool. --kv-cache-memory 3200000000
is already close to the practical ceiling (~1.25 GiB/card is deliberately left free — without it
the very first request OOMs). So it reflects what this hardware can do, not what I configured.
(Contrast: the GB10 section below deliberately does not quote a KV pool — see why there.)
Long-prompt check: a 40,575-token input was answered correctly (6.2 s including prefill, measured on the same hardware on the previous revision).
⚠️ Scope of these numbers — please read before quoting them
Everything on this page is a short, single-domain measurement. It is not a long-running or broad benchmark:
- 7 prompts per configuration, single stream, one run each. No repeated runs for variance, no multi-hour stability testing.
- One prompt domain only: programming / technical Q&A. Chinese prose, long-form reports, agent / tool-calling traces, multi-turn chat and very-long-context continuation are all not covered.
- This matters especially for speculative decoding: DFlash acceptance is essentially a function of how redundant the text is. The same draft head can differ by more than 2× in accept_len across domains (in practice: tool-calling > code > Chinese reports > Chinese prose). So the ranking between the three draft heads below only holds for this one domain — it may well flip elsewhere.
- Concurrency figures are the theoretical value vLLM prints at startup (KV pool ÷ context), not throughput measured under real concurrent load.
If you are making a decision based on this, re-measure on your own prompt distribution.
Contents
model-0000{1,2}-of-00002.safetensors 16.98 GiB main model
model.safetensors.index.json 1,460 tensors / 2 files
config.json has_vision: false
hf_quant_config.json modelopt MIXED_PRECISION
draft-mxfp8/ 2.76 GiB DFlash draft head (default)
draft-nvfp4/ 1.80 GiB DFlash draft head (smallest)
draft-bf16/ 4.76 GiB DFlash draft head (upstream, unquantized)
Quantization recipe
| Component | Precision | Size |
|---|---|---|
language_model mlp |
W4A16_NVFP4 · group 16 | 10.86 GiB |
language_model self_attn |
W4A16_NVFP4 · group 16 | 2.32 GiB |
lm_head |
MXFP8 · group 32 | 1.29 GiB |
embed_tokens |
BF16 | 2.51 GiB |
| norms | BF16 | ~0 |
How this recipe was decided
Not "quantize everything to 4-bit". Each component was decided separately, by one rule:
open vLLM's model file and check whether that layer is constructed with a quant_config.
If it isn't, it becomes a BF16 parameter — quantizing it guarantees a load failure.
| Component | Decision | Basis |
|---|---|---|
language_model mlp / self_attn |
W4A16_NVFP4 g16 | They are MergedColumnParallelLinear / QKVParallelLinear and do take a quant_config. ★Fused layers (gate+up, q+k+v) must all share one precision, otherwise the weight_scale_2 values disagree and the fused kernel breaks |
lm_head |
MXFP8 g32 | ParallelLMHead(..., quant_config=quant_config) does take one. It is read in full for every single token, so shrinking it directly buys speed — one of the few weights on the decode path where quantization pays off twice |
embed_tokens |
BF16 | VocabParallelEmbedding(vocab, hidden) takes no quant_config; and decoding only reads a single row, so shrinking it would not help speed anyway |
| norms | BF16 | Should not be quantized |
Why NVFP4 and not FP8 for the backbone: vLLM's ModelOptFp8LinearMethod is a W8A8 path.
It needs an input_scale, i.e. it needs calibration. There is no such thing as
"weight-only FP8 without calibration" here — feed it uncalibrated FP8 and the model loads fine
and then emits garbage. So if you want to skip calibration, your only options are
NVFP4 (weight-only) or BF16.
Why group_size 16: it is W4A16_NVFP4's native block size, matching vLLM's kernel.
Three draft heads — pick one
This repo ships three DFlash draft heads. Switch by pointing --speculative-config's
model at a different directory (or DRAFT=draft-nvfp4 bash run_example.sh):
| Directory | Precision | Size | Per card (TP2) | Hit rate | accept_len | tok/s | Notes |
|---|---|---|---|---|---|---|---|
draft-mxfp8/ |
MXFP8 g32 | 2.76 GiB | 1.38 GiB | 15.5% | 3.32 | 31.2 | Default. Fastest, and the highest acceptance too |
draft-nvfp4/ |
W4A16_NVFP4 g16 | 1.80 GiB | 0.90 GiB | 10.5% | 2.58 | 25.6 | Smallest (0.48 GiB/card less than MXFP8), costs roughly -18% speed |
draft-bf16/ |
BF16 (upstream) | 4.76 GiB | 2.38 GiB | 14.7% | 3.21 | 27.8 | Control group if you distrust quantized drafts; bigger and slower than MXFP8 |
| (no speculative decoding) | — | — | — | — | 1.00 | 13.2 | Baseline |
These two columns are not the same thing:
- Hit rate = accepted draft tokens ÷ proposed draft tokens (K=15, so 15 proposed per round)
- accept_len = tokens actually emitted per round =
1 + hit_rate × K. This is the one that scales with speed.
The tok/s column was measured on a GB10 single card (same target, same K=15, same 7 prompts) and is only meant for ranking; for absolute numbers on 2×5070Ti see the table at the top. The last row is the same machine with speculative decoding switched off.
Two counter-intuitive results (bounded by the scope caveat above — one prompt domain only):
- The BF16 draft head is not the best one. It is both larger and slower than MXFP8, and its acceptance is actually slightly lower (3.21 vs 3.32). Being 1.0 GiB/card larger also eats directly into the KV pool. "Unquantized must be more accurate" does not hold for draft heads.
- NVFP4 costs acceptance, not peak speed (2.58 vs 3.32). It is still worth using — provided you spend the 0.48 GiB/card you saved on KV.
★ If you switch to draft-bf16/, lower --kv-cache-memory by about 2×10⁹ or it will OOM.
Running it
⚠️ The image must have
muse_glimmersupport —vllm/vllm-openai:latestwill not start. Upstream vLLM has nomuse_glimmer.pyin main, v0.26.0, v0.26.1 or v0.27.0 (verified 2026-08-13; all four return 404).Use the public build on Docker Hub,
vllm/vllm-openai:muse-glimmer— vLLM0.26.1rc1.dev608+g99a10304d· 2026-08-11 · multi-arch (amd64 + arm64):vllm/vllm-openai@sha256:413c8fbecb1204a218117c77a4ea4b3a211d5686ff99c31d82ba6dd0cec8c5a6Every command on this page and
run_example.shpin that digest, so a retagged image cannot silently change what you run. Switch back tolatestonce upstream merges support.
huggingface-cli download pottokao/Muse-Glimmer-30B-Heretic-NVFP4-DFlash-MXFP8 \
--local-dir ./muse-text
bash run_example.sh ./muse-text # or use the command below directly
The draft head lives in a subdirectory, so --speculative-config's model must be a
local path — <download-dir>/draft-mxfp8 (or one of the other two). A repo id will not work.
docker run -d --name muse --gpus all --ipc host \
-e VLLM_ALLOW_LONG_MAX_MODEL_LEN=1 -e TORCH_CUDA_ARCH_LIST=12.0 \
-e PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True \
-v $PWD/muse-text:/model -p 8000:8000 --entrypoint vllm \
vllm/vllm-openai@sha256:413c8fbecb1204a218117c77a4ea4b3a211d5686ff99c31d82ba6dd0cec8c5a6 \
serve /model --tensor-parallel-size 2 --generation-config auto \
--quantization compressed-tensors --attention-backend TRITON_ATTN --kv-cache-dtype fp8 \
--max-model-len 131072 --gpu-memory-utilization 0.95 --kv-cache-memory 3200000000 \
--max-num-batched-tokens 2048 --max-num-seqs 4 --enable-chunked-prefill \
--chat-template /model/chat_template.jinja \
--reasoning-parser muse_glimmer --tool-call-parser muse_glimmer --enable-auto-tool-choice \
--speculative-config '{"method":"dflash","model":"/model/draft-mxfp8","num_speculative_tokens":15,"attention_backend":"TRITON_ATTN"}' \
--trust-remote-code
Dual-card configuration (2×16GB, as measured)
The parameters that matter above, and why each value:
| Parameter | Value | Reason |
|---|---|---|
--tensor-parallel-size |
2 |
Weights, KV and vision attention all shard; but plain nn.Linear does not (see the VL variant) |
--attention-backend |
TRITON_ATTN |
★On sm_120, FLASH_ATTN does not support FP8 KV (requires FA3 on SM90 or FA4 on SM100). Not a preference — it is the only way in |
--kv-cache-dtype |
fp8 |
Prerequisite for fitting 128k on 16 GB cards |
--kv-cache-memory |
3200000000 |
★Set it explicitly, don't let util compute it — and don't fill it to the brim: startup does not reserve for activations, so an over-generous value starts fine and OOMs on the first request |
--gpu-memory-utilization |
0.95 |
Used together with the explicit KV value above |
--max-num-seqs |
4 |
★The KV pool is decided by --kv-cache-memory; raising seqs is nearly free. For more concurrency, raise that instead |
--max-num-batched-tokens |
2048 |
Pairs with chunked prefill |
num_speculative_tokens |
15 |
See "cost of K" below |
attention_backend (inside speculative-config) |
TRITON_ATTN |
★The drafter needs its own setting; --attention-backend only covers the main model. flash_attn hits a CUDA device-side assert at K≥16 |
TORCH_CUDA_ARCH_LIST |
12.0 |
RTX 50-series is sm_120 |
NCCL_P2P_DISABLE=1 |
optional | On consumer dual-card setups without working P2P, this avoids NCCL hangs |
Cost of K: DFlash is a block-diffusion drafter — one forward pass produces a whole 16-token block, so raising K costs almost no compute. It only costs CUDA-graph memory (K=4→15 is about +1.17 GiB). If memory is tight, K=8 still retains roughly 95% of the benefit.
Single large-memory card (NVIDIA GB10 / DGX Spark, as measured)
The same folder on a GB10 (sm_121, 121.6 GiB unified memory) single card — three changes:
docker run -d --name muse --gpus all --ipc host \
-e VLLM_ALLOW_LONG_MAX_MODEL_LEN=1 \
-e PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True \
-v $PWD/muse-text:/model -p 8000:8000 --entrypoint vllm \
vllm/vllm-openai@sha256:413c8fbecb1204a218117c77a4ea4b3a211d5686ff99c31d82ba6dd0cec8c5a6 \
serve /model --tensor-parallel-size 1 --generation-config auto \
--quantization compressed-tensors --attention-backend TRITON_ATTN --kv-cache-dtype fp8 \
--max-model-len 131072 --gpu-memory-utilization 0.75 \
--max-num-batched-tokens 4096 --max-num-seqs 16 --enable-chunked-prefill \
--chat-template /model/chat_template.jinja \
--reasoning-parser muse_glimmer --tool-call-parser muse_glimmer --enable-auto-tool-choice \
--speculative-config '{"method":"dflash","model":"/model/draft-mxfp8","num_speculative_tokens":15,"attention_backend":"TRITON_ATTN"}' \
--trust-remote-code
| Dual 16GB | GB10 single card | Reason | |
|---|---|---|---|
--tensor-parallel-size |
2 | 1 | Single card |
--kv-cache-memory |
explicit | omit, leave it to util 0.75 |
Memory is plentiful; no need to run to the edge |
--max-num-seqs |
4 | 16 | Much larger KV pool, concurrency is affordable |
--max-num-batched-tokens |
2048 | 4096 | Same |
TORCH_CUDA_ARCH_LIST |
12.0 |
unset | GB10 is sm_121, not sm_120 |
Measured on GB10:
| Metric | GB10 single card | 2×5070Ti |
|---|---|---|
| tok/s | 34.5 | 93.4 |
| accept_len | 3.26 | 3.28 |
| Weights + non-torch | 22.41 GiB | same weights, split across two cards |
| Peak activation | 2.87 GiB | — |
| CUDA graphs (K=15) | 1.4 GiB | — |
No KV pool figure is quoted here on purpose. On GB10 the KV size is entirely determined by
how much memory you hand it (util 0.75 above is just a test value), and such machines usually
host other services too — publishing a number would invite reading it as a property of the model.
Compute it yourself instead: subtract the three rows above (~26.7 GiB) and everything left can
be KV; this model needs roughly 9,140 bytes/token with FP8 KV.
⇒ The two setups are opposites: dual 5070Ti buys speed (2.7×); GB10 buys "make the context
as large as you like". TRITON_ATTN is equally mandatory on GB10 (sm_121 is neither SM90 nor
SM100, so FP8 KV cannot use FlashAttention). If you don't need FP8 KV at all, GB10 has enough
memory to just run --kv-cache-dtype auto and keep full precision.
★ Pitfalls already paid for (copying these will save you a day)
--attention-backend TRITON_ATTNis mandatory on sm_120, not a preference. FLASH_ATTN does not support FP8 KV (requires FA3 on SM90 or FA4 on SM100), and FP8 KV is the prerequisite for 128k on 16 GB cards — so TRITON is the only way in.- The drafter needs TRITON_ATTN too (set inside
speculative-config;--attention-backendonly covers the main model). flash_attn hits a CUDA device-side assert at K≥16. - Without
--tool-call-parser muse_glimmer, chat completions come back empty. - Pass
--kv-cache-memoryexplicitly rather than relying on util — and do not fill it: startup does not reserve for activations, so too large a value starts fine and OOMs on the first request. - K=15 is nearly free — DFlash produces a whole block per forward pass, so extra K only costs CUDA-graph memory (K=4→15 ≈ +1.17 GiB), not linear slowdown. Drop to K=8 under memory pressure and keep ~95% of the benefit.
- If your vLLM build doesn't recognise
DFlashDraftModel, changearchitecturesin the draft'sconfig.jsontoMuseGlimmerAssistantModel(the original is kept asconfig.json.orig).
Provenance and credits
- Base model:
meta-models/Muse-Glimmer-30B(Meta Superintelligence Lab, Apache 2.0) - DFlash draft head: the upstream Muse Glimmer DFlash assistant
(
draft-*/README_upstream.mdis the original upstream model card) - Abliteration source:
mlasli/Muse-Glimmer-30B-Heretic-Abliterated-BF16, pinned at commitdabdf7eb48a770e4fda6a4bfc485ea21fae5fc84— refusal-direction removal with Heretic over 500 Optuna trials, 6.5% refusals / KL 0.076. This repo only quantizes; it makes no capability changes. - Quantization: NVIDIA TensorRT Model Optimizer 0.45.0
Use of this model is subject to the upstream Usage Policy.