Skip to content

模型级精度映射 ​

模型级精度映射回答的是模型的哪些部分使用什么精度,量化算法回答的是低精度参数如何生成。主流推理引擎并不会任意给每一层分配 bit,而是把少数计算密集型模块替换为硬件支持的低精度实现,其余算子保留模型 dtype,再独立配置 KV Cache。

一、精度策略不等于量化算法 ​

对线性层 Y=XWT,W4A16、W8A8 只描述 weight 和 activation,完整实现还要决定累加、输出以及相邻算子的精度:

Y^=Castpout(Accpacc(XpA,WpW)).

其中,pW、pA、pacc 和 pout 分别表示 weight、activation、累加器和输出精度。它们与模型其他模块及 KV Cache 的 dtype 一起组成精度映射。

层次需要决定的问题例子
精度策略哪些模块或状态使用哪种 dtypeLinear 使用 W4A16,Norm 使用 BF16,KV Cache 使用 FP8
量化算法如何得到低精度 weight、activation 和 scaleGPTQ、AWQ、SmoothQuant、RTN
执行后端哪个 kernel 消费这种格式Marlin、CUTLASS、DeepGEMM、oneDNN

同一种精度策略可以由不同算法生成。例如,GPTQ、AWQ 和 AutoRound 都可以生成 W4A16 checkpoint;对推理引擎而言,真正决定执行路径的是 checkpoint 格式、模块范围和可用 kernel,而不是算法名称。

二、主流实现:替换 Linear/MoE,外围保持高精度 ​

这是服务器推理中最常见的实现。推理框架只为 Linear 和 FusedMoE 等矩阵乘模块安装低精度 method;RMSNorm、Softmax、RoPE、Residual Add 和激活函数没有被量化配置替换,继续使用模型 dtype 或算子内部指定的更高精度。

text
BF16/FP16 hidden states
  → Quantized Linear / Fused MoE
      Weight: W4 / W8 / FP8 / FP4
      Activation: A16 / A8 / A4
      Accumulate: kernel-defined wider dtype
      Output: BF16 / FP16
  → Norm / RoPE / Softmax / Residual in model dtype

SGLang 的 W8A8 FP8 配置就是这种分派:LinearBase 使用 FP8 Linear method,FusedMoE 使用 FP8 MoE method,其他模块返回 None。通用 FP8 配置还会让 ignored_layers 返回未量化的 Linear/MoE method。

📄 SGLang `w8a8_fp8.py`
python
def get_quant_method(self, layer, prefix):
    if isinstance(layer, LinearBase):
        return W8A8Fp8LinearMethod(self)
    elif isinstance(layer, FusedMoE):
        return W8A8FP8MoEMethod(self)
    return None

这类实现形成两种最常见的主体配置:

主体配置Linear/MoE外围算子主要使用场景
W4A164-bit weight,BF16/FP16 activationBF16/FP16,部分归约内部使用 FP32权重容量或 decode 带宽受限
W8A8 / FP8INT8/FP8 weight 与 activationBF16/FP16,部分归约内部使用 FP32有原生低精度 GEMM 的服务器硬件

算法只负责把主体模块准备成对应格式。例如 AWQ/GPTQ 常用于生成 W4A16,SmoothQuant 或动态量化可用于准备 W8A8;它们不是这张模块级精度图本身。完整组合见量化配置。

三、少量高精度 fallback ​

主流框架普遍支持 ignore、ignored_layers 或 modules_to_not_convert,用于让少数模块回退到 BF16/FP16。它解决的是具体模型或 kernel 的兼容性问题,不代表存在一份所有模型通用的“敏感层名单”。

业界实现中常见的 fallback 包括:

  • LM Head:vLLM 的在线 FP8 路径和 LLM Compressor 示例默认跳过最终 lm_head,但支持的后端也可以选择量化它。
  • 多模态 Encoder/Projector:参数占比小且直接影响语言模型输入质量时,常保留 BF16/FP16 或 Q8。
  • 不受支持的 Projection/Gate:融合布局或 MoE kernel 无法消费其格式时,保持原始精度。
  • 校准发现的敏感模块:通过逐模块消融确认后加入 skip list,而不是预设首层、尾层一定敏感。

vLLM 的在线量化配置把模块例外直接暴露为精度路由:

yaml
quantization_config:
  linear: fp8_per_block
  moe: fp8_per_tensor
  ignore:
    - lm_head
    - "re:.*[qkv]_proj"

融合算子会限制 fallback 的粒度。例如 QKV 已打包为一个 fused tensor 时,不能假设 q_proj、k_proj、v_proj 可以任意使用三种位宽;配置必须符合框架的 shard 匹配和 kernel 布局。

四、按模型组件划分精度 ​

在 MoE 和低至 FP4 的部署中,按组件划分比任意逐层 mixed-bit 更常见。原因是组件边界通常对应独立 kernel,容易保留规则的数据布局。

1. Dense Linear 与 MoE 分开配置 ​

vLLM 在线量化为 linear 和 moe 提供独立配置。部署者可以让 Dense Linear 使用 per-block FP8,而 Fused MoE 使用 per-tensor FP8,或者反向组合;未配置的一侧继承默认方案。

2. 只量化 MLP 或 Routed Expert ​

NVIDIA ModelOpt 提供以下实际导出配方:

  • nvfp4_mlp_only:只量化 MLP 和 MoE,Attention 保持较高精度。
  • nvfp4_experts_only:只量化 MoE Routed Expert。
  • nvfp4_omlp_only:在 MLP-only 基础上增加 Attention o_proj。

这类配方利用了 MLP/Expert 参数占比高、组件边界清楚的特点。它不意味着 Router、Shared Expert 或 Attention 必须使用某个固定 dtype;具体精度仍由 checkpoint 配方定义。

3. 本地推理的跨 tensor 混合 ​

llama.cpp 的 GGUF 生态广泛使用跨 tensor 混合预设。以 Q4_K_M 为例,主体使用 Q4_K,部分 tensor 按内置规则提高位宽;--pure 用于关闭这种 mixture。量化器还支持单独设置 output.weight、token embedding 或正则匹配的 tensor 类型。

这种 tensor 级混合适合 llama.cpp 已实现相应块格式和算子的场景,不应直接外推到所有 GPU serving 框架。GGUF 的具体规则见llama.cpp:K-Quant 与 I-Quant。

五、算子内部使用更宽的累加精度 ​

低精度输入不等于全程低精度。INT8 GEMM 通常使用 INT32 partial sum,再应用 scale 并输出 BF16/FP16;FP8/FP4 kernel 也会按硬件指令选择更宽的 accumulator 和输出 dtype。

Normalization 和 Softmax 的归约也可能在 FP32 内部完成,再转回输入 dtype。例如本站 Qwen2 实现中的 RMSNorm 方差统计与 eager Softmax 都显式使用 FP32。

这部分精度通常由 kernel 或算子实现决定,而不是 checkpoint 中的 WnAm 名称决定。评估一条低精度路径时需要同时确认 input、accumulator 和 output dtype。

六、KV Cache 独立于模型精度 ​

TensorRT-LLM、vLLM 和 SGLang 都把 KV Cache dtype 作为独立配置。以下组合都可以成立:

text
W4A16 model + BF16/FP16 KV Cache
W4A16 model + FP8 KV Cache
FP8 W8A8 model + FP8 KV Cache
BF16 model + FP8 KV Cache

KV Cache 随 batch 和上下文长度增长,优化目标与静态 weight 不同。短上下文下可以保持 BF16/FP16;长上下文或高并发下再评估 FP8,部分新后端还支持 FP4。还要确认 Attention kernel 是否融合了反量化,否则 Cache 变小不一定带来吞吐提升。

存储精度也不必等于 Attention 计算精度:有的 backend 读取低精度 Cache 后转为 BF16/FP16,有的 backend 可以直接在 FP8 域完成部分计算。

八、业界实现对照 ​

实现主要精度控制入口已落地的混合方式
vLLMquantization、quantization_config.linear/moe/ignore、kv_cache_dtypeLinear/MoE 分区、模块 fallback、独立 KV Cache
SGLangQuantizationConfig method dispatch、ignored_layers、--kv-cache-dtypeLinear/FusedMoE 替换、未量化 fallback、独立 KV Cache
TensorRT-LLMW4A16/W4A8/FP8/FP4 recipe、KvCacheConfig固定硬件 recipe、模型与 KV Cache 分离
ModelOptnvfp4_mlp_only、nvfp4_experts_only 等导出配方MLP/Expert/Attention 组件级划分
llama.cppK-Quant/I-Quant preset、--tensor-type、--pureGGUF 跨 tensor 混合 bit

这里最普遍的是“主体 Linear/MoE 低精度 + 外围算子保持模型 dtype + 少量 fallback + KV Cache 独立配置”。组件级 FP4 和 GGUF tensor mixture 是针对特定硬件或运行时的扩展;任意 per-layer mixed-bit 并不是所有后端都能直接执行的通用能力。

参考 ​

  1. vLLM: Online Quantization
  2. vLLM: Quantization Support Matrix
  3. vLLM: Quantized KV Cache
  4. SGLang: Quantization
  5. SGLang: Quantized KV Cache
  6. SGLang: W8A8 FP8 Method Dispatch
  7. NVIDIA TensorRT-LLM: Quantization
  8. NVIDIA Model Optimizer: LLM PTQ
  9. NVIDIA Model Optimizer: auto_quantize
  10. llama.cpp: llama-quantize
  11. LLM.int8(): 8-bit Matrix Multiplication for Transformers at Scale