Skip to content
Friendly disclaimer: flozi00 TechHub is a solo side-project next to a full-time job — personal learning notes, no official statements. Verify critical steps yourself.

LLM Quantization: Bit Layouts, Block Scales, and the VRAM Math

NVFP4, MXFP4, FP8, GPTQ, AWQ and GGUF k-quants down to the bit level: how E2M1 and E4M3 encodings work, what block scales really cost, and how many GB your model needs at each format.

12 min readflozi00
aimachine-learninggpuquantizationdeep-learninghardware
Skip to the full article
Watch · explore · understand

Store a short code and the ruler that decodes it

The four-bit payload is only part of a format: its codebook, block scales and compute path determine what it means.

AI-assisted learning visualization · schematic article explanation

Step 1 / 5Scale a neighborhood of values

A scale adapts a small representable range to a block of weights. One large outlier can force a coarse scale for its neighbors; smaller groups contain that effect but require more scale entries.

ComparisonCurrent stepSelect a block to explain it
Original weight values
A block contains values with a local magnitude range.
Choose the shared scale
Map this block’s range into the codebook’s range.
Keep scales and metadata
NVFP4 uses an FP8 scale per 16 values plus a tensor scale.
  1. Original weight values Choose the shared scale
    group values
  2. Choose the shared scale Keep scales and metadata
    record the ruler
What to remember

Compare the codebook, scale layout and runtime support together; “four-bit” does not specify them.

Format arithmetic describes storage, not universal model quality. Block sizes, unchanged tensors, export layouts and kernel support must match the actual checkpoint.

Terms and the complete walkthrough
Codebook
The numerical values assigned to the available bit patterns.
Block scale
A shared multiplier that adapts a group’s codes to its numerical range.
Effective bits per weight
Payload bits plus each weight’s share of scales and other stored metadata.
  1. Scale a neighborhood of values

    A scale adapts a small representable range to a block of weights. One large outlier can force a coarse scale for its neighbors; smaller groups contain that effect but require more scale entries.

  2. Separate integer and floating-point codes

    Uniform INT4 uses evenly spaced integer levels before scaling, optionally with a zero-point. E2M1 FP4 uses sign, exponent and mantissa bits, producing unevenly spaced magnitudes: 0, 0.5, 1, 1.5, 2, 3, 4 and 6.

  3. Compare the scale layouts

    MXFP4 gives 32 E2M1 values one eight-bit power-of-two scale. NVFP4 gives 16 values an eight-bit E4M3 scale plus a tensor-wide FP32 scale, allowing a different local fit at a different metadata cost.

  4. Count effective bits once

    NVFP4’s local block layout costs (16 × 4 + 8) ÷ 16 = 4.5 bits per value, already including the block scale. Add the tensor scale and any padding or unchanged tensors separately; four-bit payload alone is not checkpoint size.

  5. Follow the values into computation

    A weight-only integer kernel can load packed codes and dequantize them for higher-precision arithmetic; native FP4 kernels use a different supported path. Neither weight format alone sets KV precision or guarantees a quality or speed advantage.

All connections

  • Original weight values → Choose the shared scale: group values
  • Choose the shared scale → Round to representable codes: normalize and round
  • Choose the shared scale → Keep scales and metadata: record the ruler
  • Round to representable codes → Packed weights + overhead: payload bits
  • Keep scales and metadata → Packed weights + overhead: shared overhead
  • Packed weights + overhead → Reconstruct approximate values: read format layout
  • Reconstruct approximate values → Use a compatible compute kernel: approximate operands
Set your own pace. Pause at any time or select a step directly.

Start with a number you can move: Compare INT4 and NVFP4 visually to see rounding, scaling and block overhead before the bit-level reference below.

Every LLM deployment decision — which GPU, how many concurrent users, whether the model fits at all — starts with one number: bytes per weight. Quantization is the highest-leverage knob you have, and it is worth understanding at the bit level, because the differences between formats are not marketing: they are concrete bit layouts with countable overheads and measurable accuracy costs.

This guide goes lower than most: what the bits inside FP8/FP4 actually encode, how block-scale metadata adds up, and how each popular format (NVFP4, MXFP4, FP8, GPTQ, AWQ, GGUF k-quants) spends its bits. Every number here is sourced from the primary papers, the OCP specification, or vendor documentation — and every size example is computed from the same formulas the site's VRAM calculator uses.

The One Formula That Matters

Model weights in memory:

Wbytes=P×beff8W_{\text{bytes}} = P \times \frac{b_{\text{eff}}}{8}

where PP is the parameter count and beffb_{\text{eff}} is the effective bits per weight — payload bits plus amortized scale/zero-point metadata. Real 4-bit formats have different effective widths, and mixed-precision tensors can change the checkpoint-wide average further. On the Qwen3-VL-32B reference model (~33.4B parameters — 33,357,390,064 per the Hugging Face safetensors census — used throughout our VRAM deep dive), these differences can amount to gigabytes.

Generalized group overhead — this single expression generates almost every effective-bits number in this article:

beff=k⋅b+sscale+szpkb_{\text{eff}} = \frac{k \cdot b + s_{\text{scale}} + s_{\text{zp}}}{k}

kk = elements per group/block, bb = payload bits per element, sscales_{\text{scale}} and szps_{\text{zp}} = bits for the scale (and optionally a zero-point) shared by the group. A 4-bit payload with one FP16 scale per 128 weights costs (128×4+16)/128=4.125(128 \times 4 + 16)/128 = 4.125 bits per weight; adding a 16-bit zero-point brings it to 4.25.

How a Float Becomes Bits

A binary floating-point number is three fields: sign ss, exponent ee, mantissa mm. The IEEE-754 pattern, generalized:

v=(−1)s×m.mmmm×2e−biasv = (-1)^s \times m.mmmm \times 2^{e - \text{bias}}

The exponent stores a power-of-two window; the mantissa stores position inside that window. Normal numbers have an implicit leading 1 (1.mmm1.mmm); when e=0e = 0 the number is subnormal (0.mmm0.mmm), extending the range down to zero at fixed spacing. The bias is set per format so the exponent range is centered usefully.

The 8-bit and 4-bit formats used in LLM inference are all this same structure with fewer bits:

FormatSignExponentMantissaBiasLargest finite value
FP32 (reference)18231272128≈3.4×10382^{128} \approx 3.4 \times 10^{38}
BF16187127≈3.4×1038\approx 3.4 \times 10^{38}
FP8 E4M31437448
FP8 E5M21521557,344
FP4 E2M112116

Two asymmetries in that table are deliberate, and both come from the FP8 formats paper that standardized E4M3/E5M2 (arXiv 2209.05433)1:

  • E4M3 has no infinity and exactly one NaN pattern. Freeing those encodings extends its usable range to 448=1.75×28448 = 1.75 \times 2^8. It is the weights/activations format: transformer weight distributions need mantissa precision more than range.
  • E5M2 follows IEEE conventions ( infinity + NaN), giving a much wider range (57,344=1.75×21557{,}344 = 1.75 \times 2^{15}) at lower precision. It is the gradients format, where magnitude spread dominates.

E2M1: All Sixteen Codes, On the Record

The 4-bit element at the bottom of every FP4 format is E2M1. With one mantissa bit and bias 1, its entire decode table has 16 entries — 8 magnitudes, each signed:

Code (e,m)ValueCode (e,m)Value
00,00.010,02.0
00,10.510,13.0
01,01.011,04.0
01,11.511,16.0

Sign bit set → the negative of each. That is the entire representable universe of FP4: ±{0, 0.5, 1, 1.5, 2, 3, 4, 6}\pm\{0,\ 0.5,\ 1,\ 1.5,\ 2,\ 3,\ 4,\ 6\} — sixteen codes and — because +0 and −0 encode one value — fifteen distinct values, exactly. Raw E2M1 is far too coarse for transformer weights (which is why a 4-bit format without scaling is unusable); the entire low-bit-format design problem is how to reuse these sixteen levels block-by-block so they cover each weight neighborhood well. Everything else in this article is that trick, at different granularity settings.

The Granularity Ladder

Quantization error is dominated by outliers: one large weight in a group forces the scale up and wastes resolution on everything smaller. The historical fix is ever-finer scales:

  1. Per-tensor — one scale for all weights. Cheapest (≈0\approx 0 overhead) and least accurate. Classic FP8 inference works this way: a single FP32 scale per tensor, applied in software.1
  2. Per-channel — one scale per output row of a weight matrix. It is one possible weight-quantization granularity, with low metadata cost.
  3. Per-group (k=128) — one scale per 128 weights. A common GPTQ/AWQ checkpoint setting; the AWQ paper notes round-to-nearest is already "quite strong" at group 128 with careful scaling (arXiv 2306.00978).2
  4. Per-block, power-of-two scale (k=32, E8M0) — the OCP MX standard: 32 E2M1 elements share one 8-bit power-of-two exponent (arXiv-tracked OCP MX v1.0 spec; the shared scale multiplies by a pure 2n2^n, so dequantization is an exponent add).3
  5. Per-block, FP8 scale + second level (k=16, E4M3 + FP32) — NVFP4, Blackwell's native format, detailed below.

Each rung adds scale bits — that is the beffb_{\text{eff}} arithmetic from the first section — and each rung contains outliers more tightly. The jump from rung 1 to rung 5 is roughly a 100× finer scaling mesh for about 0.5 bits per weight of metadata.

NVFP4 vs MXFP4: The Same Payload, Different Rulers

Two 4-bit block-floating formats ship on current hardware, and their difference is a textbook lesson in scale design. Both store E2M1 elements; neither touches the payload bits. Only the ruler differs:

PropertyMXFP4 (OCP standard)NVFP4 (NVIDIA Blackwell)
Elements per block3216
Block scaleE8M0 (8-bit power of two)E4M3 (8-bit FP8, fractional)
Second-level scale—FP32, one per tensor
Bits per element(32×4+8)/32=4.25(32{\times}4 + 8)/32 = 4.25(16×4+8)/16=4.50(16{\times}4 + 8)/16 = 4.50
Dequantizationbit-shift / exponent addFP8 multiply
Native hardwareBroad MX ecosystem (AMD Instinct MI-series included)NVIDIA Blackwell tensor cores

Both layouts come straight from the NVIDIA NVFP4 introduction and the OCP MX specification.43 NVFP4's two changes attack the two error sources:

  • Half-size blocks (16 vs 32): one outlier contaminates half as many neighbors.
  • A fractional scale (E4M3 vs E8M0): an E8M0 scale must snap to the nearest power of two, so a block whose values sit between 2n2^n and 2n+12^{n+1} loses up to half its representable range at the top. An E4M3 scale can land anywhere in the FP8 dynamic range. NVIDIA measures ~88% lower quantization error for E4M3 micro-block scaling versus power-of-two scaling, and in a head-to-head pretraining comparison MXFP4 needed ~36% more tokens to reach the same loss as NVFP4.5

The cost of the finer ruler is countable: 4.50 vs 4.25 bits per element, plus one FP32 per tensor (negligible at scale). And because the E4M3 scale has a narrower range than E8M0, NVFP4 adds the per-tensor FP32 second level to re-normalize whole tensors so every block's E4M3 scale stays well-conditioned — global range up top, local fit per block.

Accuracy, from NVIDIA's own PTQ study on DeepSeek-R1-0528 (converted FP8 → NVFP4): within 1% of FP8 across seven language-modeling evaluations, with AIME 2024 actually 2 points higher (89 → 91); MMLU-Pro 85 → 84, GPQA 81 → 80.45 The punchline — a 4-bit footprint behaving like an 8-bit model for most serving purposes:

164.5≈3.5× smaller than FP1684.5≈1.8× smaller than FP8\frac{16}{4.5} \approx 3.5\times \text{ smaller than FP16} \qquad \frac{8}{4.5} \approx 1.8\times \text{ smaller than FP8}

which is exactly how NVIDIA states it (~3.5× and ~1.8×).4 On Blackwell tensor cores, FP4 dense throughput is 2× the FP8 rate — the same generational doubling FP8 did to FP16 on Hopper.

Weight-Only Integer Formats: GPTQ and AWQ

GPU hardware before Blackwell has no FP16×INT4 matrix path, so 4-bit integer formats are weight-only formats (W4A16): weights stored in 4 bits, dequantized on the fly, activations kept in FP16. The GPTQ paper is explicit that its speedups come from reduced memory movement, not cheaper math — there is no mixed-precision multiply on mainstream architectures (arXiv 2210.17323).6 For decode-time LLM inference that is precisely what you want: one user's token generation is memory-bandwidth-bound (see our inference math guide), so a 4× smaller weight stream is a near-4× faster token stream until you hit other ceilings.

The two families differ in how they choose the rounding:

  • GPTQ (arXiv 2210.17323) quantizes weights column-by-column, propagating the rounding error of each column into the not-yet-quantized ones using an approximate second-order (Hessian-based) correction. It compensates errors, needs a calibration set, and quantizes OPT-175B-class models in hours, not days.6
  • AWQ (arXiv 2306.00978, MLSys 2024 Best Paper) observes that 0.1–1% of weight channels are salient — identifiable from the activation distribution, not the weights — and protects them by searching a per-channel scaling that makes the full-4-bit representation of salient channels more accurate. No backprop, no reconstruction: it generalizes across domains and modalities without overfitting the calibration set.2

Both typically ship at group size 128 with FP16 scales: beff=(128×4+16)/128=4.125b_{\text{eff}} = (128 \times 4 + 16)/128 = 4.125 bits/weight before zero-points and packing metadata. The interactive calculator models this class of format with a flat 12% overhead factor (int4/AWQ ×1.12) to stay conservative across implementations; hand-check with the formula above when it matters.

One warning from the low level: the scale layout — how scales are interleaved with packed values in memory — varies between exports (block-interleaved, scales-after-values, per-K, tile-major) and is a recurring source of serving-stack bugs when a checkpoint quantized by tool A is loaded by runtime B. If a 4-bit model produces garbage, suspect the scale layout before the model.

GGUF K-Quants: The Byte Layouts, Verified

llama.cpp documents the arithmetic of its k-quants. Its source defines the super-block structure (QK_K = 256) and carries static_asserts for the byte counts; these are the per-weight bit costs:7

TypeSuper-block structureBytesEffective bits/weight
Q4_K8 blocks x 32 weights: FP16 scale + FP16 min + 12 B of 6-bit block scales/mins + 128 B payload144 / 256 w4.5
Q5_Ksame + 32 B high-bit plane176 / 256 w5.5
Q6_K16 blocks x 16 weights: FP16 super scale + 16 B of 8-bit block scales + 192 B payload210 / 256 w6.5625
Q8_0FP16 scale + 32 B INT8 payload per 32 weights34 / 32 w8.5

Read Q4_K's row as the generic formula again: 2 bytes d + 2 bytes dmin + 12 bytes packed 6-bit scales + (256×4)/8=128(256 \times 4)/8 = 128 bytes of nibbles = 144 bytes per 256 weights — 144×8/256=4.5144 \times 8 / 256 = 4.5 bits per weight, plus sixteen levels with a two-level scale hierarchy (super-block FP16 scale over per-block 6-bit scales) so fine scaling doesn't cost a full FP16 per 32 weights.

The _S/_M/_L suffixes describe a tensor policy: they pick which tensors get stored above base width (Q4_K_M keeps attention.v and MLP down-proj at higher precision than Q4_K_S). Published effective bpw varies by model: Q4_K_M measures 4.84 bpw on Llama-2-7B, 4.83 on 13B and 4.80 on 70B in llama.cpp's table.7 The repository's perplexity measurements are specific to the tested LLaMA checkpoints and do not establish a universal quality penalty for another model or task.

Putting the Formats Side by Side

Effective bits and what you pay for them, using beffb_{\text{eff}} from the group-overhead formula (integer formats at typical group 128; NVFP4 at 4.50; GGUF at published bpw):

Formatbeffb_{\text{eff}}GB per 33.4B paramsQuality position
FP16 / BF1616.066.7 GBreference
FP8 E4M3 (+3% assumed scale overhead)8.2434.4 GBQuality depends on checkpoint and calibration
GGUF Q8_08.535.4 GBperplexity delta 0.0068% on the archived LLaMA-1-7B test7
GGUF Q6_K6.562527.4 GBQuality depends on model and task; ~59% smaller than FP16
GGUF Q4_K_M4.8420.2 GBPublished bpw for one Llama-2-7B quantization7
NVFP44.50 (FP8 scales included)~18.8 GBClose to FP8 on NVIDIA's tested DeepSeek checkpoint4; other tensors and padding may add bytes
AWQ / GPTQ int4 (+12% overhead)4.4818.7 GBstrong at g=128; AWQ guards salient channels2
MXFP44.2517.7 GBNVIDIA reported a 36% pretraining-token gap in one head-to-head study5

Three honest observations fall out of the table:

  1. The example 4-bit widths span about 17.7–20.2 GB for 33.4B weights, before unquantized tensors, KV cache and runtime allocations. The site calculator's NVFP4 entry uses 4.5 bpw, which already includes the FP8 block scales; it does not add another 10%.
  2. FP8 halves the raw payload relative to FP16/BF16, but scales and unchanged tensors add bytes. Quality depends on the model, checkpoint and task.
  3. The relative accuracy of NVFP4, MXFP4, AWQ and GGUF quantizations must be measured on the same model and evaluation set. NVIDIA's published FP8-versus-NVFP4 results describe its specific conversion study, not a universal 1% bound.

Which Format Should You Run?

Self-hosted, single-user or small-batch (llama.cpp/LM Studio/Ollama): start Q4_K_M. Size any step-up with P×beff/8P \times b_{\text{eff}}/8 against your VRAM after reserving KV-cache (the break-even calculator's KV math applies unchanged). If code/math quality matters, Q6_K; if you are establishing a reference, Q8_0.

vLLM/SGLang/TensorRT-LLM serving on Hopper: FP8 (E4M3 weights, per-tensor or per-block scales per your runtime's support). 4-bit integer weights (AWQ/GPTQ) when VRAM pressure demands it — expect a measurable but small quality step.

Blackwell serving at scale: consider NVFP4 when the checkpoint and runtime support it. It is native to Blackwell's FP4 tensor cores; NVIDIA reported close accuracy to FP8 in a particular DeepSeek conversion study, which should be reproduced on your task. MXFP4 is an OCP standard with a different 4.25-bpw block layout.

Whatever you pick, measure. Publish your own before/after on your workload — the perplexity deltas above are Llama-family measurements under llama.cpp calibration; arrival distributions, long-context regimes, and tool-calling patterns shift them. The formulas in this article give you the frontier; only your benchmark tells you where on it to sit.

Further Reading

Footnotes

  1. Peng et al., FP8 Formats for Deep Learning, arXiv:2209.05433 (NVIDIA/Arm/Intel): https://arxiv.org/abs/2209.05433 ↩ ↩2

  2. Lin et al., AWQ: Activation-aware Weight Quantization for LLM Compression and Acceleration, MLSys 2024: https://arxiv.org/abs/2306.00978 ↩ ↩2 ↩3

  3. Open Compute Project, Microscaling Formats (MX) Specification v1.0 — block size k=32, E8M0 shared scale: https://www.opencompute.org/documents/ocp-microscaling-formats-mx-v1-0-spec-final-pdf ↩ ↩2

  4. NVIDIA Developer Blog, Introducing NVFP4 for Efficient and Accurate Low-Precision Inference (block layout, E4M3+F32 scaling, DeepSeek-R1-0528 accuracy, ~3.5×/~1.8× footprint ratios): https://developer.nvidia.com/blog/introducing-nvfp4-for-efficient-and-accurate-low-precision-inference/ ↩ ↩2 ↩3 ↩4

  5. NVIDIA Efficient AI research blog, Pushing Intelligence to 4-bit (~88% error reduction vs power-of-2 scaling; MXFP4 +36% tokens head-to-head; MMLU-Pro/GPQA/AIME numbers): https://research.nvidia.com/labs/eai/blogs/pushing-intelligence-to-4-bit/ ↩ ↩2 ↩3

  6. Frantar et al., GPTQ: Accurate Post-Training Quantization for Generative Pre-trained Transformers: https://arxiv.org/abs/2210.17323 ↩ ↩2

  7. llama.cpp source, k-quant structs and size assertions: https://github.com/ggml-org/llama.cpp/blob/master/ggml/src/ggml-common.h . Historical llama.cpp quantization table for the stated LLaMA checkpoints (the README has since moved): https://github.com/ggml-org/llama.cpp/diffs/3?commit=19d8762ab61df8286367588a80b9c7db4cb568db&name=master&sha1=c2a16c0bdbe2e51adf318918bad82f0c3e3d6f3b&sha2=19d8762ab61df8286367588a80b9c7db4cb568db&short_path=840f51c&w=false ↩ ↩2 ↩3 ↩4