文章

LLM 权重量化上线生产实战:用 Calibration Set、FP8/W4A16 双轨基准与 Quality Gate 防止质量回退

大模型权重量化不能只看显存下降。本文结合 vLLM、LLM Compressor 与 TensorRT-LLM,给出校准集选择、FP8/W4A16 双轨基准、硬件匹配、质量门禁与灰度回滚的完整生产上线方法。

LLM 权重量化上线生产实战:用 Calibration Set、FP8/W4A16 双轨基准与 Quality Gate 防止质量回退

大模型进入生产后,量化经常被当成一个简单的部署优化:把 BF16/FP16 换成 FP8、INT8 或 INT4,显存变小,理论吞吐变高,然后直接上线。

问题是,量化改变的是模型数值表示。即使模型能够正常加载、接口返回正常,也不代表业务质量保持不变。与此同时,不同量化格式能否真正带来加速,还取决于 GPU 架构、推理引擎、量化 Kernel、Batch 形态和模型结构。

因此,生产上的量化决策不应该写成:

“W4A16 比 FP16 小,所以用 W4A16。”

而应该写成:

“在指定硬件与请求分布上,候选量化产物通过质量门禁,同时在显存、吞吐或延迟至少一个关键目标上带来可验证收益,因此允许灰度发布。”

这篇文章只讨论模型权重,或权重与激活的量化。为了避免和 KV Cache Quantization 混在一起,后续实验默认保持 KV Cache 精度、调度策略和 Serving 参数不变。

一、核心原理:先把量化拆成三个独立问题

1. 量化格式决定“压什么”

常见生产方案大致可以分为两类:

  • Weight-only:例如 W4A16。权重压到 4 bit,激活仍保持较高精度。它通常优先解决模型显存占用,适合低 QPS、显存受限或较老 GPU 上的部署场景。
  • Weight + Activation:例如 FP8 W8A8。权重和激活都进入低精度计算路径,更依赖硬件原生支持和对应 Kernel,但在合适平台上更有机会获得计算吞吐收益。

vLLM 当前量化支持矩阵同时包含 AWQ、GPTQ、Marlin、LLM Compressor FP8/INT8、bitsandbytes、GGUF 等实现,并明确区分不同 GPU 架构的支持情况。TensorRT-LLM 也将 FP8、FP4、W4A16 AWQ/GPTQ 等作为不同量化 Recipe,而不是一个统一的 quantized=true 开关。

生产设计的第一原则因此是:量化格式、量化算法和运行时 Kernel 必须作为一个整体选择

2. Calibration Set 决定“模型看过什么分布后再被压缩”

AWQ、GPTQ、SmoothQuant 以及部分静态激活量化需要校准数据。LLM Compressor 的官方文档明确建议校准集与目标业务保持分布一致,并指出许多校准算法只需要相对小规模的数据即可开始迭代。

这里的重点不是“样本越多越好”,而是代表性

  • 如果线上主要是中文保险条款问答,而校准集全部来自英文百科;
  • 如果线上请求通常有 8K 上下文,而校准时只使用几百 token 的短输入;
  • 如果模型是代码助手,而校准集完全没有代码;

那么量化器看到的激活分布就可能与生产环境明显偏离。

一个更实用的校准集应覆盖:

维度说明
语言与领域主要语言、主要业务领域
模板真实的 Prompt / Chat Template
长度短、中、长输入长度分桶
任务高频任务和关键长尾任务
结构化输入代码、表格、JSON 等
高价值类型对质量敏感的关键请求

校准集不是 Eval Set。Calibration 用来确定量化参数,Eval 用来证明量化后没有不可接受的回退,两者应严格隔离。

3. Runtime 和硬件决定“压缩后是否真的更快”

相同的 W4A16 checkpoint,在不同 GPU、不同 Kernel 和不同 Batch 下,收益可能完全不同。不能把 checkpoint 文件变小等价为推理更快。生产评测必须回答:

  • 当前 GPU 是否原生支持对应低精度计算;
  • Serving 引擎是否真正调用了目标量化 Kernel;
  • 小 Batch 和大 Batch 下是否表现一致;
  • 显存节省是否能转化为更高并发或更少副本;
  • TTFT、TPOT 和吞吐谁是业务真正的瓶颈。

二、工程落地:建立 Dense、FP8、W4A16 三条基准线

不要在一套环境里边改参数边“感觉快了”。更稳妥的做法是固定实验矩阵。

Baseline A:Dense 基线

使用当前生产的 BF16/FP16 artifact,固定:

  • 模型版本;
  • tokenizer / chat template;
  • Serving 引擎版本;
  • Tensor Parallel / Pipeline Parallel;
  • 最大上下文;
  • KV Cache 精度;
  • Batch 与并发参数;
  • GPU 型号和数量。

Dense 基线的意义不是追求最好性能,而是提供唯一可比较的质量和性能参照物

Candidate B:FP8

FP8 可以作为现代 GPU 上的第一条候选路线。TensorRT-LLM 的 FP8 指南明确说明,从 FP16/BF16 checkpoint 构建 FP8 engine 时可以配置 Calibration,并强调量化后必须重新验证输出质量。

FP8 候选需要记录至少以下元数据:

artifact:
  base_model: model-name@revision
  quant_scheme: fp8-w8a8
  quantizer: modelopt
  calibration_dataset: calib-prod-v3
  calibration_dataset_hash: sha256:...
  runtime: tensorrt-llm@version
  gpu: hopper
  kv_cache_dtype: same-as-dense-baseline

Candidate C:W4A16

如果核心目标是降低模型权重显存,或者硬件对 FP8 的支持并不理想,可以建立 W4A16 候选。AWQ 与 GPTQ 都属于成熟的 4-bit weight-only 路线,但算法原理不同:

  • AWQ:使用激活统计识别更重要的权重通道,通过缩放降低这些权重在量化中的损失;
  • GPTQ:使用近似二阶信息逐层优化量化误差。

生产上没有必要先争论“谁绝对更好”,应针对模型、硬件和数据进行实测。

三、Quality Gate:不能只看 Perplexity

量化后的模型可能在总体语言建模指标上变化不大,却在某类业务请求上发生明显回退。因此上线门禁至少应分三层。

第一层:基础能力回归

根据模型用途选择确定性指标:

任务类型指标
分类Accuracy / F1
抽取Exact Match / F1
数学答案正确率
代码可执行测试通过率
选择题准确率
领域任务业务规则可判定的通过率

如果只能使用开放式生成样本,至少应该保留一组人工确认的 Golden Set,并对格式、关键事实和必答项做确定性检查,不要把“看起来差不多”当作门禁。

第二层:关键切片回归

整体平均分很容易掩盖局部问题。应该按生产流量建立 Slice:

  • 中文 / 英文;
  • 短上下文 / 长上下文;
  • 高频业务 / 低频高风险业务;
  • 普通文本 / 代码 / JSON;
  • 不同系统 Prompt 或不同产品线。

上线条件不是“总分不下降”,而是关键 Slice 都没有超过业务可接受阈值。阈值不要复制论文数字,应由产品风险与成本目标共同定义。

第三层:行为稳定性

同一批输入应在 Dense 与 Quantized 两条链路上对比:

  • 拒答率是否异常变化;
  • 结构化格式成功率是否下降;
  • 生成长度分布是否漂移;
  • EOS、重复输出和异常截断是否增加;
  • 关键术语与数字的准确率是否变化。

这层特别容易发现“Benchmark 分数没变,但线上体验变了”的问题。

四、Performance Gate:只在同条件下比较

性能实验必须保持输入集和 Serving 参数一致,至少记录:

  • GPU 显存占用;
  • 每秒输出 Token;
  • TTFT P50/P95/P99;
  • TPOT P50/P95/P99;
  • 最大稳定并发;
  • 不同输入长度桶的吞吐;
  • 不同并发级别下的尾延迟。

建议使用固定请求回放集,并把请求长度分布、输出长度分布、并发曲线全部版本化。

最常见的错误是 Dense 用默认参数,Quantized 为了跑分又打开另一组 Batch 或 Kernel 配置,最终无法判断收益究竟来自量化还是 Serving 参数变化。

五、将量化产物当作可追溯的软件制品

一个生产量化模型至少应该能够回答五个问题:

  1. 从哪个 Dense 模型版本生成?
  2. 用了哪种量化算法和 Recipe?
  3. 用了哪一版 Calibration Set?
  4. 由哪个 quantizer/runtime 版本生成并运行?
  5. 哪一版 Eval Report 证明它满足发布条件?

可以把 artifact ID 设计成:

<model>@<revision>__<quant-scheme>__<calib-version>__<runtime-version>

例如:

model-x@r42__w4a16-awq__calib-v3__vllm-0.xx

重点不在命名格式,而是不能只保留一个 quantized-model 目录。如果无法重建同一个量化 checkpoint,就无法可靠地做回归和回滚。

六、灰度上线:Quantized 是新模型,不是新配置

即使离线门禁全部通过,量化 artifact 仍应被视为一次模型版本发布。推荐流程是:

  1. Dense 继续作为稳定版本;
  2. Quantized 先进入 Shadow 或内部流量;
  3. 再进入小比例 Canary;
  4. 比较质量代理指标、错误率、TTFT/TPOT、吞吐和显存;
  5. 达标后逐步扩大;
  6. 保留 Dense artifact 和快速回切能力,直到完整观察窗口结束。

不要在发布后立即删除 Dense 版本。量化回退通常不是“服务挂了”,而是某个领域、语言或长度 Slice 的质量缓慢变差,这类问题需要观察时间才能暴露。

七、适用场景

更适合优先尝试 FP8:

  • GPU 对 FP8 有成熟硬件加速;
  • 目标是同时降低显存和提高计算吞吐;
  • Serving 引擎已经验证对应 FP8 Kernel;
  • 可以接受校准、基准和质量回归流程。

更适合优先尝试 W4A16:

  • 模型权重显存是主要约束;
  • 希望在保持激活高精度的前提下降低模型尺寸;
  • 部署硬件对 AWQ/GPTQ/Marlin 等路径支持更成熟;
  • 请求并发不高,但单实例模型装载成本很高。

不应急于量化:

  • 当前瓶颈主要在网络、排队或业务后处理;
  • 模型本身已经足够小,GPU 利用率长期很低;
  • 没有稳定的业务 Eval Set;
  • 无法保留 Dense 回滚版本;
  • 运行时对目标格式只有“能加载”而缺少成熟 Kernel 支持。

八、常见误区

误区一:直接下载一个别人量化好的 checkpoint 就上线。 预量化 checkpoint 很方便,但你仍然需要确认 base revision、量化 Recipe、硬件兼容性和自己的业务质量。能在 Hugging Face 下载,不等于适合你的流量。

误区二:校准集越大越好。 校准集的首要目标是代表真实激活分布。LLM Compressor 文档建议从相对小的样本集开始,再根据质量恢复情况增加数据。盲目扩大一个分布错误的数据集,只会更昂贵地校准错误目标。

误区三:只测一次标准 Benchmark。 量化误差可能集中在长上下文、代码、数字、低频语言或某个领域 Slice。必须同时有通用 Benchmark 与业务 Golden Set。

误区四:同时打开 KV Cache Quantization。 这会破坏归因。权重量化实验中先保持 KV Cache 配置不变。如果后续还要优化 KV Cache,应单独建立第二个实验矩阵。

误区五:只比较模型文件大小。 真正有价值的是单位 GPU 能承载的稳定业务吞吐,以及在质量约束下的成本。checkpoint 缩小但 Kernel 低效,并不一定带来生产收益。

九、上线检查清单

  • Dense baseline 的模型、runtime、GPU、Serving 参数已经冻结。
  • Calibration Set 与真实业务的语言、长度、领域和模板分布匹配。
  • Calibration Set 与 Eval Set 严格隔离。
  • FP8 / W4A16 候选分别生成可追溯 artifact。
  • 量化 Recipe、数据版本、runtime 版本和硬件信息全部记录。
  • KV Cache 精度、调度与 Batch 策略在对比实验中保持一致。
  • 通用能力、业务 Golden Set 和关键 Slice 都通过 Quality Gate。
  • 同一请求回放集完成显存、吞吐、TTFT、TPOT 与并发测试。
  • 已验证实际使用目标量化 Kernel,而不是隐式反量化或低效 fallback。
  • Canary 发布支持一键回退到 Dense artifact。
  • Dense 版本在完整观察窗口结束前不删除。

十、FAQ

FP8 和 W4A16 应该二选一吗? 不应该先凭格式做决定。比较时应固定模型版本、GPU、Serving 引擎、请求集和 KV Cache 配置,再分别建立 FP8 与 W4A16 候选。FP8 更强调现代 GPU 上的低精度计算路径;W4A16 更偏向权重压缩。最终选择应由业务质量与实际性能共同决定。

校准集可以直接用 WikiText、C4 或 UltraChat 吗? 可以用作通用模型的起点,LLM Compressor 官方文档也给出了这些公开数据集示例。但如果模型服务的是代码、中文金融、保险、法律等明确领域,应该优先加入或切换到与生产输入相近的数据,并覆盖真实 Chat Template 和长度分布。

为什么本文不同时讨论 KV Cache Quantization? 因为这是另一个独立变量。权重、激活和 KV Cache 的数值误差、显存收益与 Kernel 路径不同。一次实验同时修改多个低精度组件,会让质量和性能变化无法归因。生产工程中更稳妥的方式是逐项量化、逐项门禁。

参考资料

  1. vLLM — Quantization: https://docs.vllm.ai/en/latest/features/quantization/
  2. vLLM — INT4 W4A16: https://docs.vllm.ai/en/stable/features/quantization/int4/
  3. LLM Compressor — Choosing your dataset: https://docs.vllm.ai/projects/llm-compressor/en/latest/steps/choosing-dataset/
  4. LLM Compressor — Choosing the right compression algorithm: https://docs.vllm.ai/projects/llm-compressor/en/latest/steps/choosing-algo/
  5. TensorRT-LLM — Quantization: https://nvidia.github.io/TensorRT-LLM/1.3.0rc12/features/quantization.html
  6. TensorRT-LLM — FP8 Quantization: https://nvidia.github.io/TensorRT-LLM/performance/performance-tuning-guide/fp8-quantization.html
  7. AWQ: Activation-aware Weight Quantization for LLM Compression and Acceleration: https://arxiv.org/abs/2306.00978

常见问题

FP8 和 W4A16 应该二选一吗?
不建议先凭格式做决定。应在同一硬件、同一推理引擎、同一请求集上分别建立 FP8 与 W4A16 候选基准,再同时比较任务质量、显存、吞吐和尾延迟。
量化校准集可以直接使用通用公开数据集吗?
可以作为起点,但生产模型更应使用与真实业务输入分布接近的数据。领域、语言、长度和输入模板偏差都会影响校准结果,尤其是 AWQ、GPTQ 和静态激活量化。
量化上线时为什么要保持 KV Cache 配置不变?
为了隔离变量。若同时修改权重量化和 KV Cache 精度,质量、显存与延迟变化就很难归因。本流程只讨论权重或权重加激活量化,KV Cache 应在独立实验中验证。