inference/research

23 — Choosing a quantization format for a given hardware target

The decision this document serves: you have a hardware target and a workload, and you must pick a quantization format for it. The answer is not "the best format" — the repo has no defensible ranking, and §9 says why. It is a match between three things that are recorded separately and rarely read together:

the format  ×  the kernel that will actually run it  ×  the engine that chooses the kernel

Any two of the three being right is not enough. Most of the expensive failures in this repo are a format record and a kernel matrix agreeing with each other while the running server does something else.

For why weight-only 4-bit and W4A4 are different regimes, read 04-quant-selection.md first; this doc assumes that distinction.


0. The decision rule, short form

hardware target pick and know this records
Blackwell sm100/103/107 (B200, B300, GB200) NVFP4 for W4A4; MXFP4 only if you need the open standard NVFP4 is the lower-accuracy-risk of the two; MXFP4 is the portable one NVFP4 (Blackwell block-scaled E2M1 + E4M3), MXFP4 (OCP microscaling FP4, E8M0 scale), MXFP4 vs NVFP4: block size, scale format, and hardware support comparison
Consumer Blackwell sm120 (RTX 5090, RTX PRO 6000) NVFP4 / MXFP4 / per-tensor FP8 — and not AWQ or GPTQ on TensorRT-LLM TensorRT-LLM ships no kernel for any of the four AWQ/GPTQ cells on sm120, the inverse of the Ampere/Ada pattern; Marlin is the other engine's answer TensorRT-LLM per-GPU-architecture quantization support matrix (which format has a kernel on which arch), NVIDIA GeForce RTX 5090, NVIDIA RTX PRO 6000 Blackwell Workstation Edition
Hopper (H100/H200) FP8-E4M3 for W8A8; AWQ or GPTQ at group 128 for W4A16 via Machete FP8 rowwise scaling exists on Hopper and nowhere else in the vendor matrix; Machete is sm90-and-CUDA-only FP8 E4M3 (per-tensor / per-block scaled), Machete Hopper-optimized mixed-precision GEMM kernel (CUTLASS-based), TensorRT-LLM per-GPU-architecture quantization support matrix (which format has a kernel on which arch)
Ampere (A100, A10) AWQ or GPTQ at group 128 via Marlin; INT8-W8A8 on A100 FP8 is emulated on Ampere — it is a per-tensor upcast, not a tensor-core path AWQ (activation-aware weight quantization), GPTQ (one-shot approximate second-order PTQ), Marlin INT4 weight-only kernel (FP16xINT4 mixed-precision GEMM), Marlin weight-only INT4 GEMM: repacking so dequant is free and tensor cores stay saturated
Ada (RTX 4090, RTX 6000 Ada) AWQ or GPTQ via Marlin; FP8 W8A8 if the engine supports it Volta is the only generation where GPTQ wins over AWQ — everything else is a tie vLLM Implementation x Hardware support matrix (which quantization implementation runs on which architecture, and where it does NOT), NVIDIA GeForce RTX 4090, NVIDIA RTX 6000 Ada Generation
AMD Instinct (MI300X) INT8-W8A8, or AWQ only outside vLLM vLLM's AWQ and GPTQ have no AMD GPU path; the AMD-native route is Quark, not in these records vLLM Implementation x Hardware support matrix (which quantization implementation runs on which architecture, and where it does NOT), AMD Instinct MI300X, INT8 W8A8 (weight-only scheme, per-tensor / per-channel)
Anything wide-arch — Radeon, CDNA, RDNA, Pascal GGUF via llama.cpp Zero GGUF accelerator has a silicon path; the win is bytes, not a native kernel GGUF IQ4_XS (non-linear 4-bit, 256-value super-block with 6-bit sub-block scales), llama.cpp MMQ: INT8 activation quantization with per-arch tile configs, no tensor cores
Apple Silicon MLX affine 4-bit, group 64 The group size is a default, not a constant — the API takes group_size per call MLX affine quantized linear (mlx-lm's default 4-bit weight format, group_size 64)
x86 or Arm CPU GGUF, or AWQ/GPTQ on x86 "Move W4A8 to the CPU" is false on x86 — the one W4A8 row in the matrix is Arm-CPU-only vLLM Implementation x Hardware support matrix (which quantization implementation runs on which architecture, and where it does NOT)
Any part, if you need an int4 KV cache KVQuant 3-bit or QServe 4-bit + SmoothAttention, and nothing below 3 No 8-bit KV record has any controlled accuracy delta at all KVQuant (per-channel + pre-RoPE key quantization, non-uniform KV), QServe SmoothAttention (4-bit KV cache with an accuracy-preserving correction), QServe / QoQ (W4A8KV4 quantization and system co-design)

1. Rule 1 — a format record tells you what exists, not what runs

The single most common expensive mistake is reading native_support on a format record as a statement about your GPU. It is a statement about the format. Two records in this repo exist purely to make that distinction, and they are the most decision-relevant material here:

Both are filed under a proxy scheme value (nvfp4 and gptq respectively) because the schema's enum has no matrix member, and both say so in their own notes: a query for NVFP4 returns the matrix, not the format. Read the format record for the format and the matrix for the kernel; never quote one as the other. The TRT-LLM matrix says it explicitly: "Read this table as 'what TensorRT-LLM can do', never as 'what this GPU can do'."

1.1 The sm120 inversion, which is the row that changes a purchase decision

The TRT-LLM matrix row for Blackwell sm120 — the RTX 50-series and RTX PRO 6000 — reads: NVFP4 Y, MXFP4 Y, FP8(per tensor) Y, FP8(block scaling) ., FP8(rowwise) ., FP8 KV Y, NVFP4 KV ., and all four AWQ/GPTQ cells ..

That last clause is the finding. On Ampere the same four cells are: W4A8 ., W4A16 Y, W4A8 ., W4A16 Y. On Ada and Hopper all four are Y. So the consumer Blackwell parts invert the Ampere/Ada pattern at the bottom of the precision range while gaining formats at the top — the one generation in the table where the newest 4-bit format is available and the most popular 4-bit format is not, in the same engine (TensorRT-LLM per-GPU-architecture quantization support matrix (which format has a kernel on which arch)).

Three consequences to carry:

  1. "My 5090 runs NVFP4" and "my 5090 runs AWQ" are both true, in different engines. TRT-LLM has the NVFP4 kernel and no AWQ kernel; vLLM and SGLang serve AWQ W4A16 on Blackwell through Marlin and Machete, which is a different kernel set entirely. The matrix record carries the caveat verbatim.
  2. sm120 has no block-scaled FP8 GEMM and no NVFP4 KV-cache path, both of which sm100/103 and Rubin carry. Two of the three "Blackwell supports it" reflexes are wrong on the consumer part.
  3. sm120 is also the row that the kernel records disagree about (Consumer Blackwell (SM120) vs datacenter Blackwell (SM100a): one architecture name, two incompatible kernel targets: sm100a-compiled kernels "are not compatible with RTX 50 series GPUs"; FlashInfer: a kernel-selection layer over FlashAttention, cuDNN, CUTLASS and TensorRT-LLM notes FlashInfer lists SM100/SM103 and SM120/SM121 separately). §8 keeps this open.

1.2 FP8 rowwise is a Hopper-only format, which is the opposite of intuitive

FP8 rowwise scaling needs no per-tensor calibration, so it is the FP8 variant people reach for by default. In the vendor matrix it is Y on Hopper only — . on sm120, sm100/103, sm107, Ada and Ampere (TensorRT-LLM per-GPU-architecture quantization support matrix (which format has a kernel on which arch)). It is the narrowest-supported FP8 variant in the table despite having the easiest calibration story.

Do not treat "FP8" as one row. The matrix's own recipe line is arch-dependent: "FP8 block wise scaling GEMM kernels for sm100/103/107 are using MXFP8 recipe (E4M3 act/weight and UE8M0 act/weight scale), which is slightly different from SM90 FP8 recipe (E4M3 act/weight and FP32 act/weight scale)." One column covers two numerically different scale formats, so a memory or quality calculation for block-scaled FP8 that assumes the SM90 recipe is wrong on Blackwell in a way the table does not flag.

Independent corroboration from the other direction: SmoothQuant with FP8 activations: does outlier migration still help? notes "the FP8 format has limited precision (E4M3 has 3 mantissa bits), so the migration may not help as much as it does for INT8" — SmoothQuant was designed for INT8, and whether it still earns its keep against FP8 is recorded as an open research question, not a result.

1.3 The W4A8 row is a backend-selection fact, not a hardware fact

vLLM's llm-compressor INT8 W4A8 row is supported on Arm CPU and on nothing else in the matrix — not on any NVIDIA generation, not AMD, not Intel, not x86 (vLLM Implementation x Hardware support matrix (which quantization implementation runs on which architecture, and where it does NOT)). The obvious fallback "the GPU can't do W4A8, so put it on the CPU" is false on x86, and that is the shape of the trap: a . in an NVIDIA column reads like a hardware limit when the reason is that the implementation has one backend.

Three more cells in the same table that a flat reading gets wrong:

  • GPTQ is the only row that covers Volta. AWQ and Marlin both exclude SM7.0. "GPTQ is the older format" is backwards as a compatibility statement: on a V100 it is the only one of the three that runs.
  • Marlin's Turing cell carries a footnote narrower than the cell. The star expands to "Turing does not support Marlin MXFP4", so the cell means Marlin-minus-MXFP4; a reader treating the column as a flat yes picks MXFP4 on a T4 and fails.
  • FP8 W8A8 is Ada-and-Hopper-only in this table, which is narrower than "FP8 works on Ampere and up" — on the Ampere row bitsandbytes and GGUF are YES while llm-compressor FP8 is NO, at the same compute capability.

The matrix covers Volta through Hopper only; Blackwell is absent from it. That is why it must be read together with the TRT-LLM matrix rather than instead of it, and it is why its own scope line warns the chart "is subject to change as vLLM continues to evolve".


2. Rule 2 — verify which kernel is actually running, every deploy

Given §1, the format you chose is a hypothesis. The running kernel is the fact. Four records describe the same failure from four directions, and it is the most consequential class in the repo: the output is correct and the performance is not what you bought.

Three checks that cost nothing and catch all of it:

check what a bad answer looks like source
Read the startup log's kernel/backend line a W4A16 kernel named for a W4A4 checkpoint Silent precision degradation: when W4A4 formats are served as W4A16 on pre-Blackwell hardware, SGLang hardware-dependent kernel selection logic for FP4/FP8 GEMM
Read the scheme name in the engine config nvfp4_w4a16 vLLM quantization backend selection and hardware compatibility
Ask the hardware directly: torch.ops._C.cutlass_scaled_mm_supports_fp4(<capability>) false on the part you are about to ship FP4 on vLLM's 'Your GPU does not have native support for FP4' warning fires on weight-only NVFP4 checkpoints, and gets quoted as evidence the silicon lacks FP4 kernels

The third check exists because the warning you would naturally trust is a measurement bug, not a capability statement: "Your GPU does not have native support for FP4 computation" is emitted for a weight-only checkpoint, and the record's instruction is "Do not read this warning as a hardware capability statement."

The inverse mistake is also recorded and it is worse, because it is silent and wrong in the other direction: FlashInfer's b12x MoE backend silently defaults quant_mode to W4A4, so a weight-only NVFP4 checkpoint is computed at the wrong activation precision (major) — a checkpoint marked W4A16_NVFP4 served with --moe-backend flashinfer_b12x runs the FP4×FP4 micro-kernel, and the record's instruction is "Do not accept a b12x trace showing an FP4 kernel for a W4A16 checkpoint." Two benchmark records price that misroute on an identical model: Qwen3-8B MXFP4 W4A16 served on MarlinMxfp4Kernel (correct W4A16 path): AIME-24/25 + GSM8K + MATH-500 average accuracy 78.16 versus Qwen3-8B MXFP4 W4A16 served on the FlashInfer W4A4 kernel: AIME-24/25 + GSM8K + MATH-500 average accuracy 70.58, against the unquantized Qwen3-8B BF16 reference: AIME-24/25 + GSM8K + MATH-500 average accuracy (baseline for the MXFP4 W4A16 dispatch comparison) 82.36. A 7.58-point accuracy drop caused purely by kernel selection.


3. Rule 3 — on Blackwell, NVFP4 beats MXFP4 on risk and loses on portability

Both are W4A4 with real FP4 tensor-core paths, and they are not interchangeable — a model quantized to MXFP4 cannot be served with NVFP4 kernels or vice versa (MXFP4 vs NVFP4: block size, scale format, and hardware support comparison).

MXFP4 NVFP4
scale group 32 values 16 values
scale format E8M0, power-of-two E4M3, fractional
scale levels one (per block) two (E4M3 per block + FP32 per tensor)
standard OCP open spec, multi-vendor NVIDIA-proprietary
native_support B200, B300, GB200-NVL72 B200, B300, GB200-NVL72

Recommendation: NVFP4 by default, MXFP4 when portability is a requirement. The accuracy argument is the vendor's own: NVIDIA's comparison table rates MXFP4 as "risk of noticeable accuracy drop compared to FP8" where NVFP4 is "lower risk", and the quantitative reason is that encoding the scale in E4M3 rather than E8M0 "drops the scale-encoding MSE from 0.72 to 0.08" (NVFP4 (Blackwell block-scaled E2M1 + E4M3), MXFP4 vs NVFP4: block size, scale format, and hardware support comparison).

Two honesty constraints on that recommendation. The MSE ranking is a vendor claim, and MXFP4 vs NVFP4: block size, scale format, and hardware support comparison records that "no independent controlled benchmark comparing MXFP4 and NVFP4 on the same model with the same calibration data was found." And MXFP4 (OCP microscaling FP4, E8M0 scale) has no inference quality delta recorded at all — the closest evidence is a PTQ study of SmoothQuant+AWQ+GPTQ on MX formats, which is W4A8, not W4A4. So the format preference rests on a vendor table, and the MXFP4 record says in its own words that no MXFP4 accuracy number should be quoted from it.

Both formats are Blackwell-only in silicon; on Hopper and Ampere both are emulated_support, which is §2's failure mode rather than a slow path you can accept.

The mechanism underneath is in Block-scaled FP8/FP4 tensor cores: MXFP and NVFP formats inside the MMA instruction: the scale is "part of the MMA OPERAND, not a separate kernel", which is why "the activation quantization no longer needs a fused dequant pass". Its portability warning is the one to remember when you change parts: "SM90 requires scaling factors in FP32 while SM100 requires them packed in UE8M0 ... So switching an FP8 model from H100 to B200 changes the memory layout the engine must produce, not just the kernel it calls."

MoE is a separate question from dense. MXFP4 MoE quantization: per-expert scales and block scaling for mixture-of-experts (draft, 0.5) records that per-tensor rather than per-expert scales are used for MoE, that "the block scaling in MXFP4 (32 elements) may not align well with MoE's expert structure", and flags "a potential source of silent accuracy degradation that has not been well-documented." Treat MoE MXFP4 as unproven on accuracy; do not extrapolate the dense result.


4. Rule 4 — W4A16: group size is the scheme, and the kernel is chosen for you

4.1 Group size 128 is not a tunable

AWQ (activation-aware weight quantization): "Group size 128 is the scheme's defining choice and the file layout - it is not a tunable." GPTQ (one-shot approximate second-order PTQ) adds that 32/64/1024 "are legal and change both quality and kernel eligibility, which is a frequent source of 'GPTQ is slow' reports." If you are handed a GPTQ file at group 64, you are not holding the format the docs describe, and the kernel eligibility is a separate question from the quality.

The 128 default is also the recommended default in the toolkit that implements the low-bit path: AutoRound confirms "bits 2 through 8, every one with group_size=128 and sym=True and act_bits=16", and its troubleshooting section recommends 32 or mixed bits for better results — "so 128 is the default, not the optimum" (AutoRound (Intel) - SignRound weight-rounding PTQ toolkit, W4A16 and neighbours).

The asymmetry limit is the practical line in that record. --asym supports weight bits ≤ 7 for the auto_round/auto_gptq/auto_awq exports, "because vLLM serves W8 GPTQ-format weights symmetric-only and Marlin supports zero points at 4 bits only." Two constraints, one from each side of the stack, that agree.

And a labelling trap in the same record: its README labels MXFP4, MXINT4, MXFP4_RCEIL, MXFP8, FPW8A16 and FP8_STATIC as "Research feature, no real kernel" — do not read them as deployable.

4.2 Which kernel runs, per generation — three records, one precision

Marlin INT4 weight-only kernel (FP16xINT4 mixed-precision GEMM) and Machete Hopper-optimized mixed-precision GEMM kernel (CUTLASS-based) are the decision records, and both carry the same load-bearing fact: Marlin and Machete produce the same numerical results. Marlin's is explicit — "despite being called an 'INT4 kernel', the actual tensor-core operation is FP16 × FP16 - weights are dequantized to FP16 in registers before the multiply. This is NOT an INT4 tensor-core path (which does not exist on Ampere/Ada). The speedup comes from reduced memory bandwidth (4-bit weight storage), not from faster arithmetic." Machete's record says the same for Hopper: "the kernel is numerically equivalent to Marlin for the same quantized weights, so the Marlin quality figures apply."

So the kernel choice is purely a performance decision, and it is invisible in the output. Selection logic, from Machete Hopper-optimized mixed-precision GEMM kernel (CUTLASS-based): "vLLM uses Machete when the GPU is SM90 (Hopper) and the quantization method is AWQ or GPTQ. On Ampere/Ada, Marlin is used instead."

part W4A16 kernel the number to carry
Volta SM7.0 none (GPTQ only, no Marlin) vLLM Implementation x Hardware support matrix (which quantization implementation runs on which architecture, and where it does NOT)
Turing SM7.5 Marlin, minus MXFP4 Marlin INT4 weight-only kernel (FP16xINT4 mixed-precision GEMM)
Ampere / Ada SM8.0+ Marlin Marlin weight-only INT4 GEMM: repacking so dequant is free and tensor cores stay saturated — "near-ideal 4x speedups up to batchsizes of 16-32 tokens" on A10, 3.87x theoretical max after 0.125 bits/weight scale overhead
Hopper SM9.0 Machete — Marlin is "not yet optimized for Hopper" Machete Hopper-optimized mixed-precision GEMM kernel (CUTLASS-based), Machete weight-only 4-bit GEMM: CUTLASS 3.x tiles plus an offline prepacked int4 B operand, Hopper only
anything (incl. RDNA, CDNA, Pascal) llama.cpp MMQ llama.cpp MMQ: INT8 activation quantization with per-arch tile configs, no tensor cores — integer SIMT DP4A, "not tensor-core MMAs", widest arch reach of the three

The honest comparison is in the MMQ record and it should be quoted whenever anyone ranks these: llama.cpp "reaches 4-bit throughput through integer SIMT dot products with a broad arch reach (including RDNA and CDNA), while Marlin and Machete reach it through tensor cores on a narrower arch list. Neither is strictly better ... and any comparison must state which path was taken."

Two more kernel facts that cost people deployments. Marlin is a GEMM kernel, not a format, and both records say so — Marlin "is filed under 'gptq' because Marlin consumes GPTQ-packed weights and the enum has no kernel-family values", and the proxy will "make Machete under 'awq' and Marlin under 'gptq' look like two different precisions when they are the same one". And Marlin's ROCm path has a hard failure worth pre-checking: The ROCm Triton w4a16 path asserts on GPTQ models with a non-zero-group qzeros layout (major), a qzeros.shape == (K // group_size, N // 8) assertion when serving GPTQ-Int4 on the ROCm Triton w4a16 path.

4.3 The accuracy budget you can actually cite

Accuracy cost of quantization: measured deltas on named benchmarks compiles the deltas that papers actually report, and its pattern line is the most quotable summary in the repo: "4-bit weight-only quantization typically costs 0.1-0.3 ppl on WikiText-2. 3-bit costs 0.5-1.0 ppl. 2-bit costs 2.0+ ppl. KV cache quantization at 4-bit is nearly lossless; at 2-3-bit it costs 0.1-0.5 ppl." The same record's own caveat is the load-bearing part: "The accuracy cost is model-dependent and benchmark-dependent."

The controlled numbers behind it, with models attached:

method model / benchmark delta records
Marlin INT4 g128 Llama2-7B WikiText-2 / MMLU 5.12 → 5.27 (+0.15 ppl); MMLU 41.80 → 40.07 (−1.73) Marlin INT4 weight-only kernel (FP16xINT4 mixed-precision GEMM)
Marlin INT4 g128 Llama2-13B / 70B Wikitext +0.10 / +0.09; MMLU −0.97 / −0.62 Marlin INT4 weight-only kernel (FP16xINT4 mixed-precision GEMM)
GPTQ 3-bit vs group-128 Llama-7B WikiText-2 +2.39 ppl at plain 3-bit, +0.93 at group 128 Accuracy cost of quantization: measured deltas on named benchmarks
AWQ INT3 OPT-6.7B WikiText-2 43.2 (RTN) vs 13.0 (−30.2) — mechanism demo, not a W4A16 delta AWQ (activation-aware weight quantization), AWQ INT4-g128 WikiText-2 perplexity delta vs fp16, Llama-2 7B
GGUF Q4_K_M Llama-3.1-8B WikiText-2 7.56 vs 7.32 F16 (+0.24); unweighted mean −0.46%; size −69.41% GGUF Q4_K_M (4-bit K-quant, medium), GGUF Q4_K_M WikiText-2 perplexity delta vs f16, Llama-3.1-8B-Instruct
SpQR 3–4 bit + sparse outliers LLaMA, Falcon <1% perplexity loss; 4x+ memory, 15% speedup SpQR (Sparse-Quantized Representation for near-lossless 3-4 bit compression)
SignRound 2-bit 11-task zero-shot average +6.91% to +33.22% over RTN SignRound (signed gradient descent for weight rounding optimization)

Two rows in that table are the actionable ones. At 3 bits, group size buys more than the method does (+0.93 vs +2.39 ppl for the same format at the same bit width). And rounding is a first-class lever at 2 bits, where SignRound (signed gradient descent for weight rounding optimization) records "6.91-33.22% absolute average accuracy improvement" — but it is a rounding algorithm, it "cannot be combined with other quantization methods (like AWQ's scaling or GPTQ's Hessian-based rounding) without re-running the optimization," and it is implemented by AutoRound (AutoRound (Intel) - SignRound weight-rounding PTQ toolkit, W4A16 and neighbours).

4.4 Bitrate is a target, not a format — EXL2/EXL3

EXL2 (GPTQ with mixed per-tensor bitrate) mixes quantization levels within a model, and can "apply multiple quantization levels to each individual linear layer - to hit any target average bitrate between 2 and 8 bpw." Its successor EXL3 (ExLlamaV3 format, QTIP-based trellis quantization) - the successor to the archived EXL2 is a different format with "no checkpoint compatibility between them" (ExLlamaV3) — a lattice-coded, Hessian-calibrated QTIP derivative rather than a grid quantizer.

The measured throughput curve is the decision-relevant part, from ExLlamaV2 EXL2 kernel throughput benchmarks (3090 Ti / 4090): lower bit width is slower, not faster. 2.5 bpw 70B runs 33/38 t/s on a 3090 Ti / 4090 while 4.0 bpw 7B runs 185/211 — because "lower bit widths require more complex dequantization and the memory bandwidth saving is offset by increased compute overhead." The same mechanism is QServe / QoQ (W4A8KV4 quantization and system co-design)'s central claim from the serving side: "existing INT4 methods suffer 20-90% runtime overhead from dequantizing weights or partial sums on GPUs", and INT4 "can be slower than fp16" unless you also fix the dequant path.

Neither record carries a quality delta — EXL2 (GPTQ with mixed per-tensor bitrate)'s quality_delta is empty because the README publishes throughput only, and ExLlamaV2 EXL2 kernel throughput benchmarks (3090 Ti / 4090) says "No quality delta is published in the README - only throughput numbers." Choosing EXL2/EXL3 is choosing an unquantified quality risk for a bitrate target. EXL3's group-size 256 is also the embedding group specifically — "Each embedding is split into 256-wide groups that are rotated and trellis-coded without calibration, and the following layers are calibrated against the quantized table" — which is §5's trap in a second disguise.


5. Rule 5 — GGUF: match bits-per-weight, and do not trust a group size of 256

5.1 The group-size correction, which changes what you can compare

Eight GGUF records previously carried weight_group_size: 256. Seven of those were wrong, and the error was the K-quant super-block size being read as the scale group. The correction was made from the ggml dequantize routines, and it matters because 256 vs 16/32 is the difference between "one fp16 scale per 256 values" and "eight or sixteen sub-block scales per 256 values".

record weight_group_size now the actual structure why 256 was wrong
GGUF Q4_K_M (4-bit K-quant, medium) 32 8 sub-blocks of 32 per 256-value super-block, each a 6-bit scale + 6-bit min on fp16 d/dmin "Base type Q4_K has a 32-value scale group"
GGUF Q4_K_S (4-bit K-quant, small) 32 same base type, unmixed same
GGUF Q5_K_M (5-bit K-quant, medium) 32 same base type, unmixed same
GGUF Q6_K (6-bit K-quant) 16 int is = l/16, 16 int8 sub-block scales per 256 "Base type Q6_K has a 16-value scale group"
GGUF Q3_K_M (3-bit K-quant, medium) 16 scales[is++] once per 16 values, 16 sub-block scales per 256 same
GGUF Q2_K / Q2_K_S (2-bit K-quant) 16 one (scale,min) pair per 16 values, 16 sub-blocks per 256 same
GGUF IQ4_NL (non-linear 4-bit, 32-value blocks, QK4_NL) 32 QK4_NL = 32, one fp16 d across all 32, no 256 super-block at all "the 256 was inherited from the K-quant convention"
GGUF IQ2_XXS (2.0625 bpw, almost-true 2-bit with a 16-bit scale per 256) 256 one fp16 d for the whole 256-value block, no sub-block scale plane not an error — "the super-block size and the scale group DO coincide at 256"

Four records are legitimately at 256 and must not be "corrected" again, because for them the super-block and the scale group genuinely coincide: GGUF IQ1_S (1.5625 bpw, non-linear 1-bit-ish with a 16-bit grid high plane) ("256 IS right here and the distinction matters" — one fp16 d for 256 values, no sub-block scales), GGUF IQ2_XXS (2.0625 bpw, almost-true 2-bit with a 16-bit scale per 256), GGUF IQ3_XXS (3.0625 bpw, almost-true 3-bit with a 16-bit scale per 256), and GGUF TQ1_0 / TQ2_0 (ternarized quants, QK_K super-block, trit-packed) ("TQ1_0 genuinely has a 256-value scale group ... unlike the K-quants").

The rule this yields: in GGUF the number that matters for storage is bits-per-weight, and the number that matters for quality comparison is bits-per-weight on a matched budget — not a group size, and never a quant name. See §5.2.

5.2 Measured bpw, the number to match on

Llama-3.1-8B, measured average bits per weight, straight from the records:

bpw records
1.6875 / 2.0625 GGUF TQ1_0 / TQ2_0 (ternarized quants, QK_K super-block, trit-packed) (ternarized, base-3 packing; 3⁵ = 243 ≤ 256 is the packing constraint)
2.0042 – 2.1460 GGUF IQ1_S (1.5625 bpw, non-linear 1-bit-ish with a 16-bit grid high plane), GGUF IQ1_M (1.75 bpw trellis-flavoured 1-bit with 3-bit sub-block scales and a grid-shift bit) (codebook i-quants)
2.3125 – 2.9294 GGUF IQ2_XXS (2.0625 bpw, almost-true 2-bit with a 16-bit scale per 256), GGUF IQ2_XS (2-bit non-linear, 256 super-block with a 32-element sub-block scale plane), GGUF IQ2_S (2.5625 bpw, non-linear 2-bit with a 4-bit scale per 64 and sign/high-bit planes), GGUF IQ2_M (mixture built on IQ2_S with Q4_K/Q5_K promoted tensors)
3.2548 – 3.6606 GGUF IQ3_XXS (3.0625 bpw, almost-true 3-bit with a 16-bit scale per 256), GGUF IQ3_S (3.4375 bpw, non-linear 3-bit with separate sign plane)
2.625 / 2.9697 GGUF Q2_K / Q2_K_S (2-bit K-quant)
3.9960 GGUF Q3_K_M (3-bit K-quant, medium) (contested)
4.4597 – 4.8944 GGUF IQ4_XS (non-linear 4-bit, 256-value super-block with 6-bit sub-block scales), GGUF IQ4_NL (non-linear 4-bit, 32-value blocks, QK4_NL), GGUF Q4_0 (legacy block-4 symmetric), GGUF Q4_K_S (4-bit K-quant, small), GGUF Q4_K_M (4-bit K-quant, medium) (contested), GGUF Q4_1 / Q5_1 (legacy asymmetric 32-value blocks with per-block scale AND min)
5.7036 GGUF Q5_K_M (5-bit K-quant, medium) (contested)
6.5633 GGUF Q6_K (6-bit K-quant) (contested)
8.5008 GGUF Q8_0 (legacy block-8 symmetric)

Five K-quant records are contested because the measured bpw of the *_M mixture types does not match the pure-block struct comments; both numbers are retained per record.

Two names are not two configurations. GGUF Q4_K_M (4-bit K-quant, medium): "'Q4_K_M IS A MIXTURE, not a type'" — base q4_K with attn_v and ffn_down promoted to Q6_K, and "The plain 'Q4_K' CLI name is an alias for Q4_K_M". The consequence is that a quant name does not identify a bit budget across models; see Two models quantized at 'the same Q4_K_M level' can land at 4.75 and 4.30 bpw, so named-quant comparisons across models are not controlled experiments and llama.cpp's --target-bpw, which is the tool that fixes it.

The GGUF case of the mixture trap is bigger than the K-quant one. GGUF MXFP4_MOE (llama.cpp MoE-specific ftype: MXFP4 for experts, Q8_0 for everything else) is llama.cpp's LLAMA_FTYPE_MOSTLY_MXFP4_MOE: MXFP4 on expert tensors and Q8_0 on everything else — "the embedding, output head, and any non-expert projection are stored at 8.5 bpw while the experts sit at 4.25. So the whole-model bpw of an MXFP4_MOE model is NOT 4.25**." Its mapping is explicit about 3-D tensors and BailingMoE3 MLA projections. Note also that for MX formats "the scale group IS the block" (QK_MXFP4 32), which is why GGUF MXFP4_MOE (llama.cpp MoE-specific ftype: MXFP4 for experts, Q8_0 for everything else) and MXFP4 (OCP microscaling FP4, E8M0 scale) agree at 32 and need no correction.

5.3 The lever that costs nothing: imatrix

GGUF imatrix (importance matrix) - the calibration file that determines WHICH weights get more bits is "not a format - a per-tensor activation-energy file" whose own note calls it "THE MAJOR PRACTICAL LEVER NOBODY RECORDS". It applies across every format ("every ggml type, every bit width, legacy and k-quant and i-quant alike") and its effect "is to REMOVE part of the quantization delta of the format it is applied to", with official per-type figures Q4_K_M +0.1754 and Q5_K_M +0.056 — which is most of GGUF Q4_K_M (4-bit K-quant, medium)'s +0.24 total delta.

If you are quantizing a GGUF yourself, this is a higher-return action than choosing a different quant type, and it composes with nothing else in this document.

5.4 GGUF has no silicon anywhere

Worth stating because it inverts the usual question. GGUF IQ4_XS (non-linear 4-bit, 256-value super-block with 6-bit sub-block scales): "so native_support is deliberately EMPTY and the whole accelerator ecosystem is emulated_support. No accelerator has an i-quant or k-quant path in silicon. This is the single most commonly botched field in this repo." No GGUF quant will ever be faster because the GPU supports it; it is faster because there are fewer bytes, reached by MMQ (llama.cpp MMQ: INT8 activation quantization with per-arch tile configs, no tensor cores).


6. Rule 6 — 8-bit KV cache: widely deployed, and completely unmeasured

This is the recommendation with the weakest evidence base in the repo, and the honest thing is to say so rather than pick a winner.

FP8 KV cache quantization (E4M3 keys and values) and INT8 KV cache quantization (8-bit keys and values) are both draft at confidence 0.5, and both quality_delta fields say the same thing: no controlled benchmark with a named accuracy delta was found. FP8 KV's field in full: "No controlled benchmark with named accuracy delta found in the sources accessed ... This is a significant gap: FP8 KV cache is widely deployed but the accuracy impact is not well-documented in public sources."

What is recorded, and it is enough to act on:

  • Both halve KV memory versus FP16.
  • The kernel interaction is not free: "the KV cache is quantized after the KV projection, so the attention kernel must dequantize before computing attention scores. This dequantization adds latency to the decode phase."
  • Support is not uniform: FP8 KV is native on Hopper and Ada, "On Ampere (SM80), FP8 is emulated via FP16 with reduced precision", and "The accuracy delta is expected to be larger on Ampere where the FP8 path is emulated."
  • INT8's record argues a mechanism preference: "INT8 is symmetric around zero while FP8 has an exponent. For attention keys that feed into softmax, the INT8 format may be more appropriate because the key distribution is roughly symmetric." That is a may in the record's own words.
  • And a silent-corruption combination exists, which outranks the accuracy question: Disabling FlashInfer Q-quantization with an FP8 KV cache and speculative decoding silently corrupts sliding-window models on SM100 — FP8 KV plus sliding-window attention plus speculative decoding, which is the exact configuration the FP8 KV record itself warns about.

Recommendation: use 8-bit KV to fit the cache, not to save accuracy risk — you are accepting an unquantified delta in exchange for 2x capacity — and never combine it with sliding-window attention and speculative decoding until you have measured that combination. Establish the delta yourself; the repo cannot do it for you.

For 4-bit and below, there is no such ambiguity, only disagreement. The family disagrees about the right key bit width and the repo says so: "Note the whole family (KIVI 2/4, KVQuant 3/3, QuaRot 4/4, QServe 4/4, ZipCache mixed) disagrees about the right key bit width - there is no settled answer" (QServe SmoothAttention (4-bit KV cache with an accuracy-preserving correction)).

method what it does the number record
KVQuant (per-channel + pre-RoPE key quantization, non-uniform KV) 3-bit keys and values, per-channel <0.1 ppl degradation on WikiText-2 and C4 across LLaMA, Llama-2, Llama-3, Mistral; LLaMA-7B at 1M context on one A100-80GB KVQuant (per-channel + pre-RoPE key quantization, non-uniform KV)
KIVI (2-bit key / 4-bit value KV cache, per-channel keys, per-token values) asymmetric 2-bit keys / 4-bit values "almost the same quality" (unquantified) at 2.6x less peak memory, 2.35–3.47x throughput KIVI (2-bit key / 4-bit value KV cache, per-channel keys, per-token values)
QServe SmoothAttention (4-bit KV cache with an accuracy-preserving correction) 4-bit KV + SmoothAttention as a correction 1.2x/1.4x (LLaMA-3-8B, A100/L40S) and 2.4x/3.5x (Qwen1.5-72B) vs TensorRT-LLM QServe SmoothAttention (4-bit KV cache with an accuracy-preserving correction), QServe / QoQ (W4A8KV4 quantization and system co-design)
ZipCache (channel-separable tokenwise KV quantization + salient token identification) mixed precision by token salience 4.98x compression for −0.38% GSM8k on Mistral-7B ZipCache (channel-separable tokenwise KV quantization + salient token identification)

Recommendation: KVQuant 3-bit if you want the best-documented number; KIVI if you want the most capacity per unit of risk, accepting a qualitative claim; QServe 4-bit only with SmoothAttention attached, since its record is explicit that SmoothAttention "is a CORRECTION METHOD ... introduced specifically to counter the accuracy degradation that 4-bit KV quantization causes." And note the asymmetry result is KIVI's central finding, not an incidental detail — do not carry 4-bit KV and 4-bit values forward to 2-bit keys assuming the halves are independent.

One non-quantization answer is sometimes correct. Pensieve (multi-tier conversation-state KV cache) - NOT KV quantization "solves the SAME problem as KIVI ... by storing it across tiers instead of compressing it", and the record's judgement is the useful part: "Since lossless storage is strictly better than lossy compression when the constraint is host memory rather than GPU memory, Pensieve is the correct answer when an offload path exists and KIVI is the correct answer when it does not."


7. Rule 7 — the non-post-training families, which are not choices at all

Two families in the records look like format choices and are not, and picking them as if they were is a category error.

  • Ternary / BitNet b1.58 — Ternary / 1.58-bit quantization (general), BitNet b1.58 (ternary LLM): "ternary LLM quantization is a TRAINING-TIME recipe, not a post-training one. There is no such thing as PTQ-ing an existing fp16 LLM to 1.58 bits and keeping its quality." The paper's "matches fp16" is a statement about the ternary set's expressiveness under an identical token budget. native_support is empty on both records. You cannot select this for an existing checkpoint.
  • W4A4 research without silicon — SpinQuant (learned rotations + W4A4KV4) is genuinely W4A4 (64.0 average zero-shot on LLaMA-2 7B, 2.9 points from full precision, SpinQuant W4A4KV4 8-task zero-shot accuracy delta vs fp16, LLaMA-2 7B) but "there is NO hardware INT4 tensor-core path. Its W4A4 numbers come from research Triton kernels plus fake quantization". Atom (mixed-precision block-outlier low-bit quantization for serving) is W4A4 with real integer operators, and its record draws the distinction that matters: Atom "is built around 4-bit integer operators - but that is an integer-operator path on datacenter GPUs, not the FP4 tensor-core path that Blackwell introduced". Cite these for accuracy evidence; do not cite them for speed. Its own throughput claim (7.73x vs FP16, 2.53x vs INT8) is from the authors' own kernels.

8. What would change these recommendations

change which recommendation flips record to re-read
A vendor kernel lands for sm120 AWQ/GPTQ §0 consumer-Blackwell row: AWQ/GPTQ become options on TRT-LLM, and the inversion disappears TensorRT-LLM per-GPU-architecture quantization support matrix (which format has a kernel on which arch)
vLLM or SGLang adds an SM120 NVFP4 kernel with activation quantization §2 stops being a loss on consumer Blackwell — verify the kernel is W4A4, not Marlin Silent precision degradation: when W4A4 formats are served as W4A16 on pre-Blackwell hardware, SGLang hardware-dependent kernel selection logic for FP4/FP8 GEMM
An independent MXFP4-vs-NVFP4 benchmark on one model and one calibration set appears §3's NVFP4-over-MXFP4 preference, which currently rests on a vendor table MXFP4 vs NVFP4: block size, scale format, and hardware support comparison
nvfp4_w4a16 stops being a selectable scheme name in vLLM §2's third check becomes unnecessary and the failure mode becomes unreachable-by-config vLLM quantization backend selection and hardware compatibility
A controlled 8-bit KV cache accuracy delta is published §6 becomes a choice between FP8 and INT8 rather than an unmeasured risk FP8 KV cache quantization (E4M3 keys and values), INT8 KV cache quantization (8-bit keys and values)
Per-expert MXFP4 scales reach a shipping MoE checkpoint §3's MoE carve-out lifts MXFP4 MoE quantization: per-expert scales and block scaling for mixture-of-experts
Marlin gains an Marlin-on-Hopper optimisation §4.2's Hopper row moves from Machete to Marlin on performance grounds only Marlin INT4 weight-only kernel (FP16xINT4 mixed-precision GEMM), Machete Hopper-optimized mixed-precision GEMM kernel (CUTLASS-based)
llama.cpp's IQ-quant kernels land in the llamafile size-optimized CUDA build §5's widest-arch GGUF recommendation narrows, since that build "omits the IQ-quant kernels" GGUF MXFP4_MOE (llama.cpp MoE-specific ftype: MXFP4 for experts, Q8_0 for everything else)
MI350X/MI355X get quantization-support records AMD's row in §0 becomes answerable instead of inferred AMD Instinct MI355X

9. What the records cannot answer

  1. There is no cost-per-quality ranking of formats. The deltas in §4.3 are isolated perplexity differences at isolated bit widths with no shared baseline methodology, and every one of them has its model name attached. Two of the cleanest comparisons are within a family (Marlin vs AWQ on the same model; NVFP4 vs MXFP4 on the same card) and neither crosses a bit width.

  2. The vLLM matrix stops at Hopper and the TRT-LLM matrix stops at Rubin. Blackwell's vLLM story has to be inferred from the other table plus the sm120 kernel records, which disagree with each other (Consumer Blackwell (SM120) vs datacenter Blackwell (SM100a): one architecture name, two incompatible kernel targets vs the format claim that sm120 is native for NVFP4). No record reconciles them, and there are no native_support entries for the RTX 5090 or RTX PRO 6000 from any format record — they appear in matrix records and emulated_support lists only.

  3. Zero controlled accuracy data for 8-bit KV cache, and the least-documented area named by the records themselves is "FP8/FP4 KV cache quantization, where no controlled benchmark with named accuracy delta was found" (Accuracy cost of quantization: measured deltas on named benchmarks).

  4. Format quality deltas are overwhelmingly Llama-3.1-8B or Llama-2-7B. No format has a controlled delta on a modern MoE, which is exactly where quantization behaviour is hardest — and MXFP4-MoE is the place where the format and the model structure are recorded as possibly mismatched. The sub-1-bit exception, QMoE: Practical Sub-1-Bit Compression of Trillion-Parameter Models, reports a masked-LM validation loss on SwitchTransformers (c2048 ternary 1.26 against a bfloat16 1.18) rather than a task score, and its kernel only wins as a batch-1 GEMV (The QMoE sub-1-bit expert kernel is a GEMV, and it loses as soon as two tokens share an expert).

  5. The W4A4 speed claim on Blackwell is vendor-only. The 3.5x memory and 25x/50x energy figures in NVFP4 (Blackwell block-scaled E2M1 + E4M3) are labelled "marketing, not measurements" by the record itself.

  6. EXL2 and EXL3 have no quality delta at all, and EXL2 (GPTQ with mixed per-tensor bitrate) is draft at 0.6 against an archived upstream (ExLlamaV2).

  7. SmoothQuant-on-FP8 is a research question, not a result (SmoothQuant with FP8 activations: does outlier migration still help?, draft, confidence 0.4 — the lowest-confidence record cited here).

  8. AMD has no vLLM AWQ/GPTQ path and no Quark record in this set. The vLLM matrix's AMD column is a whole-column NO that "reads like a data gap" and "must not be read as 'AMD GPUs cannot do quantized inference'" — the AMD-native route the record names is covered by quark and rocm-quant records that this document does not cite.

  9. A schema gap that makes Apple advice indirect, and a 04/23 consistency note. MLX affine quantized linear (mlx-lm's default 4-bit weight format, group_size 64) is the native format on Apple records and lists apple-m3-max and apple-m3-ultra in native_support, at group 64 with emulated_support empty. 04-quant-selection.md §3.2 said "no native quantization support recorded at all" for those two parts; that text has been corrected to agree with this document, so the two no longer contradict each other and the base layer and the selection layer say the same thing about Apple. What remains open is not the native/emulated question but everything downstream of it:

    • MLX's own mlx-quantized-4bit / mlx-quantized-8bit engine labels still have no record of their own. The MLX affine record is the closest thing, and it is keyed on the affine mode with group 64 rather than on the engine's label.
    • Three benchmark records still carry format_id: mlx-quantized-4bit, which is not a record id — the format record's own notes name these as the dangling references its existence was meant to close, and repointing them is a data/benchmarks/ edit this wave does not own.
    • "Native" is not "comparable". MLX ships four modes at four group sizes (affine 64, mxfp4 32, nvfp4 16, mxfp8 32), so a checkpoint recorded as "4-bit on Apple" may be a 64-group affine grid or a 32-group MX grid, and those differ in memory arithmetic and quality. The nvfp4 mode at 16 matches the Blackwell convention in NVFP4 (Blackwell block-scaled E2M1 + E4M3) and the mxfp4 mode at 32 matches MXFP4 (OCP microscaling FP4, E8M0 scale); affine 64 matches neither.

    For the selection consequence on Apple: MLX affine 4-bit, group 64, and treat the group size as a default rather than a constant — mlx.nn.quantize takes group_size per call, so the number in the record is the API's default and not a property of the format.


Related documents

  • 04-quant-selection.md — the regime distinction (W4A16 vs W4A4) this table assumes.
  • 04-quant-selection.md — the regime taxonomy (W4A16 vs W4A4), the per-accelerator native/emulated census, and the quality tables this document draws on. Read §3 of that doc as the base layer; read this one for the selection step.
  • 01-hardware-selection.md — which part to buy, per precision regime. The matrix rows here are the reason its Blackwell and Ampere recommendations differ.
  • 03-engine-selection.md — which engine supports which format on which backend, and the build costs of the two engines named in §1.
  • 05-known-traps.md — the full severity-ordered list behind §2.
  • 09-model-memory-envelope.md — whether the format you picked actually fits, and what KV cache it leaves room for.
  • 08-cost-per-token.md — what the precision choice costs per million output tokens, joined against real prices.