Ling-3.0-flash — NVFP4 W4A4 (calibrated, MTP verified working)

The first W4A4 NVFP4 quantization of Ling-3.0-flash (124B total / 5.1B active, hybrid KDA+MLA MoE) — weights and activations in NVFP4, calibrated with 128 samples via llm-compressor.

Size 81.4 GB (from 255 GB BF16)
Format compressed-tensors nvfp4-pack-quantized, W4A4 (E2M1 + FP8-E4M3 group-16 scales, static input global scales)
Measured 110 tok/s single / 493 tok/s @ 8-way generation, ~7,000 tok/s prefill — 8×RTX PRO 2000 Blackwell (16 GB), TP=8, 32K context
Long context 131,072 tokens verified (eager mode; prefill 5,900–8,000 tok/s)
MTP Works: 93% acceptance (k=1). Off by default — see below
Sanity 6/6 (math / logic / code / JP idiom / instruction-following / long-form JP); tool-calling 4/4

Recommended: fp8 KV cache — 131K context at full speed

With the bundled vllm_patch/triton_decode_attention.py (1-line shared-memory fix for sm_120), --kv-cache-dtype fp8 works and everything fits at once:

context KV budget generation prefill
fp8 KV + patch (recommended) 131,072 458,752 tok 112.6 / 482–493 tok/s (1 / 8-way) 1.9k single / 6.5k @ 4-way
bf16 KV, 32K 32,768 ~187K tok 110 / 493 tok/s up to 7.6k single (4096 chunks)
bf16 KV, 131K (--enforce-eager) 131,072 ~187K tok 16.5 / 31.7 tok/s 5.9k–8.0k

458K tokens of KV = three concurrent 131K streams, or eight at 57K each. Quality battery under fp8 KV: 6/6 (math / logic / code / JP idiom / instruction-following / long-form JP) — no measured degradation vs bf16 KV. Single-stream prefill in the recommended config is chunking-bound (--max-num-batched-tokens 2048, the largest stable value at 131K on 16 GB); parallel prefill reaches ~6,500 tok/s.

Why context is cheap here but headroom is not. Only 7 of 42 layers are MLA (the other 35 are KDA linear attention and carry no KV), so the KV cost is 8.2 KB/token — roughly 9× cheaper per token than an all-MLA model like DeepSeek-V3. The constraint is the card: weights + non-torch overhead take 12.66 GB of a 16 GB GPU, leaving ~1.5 GB for KV and KDA state — a total budget of about 187K tokens to split between length and concurrency (131K × 1 stream, or 23K × 8 streams, etc.). On 80 GB cards this limit essentially vanishes.

How this differs from olka-fi/Ling-3.0-flash-NVFP4 (weight-only W4A16): this build quantizes activations too (W4A4) with real calibration data, and ships a working MTP path.

Quantization boundary

Same proven boundary as the W4A16 build: routed experts only (layers 2–41, mlp.experts.*.{gate,up,down}_proj, 120.8B of 127.4B params) → NVFP4 W4A4. Kept in BF16: shared experts, KDA & gated-MLA attention, router gate + expert_bias, dense layers 0–1, the MTP layer 42, embeddings, lm_head, norms.

Serving (vLLM fork required)

Upstream vLLM does not support bailing_hybrid v3. Use the prebuilt image olkafi/vllm-bailing-v3 (inclusionAI/vllm @ ling_3_0 + SwiGLU-clamp patch).

This exact command reproduces every number in this card (131K context, fp8 KV, 458,752-token KV budget, ~112 tok/s single-stream). Both bundled patch files are mounted over the image's own copies — no rebuild needed, they are pure Python:

REPO=/path/to/this-repo   # e.g. $(huggingface-cli download sakamakismile/Ling-3.0-flash-W4A4-NVFP4)

docker run --gpus all -d --name ling3 --ipc=host -p 8000:8000 \
  -e NCCL_P2P_DISABLE=1 -e NCCL_CUMEM_ENABLE=0 \
  -v $REPO:/models/ling3:ro \
  -v $REPO/vllm_patch/unquantized.py:/opt/vllm-ling3/vllm/model_executor/layers/fused_moe/oracle/unquantized.py:ro \
  -v $REPO/vllm_patch/triton_decode_attention.py:/opt/vllm-ling3/vllm/v1/attention/ops/triton_decode_attention.py:ro \
  olkafi/vllm-bailing-v3:latest /models/ling3 \
  --served-model-name ling3 --trust-remote-code --host 0.0.0.0 --port 8000 \
  --tensor-parallel-size 8 --disable-custom-all-reduce \
  --kernel-config '{"moe_backend":"marlin"}' --kv-cache-dtype fp8 \
  --compilation-config '{"max_cudagraph_capture_size":16}' \
  --gpu-memory-utilization 0.95 --max-model-len 131072 --max-num-seqs 8 \
  --max-num-batched-tokens 2048 \
  --enable-prefix-caching --mamba-cache-mode align \
  --enable-auto-tool-choice --tool-call-parser ling3 --reasoning-parser ling3

Notes for reproducers:

  • --max-num-batched-tokens 2048: 4096 OOMs at 131K on 16 GB cards (chunked-prefill activations); 2048 is stable.
  • On cards with more than 16 GB, drop the two patch mounts if you don't need them (flashinfer_cutlass may still be broken on sm_120 — keep moe_backend=marlin there), and raise --max-num-batched-tokens / --max-num-seqs freely.
  • NCCL flags are for machines without GPU P2P; harmless otherwise.

Sampling (from the base card): temperature=0.6, top_p=0.95, top_k=20, thinking enabled.

⚠️ Known landmines (sm_120 / consumer Blackwell)

  1. moe_backend=marlin is mandatory. The auto-selected flashinfer_cutlass backend silently corrupts output (endless !!!!) on sm_120 with EP, and plain TP=8 hits NotImplementedError (per-rank intermediate 768/8=96 needs unsupported padding). cutlass rejects EP. Marlin works and is the source of the numbers above.
  2. KV headroom is tight — on 16 GB cards use --gpu-memory-utilization 0.95, --max-num-seqs 8 and --compilation-config '{"max_cudagraph_capture_size":16}'. 32K fits comfortably that way; 131K needs --enforce-eager (see table above).
  3. --kv-cache-dtype fp8 needs the bundled kernel patch on sm_120. The TRITON_MLA fp8 decode kernel asks for 102,400 bytes of shared memory at num_stages=2; consumer Blackwell caps at 101,376 — 1 KB short. vllm_patch/triton_decode_attention.py drops fp8-KV MLA to num_stages=1, which fits with no measured speed loss (112.6 tok/s single-stream, same as bf16 KV).
  4. The bundled vllm_patch/unquantized.py makes the unquantized MTP-layer MoE fall back to triton when moe_backend=marlin is forced globally — without it, serving with --speculative-config fails at startup.

MTP / speculative decoding: verified working, off by default

The W4A16 release reported 0% acceptance and shipped with MTP disabled. With this build + the bundled patch, MTP works:

config single-stream acceptance
no MTP (recommended) 113.2 tok/s
MTP k=1 88.3 tok/s 93.0%
MTP k=2 110.0 tok/s 68%/tok

The draft (BF16 MTP layer on the triton path) currently costs more than the accepted tokens buy back on this hardware, so MTP is a proof-of-life, not a speed win — leave --speculative-config off for throughput. To try it: --speculative-config '{"method":"mtp","num_speculative_tokens":1}' (add --compilation-config '{"max_cudagraph_capture_size":32}' --max-num-seqs 32 for memory).

Bake provenance

llm-compressor 0.12 (lna-lab/llmc-bake:v0.24.0), 128 calibration samples (neuralmagic/calibration, chat-templated) @ 2048 tokens, basic pipeline with CPU-resident weights and single-GPU onload calibration (fla/KDA kernels are triton/cuda-only, so pure-CPU forward is impossible). Recipe quirks that will bite reproducers: transformers 5.x needs three shims in the custom modeling file (is_torch_fx_available, ROPE_INIT_FUNCTIONS['default'], _tied_weights_keys); rope_scaling must be forced back to None after config normalization; llm-compressor drops model_type from the saved config (breaking vLLM's MLA detection — restore "model_type": "bailing_hybrid"); and post-calibration weight observation must be moved to CPU (set_onload_device) or 61,440 expert observers accumulate on one GPU and OOM.

Acknowledgements

Built on inclusionAI's Ling-3.0-flash (MIT). Quantization boundary and serving groundwork follow olka-fi's pioneering W4A16 release and vendor-fork patches.

MIT license, inherited from the base model.

Downloads last month
157
Safetensors
Model size
75B params
Tensor type
F32
·
BF16
·
U8
·
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for sakamakismile/Ling-3.0-flash-W4A4-NVFP4

Quantized
(17)
this model