Online quantization best practices#
This guide provides practical guidance for choosing an --online_quant_config.
It starts with a conservative configuration and expands quantization coverage
one step at a time, making it easier to attribute any accuracy regression to a
specific change.
For flag syntax, supported target formats, pattern resolution order, and how to
interpret the online_quant_info_*.json dump, see the
online quantization guide. This document
focuses on configuration selection and the recommended evaluation order.
Scope
Hardware: the examples below use the AMD Instinct MI300 and MI350/MI355 series as concrete cases. The methodology is not hardware-specific — on a different GPU, keep the same layer-selection and step-by-step coverage strategy and only adjust the format to what the hardware accelerates.
Beyond load-time quantization: the reasoning about which layers tolerate quantization and which do not applies equally when you are searching for an offline recipe with Quark, so the conservative-to-aggressive progression below carries over directly. Load-time quantization is plain round-to-nearest, so it is the cheaper way to find the layer assignment; once you have settled on one, Quark can push the same recipe further with accuracy-recovery techniques such as rotation and SmoothQuant. See Online vs. offline quantization for when to make that switch.
Recap of the three fields#
--online_quant_config '{
"global_quant_config": "ptpc_fp8",
"layer_quant_config": {"*expert*": "mxfp4"},
"exclude_layer": ["lm_head", "*.gate.*"]
}'
global_quant_config— the default target format for every Linear and fused MoE module.layer_quant_config— per-layer overrides, keyed by glob patterns matched against the fully-qualified module name frommodel.named_modules().exclude_layer— patterns left at source precision.
Under the vLLM plugin backend the same object
is passed as --additional-config '{"online_quant_config": {...}}'; every
recommendation below applies unchanged.
What “excluded” means#
exclude_layer leaves a layer at the source checkpoint’s precision, which
is not necessarily BF16:
Source checkpoint |
An excluded layer stays in |
|---|---|
Unquantized (BF16/FP16) |
BF16/FP16 |
Block FP8 (e.g. DeepSeek-R1-0528) |
Block FP8 |
This matters when reading the recommendations below. “Keep attention out of quantization” means “do not apply a new target format to it” — on an FP8 checkpoint that layer is still FP8, not floating point. If you need a layer in BF16 you have to start from a BF16 checkpoint.
Choosing a format#
The accuracy and performance of FP8 formats are model-specific. ptpc_fp8,
per_block_fp8, and mxfp8 use different scaling granularities and scale
representations, so their relative behavior can vary across models, layer types,
and hardware. There is no universal ordering from conservative to aggressive
among these three FP8 formats.
This guide uses ptpc_fp8 as the representative 8-bit format to explain
layer-selection and step-by-step coverage strategies. It uses FP8 E4M3 with
per-channel static weight scales and dynamic activation scales, and is a
conservative, general-purpose default. Using it in the examples does not imply
that it is more accurate than every other FP8 format on every model.
Other 8-bit formats can be substituted based on measured accuracy and performance:
per_block_fp8/per_block128_fp8uses DeepSeek-style 128×128 block scaling. Consider it when the source checkpoint already uses block FP8 or its kernels perform better on the target hardware.mxfp8uses microscaling FP8 with group size 32 and E8M0 block scales. Choose it based on accuracy, throughput, and hardware support on the target model.
Regardless of the FP8 format, the layer-selection strategy below remains the
same: exclude sensitive paths first, then expand coverage one step at a time. In
practice, use the ptpc_fp8 examples to establish a layer assignment, then
compare alternative FP8 formats with A/B evaluation.
mxfp4 is the clearly more aggressive low-bit target: OCP MXFP4, group size 32,
and E8M0 block scales. It fits MoE experts well, because that is where most of
the parameters and memory bandwidth go. It saves the most memory but is the most
likely to hurt accuracy on sensitive paths such as attention and shared experts.
Hardware support#
mxfp4 needs native MXFP4 acceleration, which is available on CDNA 4 GPUs such
as the AMD Instinct MI350/MI355. The MI300 series (CDNA 3) does not accelerate
MXFP4.
On MI300, skip every mxfp4 step below — but keep the layer selection from
those steps. The decisions about what to exclude (lm_head, router/gate, shared
experts, attention, vision modules) are independent of the format. Read the
levels below, keep their exclude_layer and layer_quant_config layer choices,
and express the whole recipe in ptpc_fp8.
What to exclude by default#
lm_head#
lm_head maps hidden states straight to vocabulary logits, so quantization
error there can reorder tokens. That shows up as degraded generation quality,
unstable formatting, and changed reasoning paths. The parameter savings are not
worth the risk:
"exclude_layer": ["lm_head"]
Router and gate layers#
Here “gate” means the router, gating, or control-path module — not the
regular MLP gate_proj. These modules decide where information flows. They are
small, so quantizing them saves almost nothing, but an error is amplified by
everything downstream: in an MoE model a small router error changes the top-k
expert assignment for a token, which sends it through entirely different weights.
"exclude_layer": ["lm_head", "*.gate.*"]
Avoid a broad *gate* unless you have checked that it does not also catch
gate_proj, which is an ordinary FFN Linear and is usually safe to quantize.
Replace *.gate.* with the exact router prefix your model uses.
Vision modules in VLMs#
Do not apply a text-only policy to a vision-language model. The vision tower, patch embedding, and multi-modal projector see very different input distributions, and errors there may not move text perplexity at all while clearly degrading image-text understanding.
"exclude_layer": [
"lm_head",
"*.gate.*",
"*attn*",
"<vision_encoder_pattern>",
"<multi_modal_projector_pattern>"
]
Replace the placeholders with the actual module prefixes for your model’s vision tower, patch embedding, and image/video projector. Only consider quantizing them after the language decoder is known to be healthy, and validate them on image-text tasks rather than text-only metrics.
MoE models#
MoE models need the most care. Almost all the parameters are in the experts, while almost all the accuracy risk is in routing, shared experts, and attention. Attention is a small share of an MoE model’s parameters and compute, so quantizing it buys little and can cost a lot.
Where to start#
Pick an entry point based on what you care about, rather than always starting in the same place:
Accuracy-sensitive: start at Level 0 —
ptpc_fp8on non-attention Linear layers only, with router/gate, shared experts, and attention excluded. This is the lowest-risk configuration.Latency-sensitive: start at Level 4 — global
mxfp4, excluding onlylm_headand the router/gate. This gives the largest memory and bandwidth saving and needs MI350/MI355-class hardware. On MI300, use globalptpc_fp8with the same exclusions.Tuning back down: if an aggressive configuration fails evaluation, walk the levels backward one step at a time. Each step moves the most sensitive remaining path — attention first, then shared experts, then regular experts — to a safer format.
The levels are ordered from most conservative to most aggressive. Read top-down if you are starting conservative, bottom-up if you are stepping down from an aggressive configuration.
Which MoE components are sensitive#
Router / gate. Excluded by default, because it decides which experts see each token. Even a small error can change expert selection, and then the token is processed by different weights entirely. The benefit is negligible.
Shared experts. Exclude them in the first stage. Shared experts serve all or most tokens, so they behave more like a global FFN or a residual path than like regular experts, and they are correspondingly more sensitive to distribution shift. Quantizing them early tends to degrade quality broadly. Start with the regular experts.
Attention. Handle conservatively. Attention mixes information across tokens,
and long-context or reasoning models are especially sensitive to it. Keep it out
of quantization first; if you later want to include it, use ptpc_fp8 rather
than mxfp4.
Note that *expert* matches shared experts too (...mlp.shared_experts as well
as ...mlp.experts). Because exclude_layer is evaluated before
layer_quant_config, listing *shared_expert* in exclude_layer is what keeps
them out, even when *expert* also appears as an override.
Level 0 — non-attention Linear layers in ptpc_fp8#
--online_quant_config '{
"global_quant_config": "ptpc_fp8",
"exclude_layer": ["lm_head", "*.gate.*", "*shared_expert*", "*attn*"]
}'
This is the MoE accuracy baseline. Attention is deliberately left alone: small benefit, large risk.
If even this fails evaluation, do not move on to mxfp4. Check the
online_quant_info_*.json dump first — a typo in a pattern that sends every
layer into exclude_layer (or fails to exclude the router) is far more likely
than a genuine ptpc_fp8 accuracy problem. Verify the layer count and the
per-layer formats as described in the
online quantization guide.
Level 1 — regular experts in mxfp4#
--online_quant_config '{
"global_quant_config": "mxfp4",
"exclude_layer": ["lm_head", "*.gate.*", "*shared_expert*", "*attn*"]
}'
The first aggressive step targets regular experts only; shared experts and
attention stay excluded. The point of this level is to establish whether the
regular experts tolerate mxfp4 at all.
Level 2 — all MoE experts in mxfp4#
--online_quant_config '{
"global_quant_config": "mxfp4",
"exclude_layer": ["lm_head", "*.gate.*", "*attn*"]
}'
Once regular experts pass, bring the shared experts in. Attention is still excluded, so any regression is isolated to the MoE blocks.
Level 3 — attention in ptpc_fp8#
--online_quant_config '{
"global_quant_config": "ptpc_fp8",
"layer_quant_config": {"*expert*": "mxfp4"},
"exclude_layer": ["lm_head", "*.gate.*"]
}'
If all experts pass in mxfp4 and you still want to reduce the unquantized
footprint, move attention in — at ptpc_fp8, not mxfp4.
Level 4 — global mxfp4#
--online_quant_config '{
"global_quant_config": "mxfp4",
"exclude_layer": ["lm_head", "*.gate.*"]
}'
Attention is now in mxfp4 as well. Treat this as the highest-risk
configuration and validate it carefully before deploying.
Dense models#
Without expert routing the progression is much shorter:
Global
ptpc_fp8, excludinglm_head.If accuracy holds, try global
mxfp4.If global
mxfp4regresses, override the model’s attention pattern back toptpc_fp8.
Safe starting point:
--online_quant_config '{
"global_quant_config": "ptpc_fp8",
"exclude_layer": ["lm_head"]
}'
More aggressive:
--online_quant_config '{
"global_quant_config": "mxfp4",
"exclude_layer": ["lm_head"]
}'
Step 3, expressed as an override:
--online_quant_config '{
"global_quant_config": "mxfp4",
"layer_quant_config": {"*attn*": "ptpc_fp8"},
"exclude_layer": ["lm_head"]
}'
Vision-language models#
Quantize the language decoder first and keep the vision side out. Follow the dense or MoE progression above for the language part:
--online_quant_config '{
"global_quant_config": "ptpc_fp8",
"exclude_layer": [
"lm_head",
"<vision_encoder_pattern>",
"<multi_modal_projector_pattern>"
]
}'