, ,

Quantization: how to fit a bigger model in less VRAM

How quantization shrinks LLM weights from 16-bit to 8-bit and 4-bit: the formula, why it speeds up decode, FP8, INT8, INT4, NVFP4 and MXFP4 explained, how much quality you lose, how to quantize a model and how to choose a format for your GPUs.

Model weights shrinking from 16-bit to 8-bit and 4-bit

AI Infrastructure series · Part 18 of 24

A 70-billion-parameter model in its original 16-bit form needs 141 GB just for its weights: two H100s before a single user connects. Stored in 8-bit it needs about 71 GB, and in 4-bit under 40 GB. That is quantization: keeping each weight in fewer bits. This part shows how a GPU stores a number bit by bit, works through quantizing real-looking weights by hand in INT8, INT4 and FP4, explains why outliers and block scales matter, and ends with the vLLM commands and a decision guide for FP16/BF16, FP8 and FP4.

Try it: Quantization Lab

Four tabs: check whether a model fits and how fast it decodes, type a number and see how BF16, FP8 and FP4 store it bit by bit, step through quantizing eight weights, and compare one shared scale against blocks of 16, 32 or 128.

Open the demo →

What is quantization, and why does it matter so much?

A model is mostly weights: billions of numbers learned during training (part 9). Most models are trained and released in a 16-bit format, BF16 or FP16, so each weight takes 2 bytes. Quantization stores those same weights in fewer bits: 8 bits (1 byte) or 4 bits (half a byte). Fewer bits means fewer possible values, so every weight is rounded to the nearest value the smaller format can hold.

Three things improve at once. The weights take less memory, so a model fits on fewer or smaller GPUs (part 7). The memory freed goes to the KV cache, so more conversations fit (part 14). And decode gets faster, because generating each token means reading every active weight from memory, and fewer bytes take less time to read (part 4). The price is rounding error. The rest of this part is about where that error comes from and how to keep it small.

params × bits ÷ 8bytes for the weights
70.6B × 8 ÷ 8Llama 3.1 70B in FP8
≈ 71 GBagainst 141 GB in BF16

How does a GPU store a number?

A floating-point number has three parts, like scientific notation in binary. The sign bit says positive or negative. The exponent picks a power of two, which sets how big the number is: its range. The mantissa (also called the fraction) says where the number sits between that power of two and the next one: its precision. The value is roughly sign × 1.mantissa × 2^exponent. Every format is a trade between those two budgets. More exponent bits reach bigger and smaller numbers; more mantissa bits put the steps closer together.

Each row stores π (3.14159…) in a different formatsignexponent (range)mantissa (precision)integer code (needs a scale)FP321 + 8 + 23 bits01000000010010010000111111011011stores 3.1415927 (error under one part in ten million) · max 3.4 × 10^38BF161 + 8 + 7 bits0100000001001001stores 3.140625 (0.031% off)same range as FP32, about 3 digitsFP161 + 5 + 10 bits0100001001001000stores 3.140625 (0.031% off)max 65,504, finer steps than BF16FP8 E4M31 + 4 + 3 bits01000101stores 3.25 (3.5% off)max 448, used for weights and activationsFP8 E5M21 + 5 + 2 bits01000010stores 3 (4.5% off)max 57,344, more range, less precisionFP4 E2M11 + 2 + 1 bits0101stores 3 (4.5% off)only 0, 0.5, 1, 1.5, 2, 3, 4, 6 (and negatives)INT88-bit integer01100100code 100 × scale 0.0315 = 3.1496 (0.26% off)codes -128 to 127; value = code × scale (block max 4 here)INT44-bit integer0101code 5 × scale 0.5714 = 2.8571 (9.1% off)codes -8 to 7; value = code × scale (block max 4 here)

Each format storing π. BF16 keeps FP32’s 8 exponent bits and drops 16 mantissa bits, so it has the same range but only about 3 significant digits. FP8 and FP4 cannot get close to π on their own; INT8 and INT4 store a whole-number code that is multiplied by a scale shared with other values (here the largest value in the block is assumed to be 4).

The table puts numbers on that trade. “Step near 1” is the gap between 1 and the next value the format can store, which is the best relative precision it offers.

FormatBits (S + E + M)Largest valueSmallest normal valueStep near 1Used for
FP321 + 8 + 233.4 × 10^381.2 × 10^-380.00000012Optimizer master weights in training
BF161 + 8 + 73.4 × 10^381.2 × 10^-380.0078Training and release format
FP161 + 5 + 1065,5040.0000610.00098Older release format, activations
FP8 E4M31 + 4 + 34480.01560.125Weights and activations
FP8 E5M21 + 5 + 257,3440.0000610.25Gradients, some KV caches
FP4 E2M11 + 2 + 161 (0.5 as subnormal)0.5Blackwell 4-bit, always with block scales
INT88-bit integer127 × scale1 × scaleeven stepsW8A8 on any modern GPU
INT44-bit integer7 × scale1 × scaleeven stepsWeight-only 4-bit (GPTQ, AWQ)

Two things stand out. First, FP8 E4M3 can only reach 448, and FP4 only 6. Real weights are small numbers, mostly well under 1, but activations can be in the hundreds. So low-bit formats always come with a scale factor: the values are divided by a scale before rounding, so they land inside the format’s range, and multiplied by it again when used. Second, integers and floats spread their values differently. INT4 has 15 evenly spaced levels. FP4 E2M1 has 15 values packed closely near zero and spread out towards 6. Trained weights follow roughly a bell curve, with most values near zero and a few large ones, so FP4’s spacing matches them better.

FP4 E2M1: 15 values, dense near zero-6-4-20246INT4 (scaled so its maximum is also 6): 15 even steps-6-4-20246where most weights land after scaling (illustrative)

FP4 E2M1 against INT4 with the same maximum. FP4 spends its values where weights are dense (steps of 0.5 near zero) and accepts big gaps (4 to 6) where few weights live. INT4 uses the same step everywhere.

How does quantization work, step by step?

The simplest method is called absmax (or round-to-nearest) quantization, and every other method builds on it. It works on a group of weights at a time:

1

Find the largest absolute value in the group, the absmax. This is the number that must still fit after rounding.

2

Work out the scale: absmax divided by the largest code the format can hold. That is 127 for INT8, 7 for INT4, 6 for FP4 and 448 for FP8 E4M3.

3

Divide every weight by the scale and round to the nearest value the format can store. This gives the stored codes.

4

Store the codes plus the scale. The scale is kept in higher precision (FP16, FP32 or FP8, depending on the format).

5

At run time, multiply each code by the scale (dequantize) to get back an approximation of the original weight. The difference is the quantization error.

The animation shows the same flow for one block of 16 weights in NVFP4, split between what happens once (when someone quantizes the model) and what happens for every token while it is served.

Once, when the model is quantized (offline) 1 · Take a block 16 weights in BF16 0.12, -0.45, 0.03, 0.88, -0.27 … 16 × 2 B = 32 B 2 · Find absmax largest |weight| in the block absmax = 0.88 3 · Set the scale absmax ÷ FP4 max 0.88 ÷ 6 kept in FP8 scale = 0.147 4 · Divide, round 0.12 ÷ 0.147 = 0.82 nearest FP4 value: 1.0 (code 0010) 16 codes 5 · Pack and save 16 × 4 bits = 8 B + 1 B scale 9 B (was 32 B) checkpoint file written to disk, loaded into GPU memory (HBM) Every token, inside the GPU (while serving) 6 · Read from HBM 9 B for these 16 weights instead of 32 B 3.6× less memory traffic 7 · Unpack in registers code × scale 1.0 × 0.147 = 0.147 error against 0.12: 0.027 8 · Tensor-core maths Ada / Hopper: maths in BF16 Blackwell: maths in FP4 result in BF16 Steps 1 to 5 run once. Steps 6 to 8 repeat for every block of weights, for every token.

Quantizing and serving one NVFP4 block. Real NVFP4 also keeps one FP32 scale for the whole tensor; it is left out to keep the numbers simple. On GPUs without FP4 tensor cores, step 8 runs in BF16, so you keep the memory saving but not the faster maths.

A worked example in INT8, INT4 and FP4

Take eight weights from one row of a layer: 0.12, -0.45, 0.03, 0.88, -0.27, 0.51, -0.09 and 0.34. The absmax is 0.88. The three scales are 0.88 ÷ 127 = 0.00693 for INT8, 0.88 ÷ 7 = 0.1257 for INT4 and 0.88 ÷ 6 = 0.1467 for FP4. Divide, round, multiply back:

WeightINT8 codeINT8 backINT4 codeINT4 backFP4 (w ÷ s)FP4 valueFP4 back
0.12170.117810.12570.821.00.1467
-0.45-65-0.4504-4-0.5029-3.07-3.0-0.4400
0.0340.027700.00000.2000.0000
0.881270.880070.88006.006.00.8800
-0.27-39-0.2702-2-0.2514-1.84-2.0-0.2933
0.51740.512840.50293.483.00.4400
-0.09-13-0.0901-1-0.1257-0.61-0.5-0.0733
0.34490.339530.37712.322.00.2933
Average error0.0011 (about 0.3% of the weights’ average size of 0.34)0.0234 (about 7%)0.0279 (about 8%)

INT8 has 255 levels, so every weight lands within 0.003 of where it started. INT4 has only 15, and 0.03 rounds to zero. FP4 does a little worse than INT4 on this particular set, because its gaps widen away from zero: 0.51 falls between the stored values 0.44 and 0.59 and loses 0.07. On a full layer, with thousands of weights clustered near zero, FP4’s spacing usually helps; on eight hand-picked numbers it can go either way. Every error in a layer is small, but a model has billions of them, and they add up through 80 layers. That is why the method used to pick the rounding matters so much at 4 bits, and much less at 8.

Why do outliers hurt, and how do block scales fix them?

The weakness of absmax is that one large value sets the scale for everyone. Large language models are known for this: Dettmers and colleagues, in the LLM.int8() paper, found that from about 6.7 billion parameters, a few hidden dimensions carry values far larger than the rest. If one weight in a group is 1.6 and the others are around ±0.1, the INT4 scale becomes 1.6 ÷ 7 = 0.229, and every weight smaller than half of that, 0.114, rounds to zero.

One scale for all 32 weightsscale = 1.6 / 7 = 0.229 · 25 of 32 become 0 · avg error 0.0491.6One scale per block of 16block 2 scale = 0.0334 · 15 of 32 become 0 · avg error 0.0271.6block 1 (holds the outlier)block 2 (own, smaller scale)original weightstored 4-bit valuelevels the format can hold

Illustrative: 32 weights drawn from a bell curve with one outlier (1.6, drawn cut off), quantized to INT4 with absmax scaling. Grey bars are the originals, red dots the stored values, pink lines the levels available. With one scale, most weights collapse to zero. With a scale per 16 weights, the outlier only damages its own block.

The fix is to give small groups of weights their own scale. This is called group-wise or block scaling. The cost is storage: each block needs its scale, so the real size per weight grows. With a 16-bit scale per 128 weights, INT4 costs 4 + 16 ÷ 128 = 4.125 bits per weight; per 32 weights it is 4.5 bits. The benefit, for the same 32 weights, looks like this:

One scale for 3225 of 32 weights become 00.049
Blocks of 1615 of 32 become 00.027
Blocks of 8outlier isolated further0.013

Average absolute error for the 32 illustrative weights above, INT4 absmax per block.

The two FP4 formats on Blackwell build this idea into the hardware. Both use the same 4-bit E2M1 values; they differ in block size and in what the scale can be.

NVFP4 (NVIDIA)a scale for every 16 values, stored as FP8 E4M3, plus one FP32 scale per tensorE4M3E4M34.5 bits/value(16×4 + 8) ÷ 16MXFP4 (OCP Microscaling standard)one scale for every 32 values, an 8-bit power of two (E8M0)E8M04.25 bits/value(32×4 + 8) ÷ 32Block max 0.88, FP4 max 6, so the ideal scale is 0.88 ÷ 6 = 0.147NVFP4: the scale can be 0.156 (an E4M3 value just above 0.147), so the block max lands at 5.6 of 6.MXFP4: only powers of two. 0.125 clips the max to 0.75; 0.25 avoids clipping but uses FP4 only up to 3.5.

Memory layout for 32 values. NVFP4 pays slightly more storage for smaller blocks and a scale that can take fractional values. MXFP4’s power-of-two scale is cheaper to apply in hardware but wastes part of FP4’s range in most blocks.

NVFP4’s finer scale and smaller blocks are designed to keep more accuracy than MXFP4 at almost the same size. MXFP4 is an open standard from the Open Compute Project, supported beyond NVIDIA, and it is the format OpenAI chose for the expert weights of gpt-oss: that is how the 117-billion-parameter gpt-oss-120b fits on one 80 GB GPU.

What can you quantize: weights, activations or the KV cache?

Three different things in GPU memory can be stored in fewer bits, and each one speeds up a different part of serving. Recall from part 13 that prefill (reading the prompt) is limited by compute, and decode (one token at a time) is limited by memory bandwidth.

Weight-only (W4A16) SM: tensor cores unpack 4-bit → BF16 in registers BF16 × BF16 maths 0.5 B per weight HBM weights: 4-bit KV: 16-bit Speeds up: decode prefill maths unchanged Weights + activations (W8A8 FP8) SM: FP8 tensor cores FP8 × FP8 maths H100: 1,979 vs 989 TFLOPS 1 B per weight HBM weights: FP8 KV: 16-bit Speeds up: decode and prefill needs Ada, Hopper or Blackwell KV cache (FP8 KV) SM: attention reads every past K and V half the bytes per token 1 B per value HBM weights: any KV: FP8 Speeds up: long contexts and doubles users per GPU

What sits in GPU memory (HBM) and what the streaming multiprocessors compute with, for each kind of quantization. Bar widths show bytes per value. The three can be combined: FP8 weights and activations with an FP8 KV cache is a common production setting.

SchemeWhat is stored smallMaths runs inMemory savedSpeeds upGPUs
W4A16 (GPTQ, AWQ)Weights, 4 bitsBF16about 3.7× on weightsDecode at small batchAny recent NVIDIA GPU
W8A16Weights, 8 bitsBF162× on weightsDecodeAny; how FP8 checkpoints run on Ampere
W8A8 INT8Weights and activationsINT82× on weightsDecode and prefillAmpere and newer
W8A8 FP8Weights and activationsFP82× on weightsDecode and prefillAda, Hopper, Blackwell
NVFP4 / MXFP4 (W4A4)Weights and activationsFP4about 3.6× on weightsDecode and prefillBlackwell
FP8 KV cacheKeys and valuesattention in 16-bit or FP82× on KV cacheLong context, batch sizeAda, Hopper, Blackwell

Why does weight-only 4-bit not speed up prefill? In prefill the GPU multiplies the weights by thousands of prompt tokens at once, so it does many calculations per byte read and the limit is tensor-core speed, not memory. W4A16 still does the maths in BF16, at BF16 speed, plus the extra work of unpacking. At large batch sizes it can even be slightly slower than FP8. W8A8 and W4A4 change the maths itself, which is why they help both phases.

How much memory and speed do you gain?

Start with memory. The table uses the makers’ published parameter counts, and includes the block scales for 4-bit formats (INT4 with group scales and MXFP4 about 4.25 bits per weight, NVFP4 about 4.5). Real checkpoints keep a few layers, such as embeddings and the output layer, in 16-bit, so files come out slightly larger.

ModelParametersBF16FP8 / INT8INT4 / MXFP4NVFP4
Llama 3.1 8B8.03B16.1 GB8.0 GB4.3 GB4.5 GB
Llama 3.1 70B70.6B141 GB71 GB37.5 GB39.7 GB
gpt-oss-120b (MoE)117B (5.1B active)234 GB117 GB62 GB66 GB
Llama 3.1 405B405B810 GB405 GB215 GB228 GB
DeepSeek-V3 (MoE)671B (37B active)1,342 GB671 GB356 GB377 GB

That memory turns straight into users. Take Llama 3.1 70B, with its KV cache of 320 KB per token in 16-bit, and conversations of 8,000 tokens (2.6 GB each). Keep 10% of each GPU free, so an H100 offers 72 GB:

BF16 on 2 × H100144 − 141 GB1 user
INT4 on 1 × H10072 − 37.5 GB, 16-bit KV13 users
INT4 + FP8 KV, 1 × H100same, 1.3 GB per user26 users
FP8 + FP8 KV, 2 × H100144 − 71 GB56 users

Illustrative: conversations that fit at once, from memory alone. Real engines also reserve memory for activations and CUDA graphs.

Why do fewer bytes make decode faster? A worked calculation

For one user, generating one token means reading every weight once. The time cannot be shorter than bytes ÷ memory bandwidth. For Llama 3.1 8B on one H100 (3.35 TB/s):

1

BF16: 16.1 GB ÷ 3,350 GB/s = 4.8 ms per token, a ceiling of 208 tokens per second.

2

FP8: 8.0 GB ÷ 3,350 GB/s = 2.4 ms per token, a ceiling of 417 tokens per second.

3

INT4 with group scales: 4.3 GB ÷ 3,350 GB/s = 1.27 ms per token, a ceiling of 785 tokens per second.

4

Real kernels reach part of peak bandwidth. At an assumed 70%, that is about 146, 292 and 549 tokens per second.

BF1616.1 GB per token~146 tok/s
FP88.0 GB per token~292 tok/s
INT4 (W4A16)4.3 GB per token~549 tok/s

Illustrative upper bounds for one user, Llama 3.1 8B on one H100, 70% of peak bandwidth, KV cache reads ignored.

The same sum explains a useful result for the 70B model. BF16 on two H100s reads 141 GB at 6.7 TB/s combined: 21 ms per token. FP8 on one H100 reads 71 GB at 3.35 TB/s: also 21 ms. FP8 gives the same single-user speed on half the GPUs. The gain shrinks as batches grow, because many users share each weight read and the KV cache becomes a larger share of the traffic, which is where an FP8 KV cache helps.

Which GPUs support which formats?

Any GPU can store weights in any format; the question is whether its tensor cores can do the maths in that format. If not, the engine unpacks the weights to 16-bit inside the kernel. You still save memory and decode bandwidth, but not compute.

GenerationExamplesINT8 mathsFP8 mathsFP4 mathsGood default
AmpereA100, A10YesNo (FP8 runs as W8A16)NoW4A16 or W8A8 INT8
Ada LovelaceL40S, L4, RTX 4090YesYes (E4M3, E5M2)NoFP8 W8A8, FP8 KV
HopperH100, H200YesYesNoFP8 W8A8, FP8 KV
BlackwellB200, GB200YesYesYes (NVFP4, MXFP4)FP8, then test NVFP4

Peak dense rates show what native support buys: an A100 does 312 TFLOPS in BF16 and 624 TOPS in INT8; an H100 989 TFLOPS in BF16 and 1,979 in FP8; an L40S 733 in FP8. vLLM’s documentation puts the FP8 W8A8 requirement at compute capability 8.9 or higher, which means Ada and newer.

How do you keep the quality?

FP8 with a scale per tensor or per channel is usually close to lossless and needs no special method. At 4 bits, and for INT8 activations, simple rounding loses too much, so several methods choose the rounding more carefully. Most need a small calibration set: a few hundred sample prompts, run through the model so the tool can see real activation values.

MethodWhat it doesNeedsTypical use
Round to nearestAbsmax scale, round each value; the baselineNothingFP8 weights, quick tests
CalibrationRecords activation ranges on sample prompts to fix static scalesA few hundred promptsW8A8 static scales, FP8 KV scales
GPTQQuantizes one column at a time and adjusts the remaining weights to cancel the error, using second-order information; the paper quantized 175B-parameter models in about four GPU hoursCalibration dataW4A16, W8A8 INT8
AWQFinds the small share of weight channels (about 1%) that meet large activations and scales them up before rounding so they keep precisionCalibration dataW4A16
SmoothQuantMoves outliers from activations into the weights with a per-channel scale, so both fit in 8 bitsCalibration dataW8A8 INT8
Quantization-aware trainingTrains or fine-tunes with simulated rounding so the model learns to copeA training runBest 4-bit quality

How do you know it worked? Compare the quantized model against the 16-bit original, not against impressions from a few chats.

  • Standard benchmarks. Run the same tasks on both, for example with lm-evaluation-harness against a vLLM endpoint. Maths (GSM8K) and code tend to show 4-bit damage first; general knowledge (MMLU) last.
  • Your own prompts. Fifty to a few hundred real prompts with known good answers, scored the same way for both versions.
  • Long inputs. Errors build up over long contexts and long reasoning chains; test the longest documents you will serve.
  • Speed, too. Measure tokens per second and time to first token at your real batch size; a format your GPU cannot compute natively may save memory and lose speed.

How do you run a quantized model in practice?

The easiest route is a checkpoint someone has already quantized and tested. vLLM reads the quantization settings from the model’s config file, so nothing extra is needed:

# FP8 weights and activations, scales already in the checkpoint
vllm serve RedHatAI/Meta-Llama-3.1-8B-Instruct-FP8

# 4-bit weight-only (W4A16): 70B on one 80 GB GPU
vllm serve RedHatAI/Meta-Llama-3.1-70B-Instruct-quantized.w4a16 \
  --max-model-len 16384

# Add an FP8 KV cache to any of these: twice the tokens fit
vllm serve RedHatAI/Meta-Llama-3.1-8B-Instruct-FP8 --kv-cache-dtype fp8

# No quantized copy available: convert BF16 weights to FP8 at load time
vllm serve meta-llama/Llama-3.1-8B-Instruct --quantization fp8

The last option is the quickest to try. Recent vLLM releases also list it as fp8_per_tensor; it uses one scale per tensor and computes activation scales on the fly. At start-up, the log line that reports model loading shows how many GiB the weights take: around 8.5 for the FP8 8B model instead of about 15 in BF16. A bit later, the line about the KV cache shows how many tokens fit, which is the number that should roughly double when you add --kv-cache-dtype fp8.

To make your own calibrated copy, LLM Compressor (part of the vLLM project) applies a recipe to a Hugging Face model and saves a checkpoint vLLM can load. A full walk-through with a Granite model is in this LLM Compressor post. The shape of it:

from transformers import AutoModelForCausalLM, AutoTokenizer
from llmcompressor import oneshot
from llmcompressor.modifiers.quantization import QuantizationModifier

model_id = "meta-llama/Llama-3.1-8B-Instruct"
model = AutoModelForCausalLM.from_pretrained(model_id, device_map="auto", dtype="auto")
tok = AutoTokenizer.from_pretrained(model_id)

# FP8 weights, dynamic FP8 activations; keep the output layer in 16-bit
recipe = QuantizationModifier(targets="Linear", scheme="FP8_DYNAMIC", ignore=["lm_head"])
oneshot(model=model, recipe=recipe)

model.save_pretrained("Llama-3.1-8B-Instruct-FP8")
tok.save_pretrained("Llama-3.1-8B-Instruct-FP8")

FP8 dynamic needs no calibration data. For 4-bit, swap the modifier for GPTQModifier with scheme="W4A16", or use the NVFP4 scheme for Blackwell, and pass a calibration dataset to oneshot. Then evaluate as above before the copy goes anywhere near users.

Which format should you choose?

Which GPU generation? Ampere or older W4A16 (GPTQ / AWQ) or INT8 W8A8 Ada or Hopper FP8 weights + activations plus FP8 KV cache Blackwell FP8 first, then test NVFP4 for the biggest models Fits with room for the KV cache at your target users and context length? yes no Evaluate against BF16 benchmarks + your prompts + long inputs, then ship Go to 4-bit weights or add GPUs a well-made 4-bit model often beats a smaller model in 16-bit

A starting point, not a rule. Whatever the route, the last step is the same: compare against the 16-bit original on your own tasks.

For MoE models (part 12), quantization shrinks every expert, including the ones that sit idle for most tokens, so it is often what makes a large MoE model fit at all. DeepSeek-V3 was trained largely in FP8, and gpt-oss ships its experts in MXFP4: for these models the low-bit format is the original, not a copy.

Common mistakes

  • Counting only the weights. A model that “fits” with 1 GB left over serves one short conversation. Size for weights plus the KV cache your users need (part 20 does the full sum).
  • Expecting FP4 speed on a GPU without FP4 tensor cores. NVFP4 on an H100 is unpacked to 16-bit for the maths. You keep the memory saving and lose the compute gain.
  • Expecting W4A16 to speed up long prompts. It helps decode; prefill still runs in BF16.
  • Judging quality by chatting with it. 4-bit damage shows first in maths, code and long reasoning, which casual chat does not exercise.
  • Quantizing everything. Tools leave the output layer (and often embeddings) in 16-bit for a reason; forcing them low saves little and costs accuracy.
  • Thinking 4 bits means 4 bits. Block scales add 0.125 to 0.5 bits per weight; NVFP4 is about 4.5.

Questions people ask about quantization

Is FP8 really as good as BF16?

For most large models, close enough that benchmarks barely move, which is why it is the usual production format on Hopper and Ada. Still compare on your own tasks before switching.

Should I use INT4 or FP4?

On Blackwell, NVFP4, because the tensor cores compute in it directly. On older GPUs, INT4 weight-only (GPTQ or AWQ) has the most mature kernels; FP4 weights would be unpacked anyway.

Does quantization change what the model knows?

No new knowledge is added or removed on purpose, but every weight moves slightly. At 8 bits the effect is usually tiny; at 4 bits and below, rare facts and long reasoning chains are the first to suffer.

Can I fine-tune a quantized model?

Yes, with adapters. QLoRA keeps a 4-bit base frozen and trains small 16-bit adapters on top, which is the subject of part 19.

Is a bigger quantized model better than a smaller full-precision one?

Often, for the same memory: a well-quantized 70B model at about 40 GB usually beats an 8B model in 16-bit at 16 GB, and many teams pick that trade. Measure it for your tasks.

Quantization checklist
  • Weights = parameters × bits ÷ 8, plus block scales and a few 16-bit layers.
  • Match the format to the GPU: FP8 maths needs Ada, Hopper or newer; FP4 maths needs Blackwell.
  • Prefer models already published in FP8 or 4-bit by their makers or a trusted team.
  • Use block scales at 4 bits; one scale per tensor lets outliers wipe out small weights.
  • Quantize the KV cache too when memory for users is the limit.
  • Test quality against the 16-bit original on your own prompts, especially maths, code and long documents.

Sources: number-format layouts from IEEE 754 (FP32, FP16), the BF16 definition and the OCP 8-bit floating point (FP8) and Microscaling (MX) specifications; NVFP4 block size and scales from NVIDIA’s documentation. GPU rates from NVIDIA’s A100, H100 SXM and L40S specifications (dense). FP8 compute-capability requirement and FP8 KV cache options from the vLLM documentation; LLM Compressor recipe from its documentation. Outlier features from Dettmers et al., LLM.int8(); GPTQ from Frantar et al.; AWQ from Lin et al.; SmoothQuant from Xiao et al. gpt-oss parameter counts and MXFP4 release from OpenAI’s model card; DeepSeek-V3’s FP8 training from its technical report. Worked examples, user counts and speeds are illustrative calculations, not measurements.

About The Author


Discover more from Journal of Intelligent Infrastructure

Subscribe to get the latest posts sent to your email.

Leave a Reply

Your email address will not be published. Required fields are marked *

Architect’s Toolkit

About the Author

Dr. Pranay Jha is a Cloud and AI Consultant with 18+ years of experience in hybrid cloud, virtualization, and enterprise infrastructure transformation. He specializes in VMware technologies, multi-cloud strategy, and Generative AI solutions. He holds a PhD in Computer Applications with research focused on Cloud and AI, has published multiple research papers, and has been a VMware vExpert since 2016 and a VMUG Community Leader.

Discover more from Journal of Intelligent Infrastructure

Subscribe now to keep reading and get access to the full archive.

Continue reading