rdtand's picture
Add YAML frontmatter (license/base_model/tags/pipeline_tag)
e7c8b12 verified
---
license: apache-2.0
base_model: Qwen/Qwen3.6-27B
base_model_relation: quantized
library_name: transformers
pipeline_tag: image-text-to-text
language:
- en
- zh
tags:
- prismaquant
- compressed-tensors
- nvfp4
- mxfp8
- quantized
- multimodal
- vision-language
- mtp
- speculative-decoding
- vllm
- qwen3.6
---
# Qwen3.6-27B — PrismaQuant 5.5 bpp
[![PrismaQuant source](https://img.shields.io/badge/PrismaQuant-GitHub-blue?logo=github)](https://github.com/RobTand/prismaquant)
[![License: Apache-2.0](https://img.shields.io/badge/license-Apache--2.0-green)](https://huggingface.co/Qwen/Qwen3.6-27B/blob/main/LICENSE)
[![vLLM native](https://img.shields.io/badge/vLLM-compressed--tensors-orange)](https://docs.vllm.ai/en/latest/features/quantization/compressed_tensors.html)
Mixed-precision quantization of `Qwen/Qwen3.6-27B` produced by
[**PrismaQuant**](https://github.com/RobTand/prismaquant) — a per-Linear
sensitivity-driven allocator that chooses each Linear module's format
individually under a total-bit budget. Same allocator + activation-aware
export stack as the 35B-A3B sibling; sibling-coupling is pre-aggregated
into the DP so the achieved bpp hits the target exactly (5.500 not 5.28).
This checkpoint sits at the Pareto knee of the Δloss-vs-bpp curve —
see **[Why 5.5 bpp](#why-55-bpp)** below for the full sweep and
selection rationale.
---
## At a glance
| Metric | BF16 source | **This artifact** | Delta |
|---|---:|---:|---:|
| Size on disk | 54 GB | **~19 GB** | **−65 %** |
| Fraction of original weights | 100 % | **35 %** | |
| Average bits per param | 16 | **5.50** | |
| Multimodal (vision + text) | ✓ | **✓** | |
| MTP speculative decoding head | ✓ | **✓** | |
| Loads in vLLM (stock `compressed-tensors`) | ✓ | **✓** | |
| Runtime backend | any | **vLLM only** | |
---
## Precision mix
Selected per-Linear by the allocator from measured Fisher sensitivity.
On this dense 27B the allocator hit the 5.5 bpp budget exactly:
| Format | W | A | Use | Count (after expansion) |
|---|---|---|---|---:|
| **NVFP4** | 4-bit (FP4, group_size=16 with per-group FP8 scale + per-tensor global) | 4-bit (dynamic) | Bulk dense MLPs + medium-sensitivity attention + most visual Linears | **349** |
| **MXFP8** | 8-bit (E4M3, group_size=32 with per-group E8M0 scale) | 8-bit (dynamic) | High-sensitivity dense Linears the allocator won't risk at 4-bit | **35** |
| **BF16** | 16-bit | 16-bit | Router-free dense top-k sensitivity + norms + biases + embed / lm_head / pos_embed | **112 (linear) + 352 (layer_passthrough)** |
The allocator **pre-aggregates fused-projection siblings** — `qkv_proj`
(q/k/v share one format) and `gate_up_proj` (gate+up share one format) —
as single DP items. Previously sibling coupling was enforced as a post-
pass that inflated the achieved bpp by up to 0.5 above target; the new
pre-aggregation path collapses each group into one multi-choice item so
the DP's solution is already sibling-consistent.
### Activation-aware passes applied during export
On every NVFP4 weight the exporter runs, in order:
1. **GPTQ-OBS one-shot rounding** — block-wise error propagation along
the group-quant structure using the calibration Hessian. Closed-form,
not iterative.
2. **Closed-form per-group scale sweep** — for each 16-weight NVFP4
group, enumerate `grid=32` candidate scales spanning
`[0.5·s₀, 1.5·s₀]`, round each weight to its nearest codebook
neighbor at every candidate scale, pick the (scale, rounding-set)
configuration minimizing activation-weighted per-group MSE. Sub-second
per Linear. Closed-form analog of Intel's AutoRound.
**Measured per-Linear output-MSE vs RTN baseline (family-level
measurement on Qwen3.6-35B-A3B; same pipeline applied here):**
| Pipeline variant | out_mse ratio vs RTN |
|---|---:|
| RTN (no passes) | 1.00 |
| GPTQ only | 0.41 |
| **GPTQ + scale_sweep (this artifact)** | **0.33** |
---
## Why 5.5 bpp
Before quantizing we ran the allocator across the full target sweep
`{4.5, 4.75, 5.0, 5.25, 5.5, 6.0, 7.0, 8.25}` on the same Fisher-
probed + RTN-costed stats this artifact was built from. Thanks to
allocator pre-aggregation of fused siblings + convergence-based
tightening, every target lands its budget exactly — achieved = target
within 0.001 bpp — so the curve below is a true Δloss-vs-bpp trade-off
across the Pareto frontier, not an apples-to-oranges approximation.
| Target bpp | Achieved bpp | Predicted Δloss | NVFP4 / MXFP8 / BF16 | vs 5.5 bpp |
|---:|---:|---:|---:|---|
| 4.5 | 4.500 | 948 | 416 / 1 / 0 | +99% Δloss, −18% size |
| 4.75 | 4.750 | 704 | 373 / 12 / 32 | +48% Δloss, −14% size |
| 5.0 | 5.000 | 604 | 347 / 14 / 56 | +27% Δloss, −9% size |
| 5.25 | 5.250 | 532 | 321 / 20 / 76 | +12% Δloss, −5% size |
| **5.5** | **5.500** | **477** | **300 / 30 / 87** | **← this artifact** |
| 6.0 | 6.000 | 393 | 270 / 35 / 112 | −18% Δloss, +9% size |
| 7.0 | 7.000 | 276 | 211 / 62 / 144 | −42% Δloss, +27% size |
| 8.25 | 8.249 | 180 | 152 / 73 / 192 | −62% Δloss, +50% size |
(Layer counts are at the un-expanded allocator level — per-Linear
expansion inflates each count 1.0-1.4× after broadcasting sibling-group
formats to members.)
**Selection rationale.** The Kneedle algorithm (Satopää et al.) places
the knee at **5.5 bpp**: on the normalized Δloss-vs-bpp curve, the
farthest point below the chord from `(min_bpp, max_Δloss)` to
`(max_bpp, min_Δloss)` is target 5.5. Reading across the frontier
instead of committing to a single anchor like "4.75" or "6" makes the
trade-off explicit:
- **Below 5.5** the loss curve steepens: 4.75 bpp saves 14% disk but
pays **+48% Δloss**; 4.5 bpp saves 18% and pays **+99%**. Dense 27B
can't be aggressively NVFP4'd the way MoE-A3B can, because every
body Linear is active for every token — there are no "cheap"
low-utilization experts to compress hard.
- **Above 5.5** the loss curve flattens: jumping to 6.0 bpp costs
+9% disk for only −18% Δloss — a softer marginal gain than the
knee's 5.25→5.5 step (−5% size, −12% Δloss in the right direction).
- **At the knee**, 5.5 bpp strikes the maximum distance from the
chord — the point where further bit-budget buys less marginal
Δloss reduction than the bits already spent.
PrismaQuant's precision mix at this knee: 300 Linears at NVFP4 (bulk
dense MLP + medium-sensitivity attention + visual), 30 at MXFP8 (high-
sensitivity dense Linears the allocator won't risk at 4-bit), 87 at
BF16 (highest-sensitivity Linears preserved lossless).
---
## Which layers are quantized
### Text body (DeltaNet linear-attention + dense MLP, 64 layers)
- **Full attention** Linears (`q_proj` / `k_proj` / `v_proj` / `o_proj`):
qkv siblings share one format per layer (pre-aggregated)
- **DeltaNet linear-attention** Linears (`in_proj_qkv` / `in_proj_z` /
`in_proj_a` / `in_proj_b` / `in_proj_ba` / `out_proj`): each Linear's
format chosen independently
- **Dense MLP** (`gate_proj` / `up_proj` / `down_proj`): gate+up
siblings share one format per layer; down chosen independently
### Multi-token-prediction (MTP) head
- One full-attention + dense-MLP decoder layer at the model tail,
quantized by the same per-Linear policy — so
`--speculative-config method=mtp` drafts at the same precision
profile as the body.
### Visual encoder (27 blocks — Qwen3.6-VL vision tower)
- **Fisher-driven per-Linear allocation:** 108 of 110 visual Linears
got placed by the full DP allocator on the basis of per-Linear
activation-weighted cost (8 multimodal calibration samples).
- **Remaining 2 un-probed visual Linears** (`patch_embed.proj` edges
the probe didn't tap) stamped at NVFP4 uniformly.
- **`model.visual.pos_embed`** stays BF16 — it's a learnable Parameter,
not an `nn.Linear`, and vLLM's compressed-tensors loader cannot
consume a quantized Parameter layout.
### Passthrough (unquantized)
- `lm_head` — kept at BF16 because vLLM's `ParallelLMHead` module only
accepts a single `weight` parameter. The allocator measures
lm_head's Fisher sensitivity and would pick NVFP4 for it, but the
compressed-tensors runtime rejects a compressed lm_head with
`KeyError: lm_head.input_global_scale`. This is a vLLM runtime
limitation, not a PrismaQuant design decision.
- RMSNorm weights (all layers + MTP + visual)
- All biases
- `embed_tokens`
- `model.visual.pos_embed`
---
## Serving (vLLM only)
This artifact is **only** runnable via vLLM's stock `compressed-tensors`
support — there is no transformers-native runtime path for mixed NVFP4 +
MXFP8 today. vLLM 0.11+ or equivalent is required.
```bash
vllm serve rdtand/Qwen3.6-27B-PrismaQuant-5.5bit-vllm \
--trust-remote-code \
--max-model-len 32768 \
--gpu-memory-utilization 0.90 \
--speculative-config '{"method":"mtp","num_speculative_tokens":3}'
```
- **FlashInfer** NVFP4 attention is picked up automatically; set
`VLLM_NVFP4_GEMM_BACKEND=flashinfer-cutlass` to make the preference
explicit.
- **MTP speculative decoding** at `n=3` is the measured optimum for
this family on DGX Spark (n=2 leaves ~10% tok/s on the table, n=4
regresses).
- **Visual inputs** work via vLLM's standard `image-text-to-text` chat
API — no special flags.
A full recipe with the flashinfer-cutlass backends, reasoning/tool
parsers and chat-template pinning is available at
[`spark-vllm-fresh/recipes/qwen3.6-27b.yaml`](https://github.com/RobTand/prismaquant).
---
## Reproducing this artifact
Full pipeline is in the [PrismaQuant repo](https://github.com/RobTand/prismaquant):
1. **Sensitivity probe** — streaming per-shard empirical-Fisher trace
(diagonal) across body + MTP + visual Linears. Shard granularity
and layer-cache budget are auto-derived from available RAM via
`prismaquant.autoscale`. Checkpoint-level reuse (per-Linear stats
are pooled across prior shard pickles) means mid-run crashes resume
cleanly regardless of `LAYERS_PER_SHARD` changes.
2. **Per-(Linear, format) cost measurement** — for each Linear and each
candidate format, the per-group RTN error weighted by cached input
activations.
3. **Multi-choice knapsack allocator** — picks one format per Linear
minimizing total predicted Δloss under the bit budget. Fused-sibling
groups pre-aggregated into DP items to avoid post-pass overshoot.
Target 5.5 bpp; achieved 5.500 bpp.
4. **Export** — streams each body / visual / MTP shard, applies GPTQ +
scale_sweep to its NVFP4 entries, writes the compressed-tensors
format. `lm_head` passthrough at BF16 enforced at this stage.
Wall-clock on a DGX Spark (128 GB unified memory): ~2 h cold probe +
~15 min cost + ~20 min export. Subsequent iterations at different bpp
targets reuse probe + cost artifacts and complete in minutes.
---
## Known issues / limitations
- **vLLM only at serve time.** No transformers-runtime path for this
precision mix today.
- **lm_head stays BF16** because vLLM's `ParallelLMHead` does not
register the NVFP4/MXFP8 compressed-tensors schemes. Allocator
measured it and would have picked NVFP4; the runtime limitation
forces BF16. Costs ~770 MB on the disk footprint.
- **MTP n=4 regresses on this family.** Stick to `n=3` unless you
verify against the draft-head acceptance-rate trace.
---
## Links
- **Source:** [github.com/RobTand/prismaquant](https://github.com/RobTand/prismaquant)
- **Base model:** [Qwen/Qwen3.6-27B](https://huggingface.co/Qwen/Qwen3.6-27B)
- **Sibling 35B-A3B:** [Qwen3.6-35B-A3B-PrismaQuant-4.75bit-vllm](https://huggingface.co/rdtand/Qwen3.6-35B-A3B-PrismaQuant-4.75bit-vllm)
- **Sibling 122B-A10B:** [Qwen3.5-122B-A10B-PrismaQuant-4.75bit-vllm](https://huggingface.co/rdtand/Qwen3.5-122B-A10B-PrismaQuant-4.75bit-vllm)
## Citation
```bibtex
@software{prismaquant2026,
title = {PrismaQuant: per-Linear sensitivity-driven mixed-precision
quantization for LLMs},
author = {Tand, Rob},
year = 2026,
url = {https://github.com/RobTand/prismaquant},
}
```