模型转换与量化:FP16/INT8/INT4量化原理、PTQ与QAT流程、精度评估
4.1 为什么量化是TensorRT-LLM落地的关键环节
大语言模型在推理阶段的主要瓶颈是显存带宽与计算吞吐。以LLaMA-70B为例,FP16权重占用约140GB显存,单张H100 80GB无法承载;即便使用多卡,访存开销也远高于计算开销。量化通过降低权重和激活值的位宽,同时压缩模型体积并提升计算密度,是TensorRT-LLM实现高吞吐、低延迟服务的必经之路。
TensorRT-LLM的量化并非简单调用torch.quantize,而是需要理解其底层引擎对张量布局、Kernel选择、反量化时机的约束。量化方案选错或校准不当,轻则精度损失超标,重则推理结果完全不可用。因此,掌握FP16/INT8/INT4的量化原理、PTQ与QAT的完整流程,以及精度评估方法,是模型上线前的必修课。
4.2 量化原理:从FP16到INT4的映射与误差来源
量化的数学本质是将浮点张量映射到低比特整数空间。以对称量化为例,核心公式为:
scale = max(|x|) / (2^(bits-1) - 1)
x_int = round(x / scale)
x_dequant = x_int * scale
TensorRT-LLM中,权重通常采用逐通道(Per-Channel)量化,激活值采用逐张量(Per-Tensor)或逐Token量化。Per-Channel能显著降低权重离群值带来的精度损失,但会增加反量化计算量。
FP16到INT8的转换相对温和,动态范围仅从约5位指数缩减到固定整数范围。而INT4量化只有16个离散级别,对离群值极其敏感。下图展示了不同位宽下权重分布与量化误差的关系:
从图中可以看出,FP16的连续分布被INT8的256个离散级别替代后,主体信息保留良好;而INT4仅有16个级别,离群值(红色感叹号处)会导致严重的信息丢失。这也是为什么INT4量化必须配合离群值感知的权重均衡算法(如AWQ的激活感知缩放、GPTQ的近似二阶优化)才能保证可用性。
4.3 PTQ与QAT:两种量化流程的完整对比
TensorRT-LLM支持两种主流量化路径:训练后量化(PTQ)和量化感知训练(QAT)。两者的核心区别在于:PTQ在模型训练完成后进行,需要少量校准数据;QAT在训练或微调阶段引入伪量化节点,让模型自适应低比特表示。
| 对比维度 | PTQ (训练后量化) | QAT (量化感知训练) |
|---|---|---|
| 所需数据 | 数百条无标签校准样本 | 需要带标签训练数据 |
| 计算开销 | 低(分钟级) | 高(需完整训练/微调) |
| 精度保留 | INT8良好,INT4需算法补偿 | INT4精度显著优于PTQ |
| 适用场景 | 快速上线、无训练资源 | 精度敏感、可微调模型 |
| TensorRT-LLM支持 | 支持AWQ/GPTQ/SmoothQuant | 支持QAT导出INT8/INT4 |
4.3.1 PTQ流程:校准与算法选择
在TensorRT-LLM中执行PTQ的标准流程如下:
- 准备校准数据:从训练集或真实业务采样中选取128~512条样本,覆盖不同长度和主题。
- 选择量化算法:权重使用
RTN(舍入到最近)、AWQ或GPTQ;激活使用Max/Min或Percentile校准。 - 执行校准:运行TensorRT-LLM的量化脚本,生成量化权重和缩放因子。
- 构建引擎:将量化模型转换为TensorRT引擎,指定
--quantize int4_awq等参数。
# 使用TensorRT-LLM的量化脚本(示例)
python convert_checkpoint.py \
--model_dir ./llama-2-7b-hf \
--output_dir ./llama-2-7b-int4-awq \
--dtype float16 \
--quant_method awq \
--quantize_weight 4 \
--calib_dataset ./calib_data.jsonl \
--calib_size 128
# 构建引擎
trtllm-build \
--checkpoint_dir ./llama-2-7b-int4-awq \
--gemm_plugin float16 \
--max_batch_size 8 \
--max_input_len 2048 \
--max_seq_len 4096 \
--output_dir ./engine
4.3.2 QAT流程:伪量化与端到端微调
QAT的核心是在模型前向传播中插入伪量化节点(FakeQuant),模拟量化误差,让权重在训练中逐步适应低比特表示。TensorRT-LLM的QAT流程通常借助torchao或NVIDIA TensorRT Model Optimizer实现:
# 使用TensorRT Model Optimizer进行QAT(伪代码)
from modelopt.torch.quantization import quantize, QAT
# 定义量化配置
qat_config = QAT(
quant_algo="INT4_AWQ",
calib_data=calib_loader,
num_calib_steps=128
)
# 应用QAT
qat_model = quantize(model, qat_config)
# 微调训练(通常1~3个epoch,学习率降低10倍)
train(qat_model, train_loader, epochs=2, lr=1e-5)
# 导出为TensorRT-LLM格式
export_quantized_model(qat_model, output_dir="./qat_model")
QAT的关键超参数包括:伪量化起始步数(建议前10%训练步数不做量化,让模型先收敛)、学习率调度(比正常微调低10~50倍)、批大小(保持与原始训练一致)。QAT后的模型通常能恢复PTQ损失的50%~80%精度,尤其在4比特场景下效果显著。
4.4 精度评估:量化前后必须验证的指标
量化是否成功,不能只看Loss或Perplexity,需要从多个维度评估。TensorRT-LLM部署场景中,推荐以下评估矩阵:
- 困惑度(PPL):在标准语料(如Wikitext)上对比量化前后PPL变化,通常INT8应小于0.5,INT4应小于2.0。
- 下游任务准确率:MMLU、GSM8K、HumanEval等,按业务场景选择2~3个任务。
- 输出质量抽样:人工或LLM-as-Judge对比量化前后的回答质量。
- 数值误差分析:对比量化模型与FP16模型的隐藏层输出余弦相似度。
# 使用lm-evaluation-harness评估量化模型
lm_eval --model vllm \
--model_args pretrained=./llama-2-7b-int4-awq,quantization=awq \
--tasks mmlu,gsm8k \
--batch_size auto \
--output_path ./eval_results.json
4.5 案例复盘:LLaMA-2-7B的INT4量化实战
某企业需要将LLaMA-2-7B部署到2张A10(24GB)显卡上,目标吞吐提升3倍。我们对比了三种方案:
| 方案 | 显存占用 | MMLU准确率 | 吞吐 (tokens/s) | 结论 |
|---|---|---|---|---|
| FP16基线 | 13.5GB | 45.3% | 820 | 作为对照 |
| INT8 PTQ | 7.2GB | 44.8% (-0.5) | 1450 | 精度损失可接受 |
| INT4 AWQ | 4.1GB | 43.9% (-1.4) | 2310 | 精度略降,吞吐翻倍 |
最终选择INT4 AWQ方案,但针对MMLU中下降明显的“法律”和“医学”子任务,额外收集了500条领域数据做QAT微调,将准确率恢复到44.7%。这一案例说明:PTQ快速上线,QAT精调兜底是量化落地的标准组合拳。
4.6 量化选型决策清单
在实际项目中,可按下述清单快速决策:
- 显存是否紧张?不紧张则保持FP16,省去所有量化风险。
- INT8 PTQ后PPL增加是否小于1.0?是则直接采用INT8。
- 需要INT4时,优先尝试AWQ/GPTQ,若精度不达标再考虑QAT。
- KV Cache是否量化?长序列场景下KV Cache INT8可节省30%显存。
- 是否开启
--use_fp8?H100等硬件支持FP8时,精度优于INT8且速度更快。
量化不是“越低越好”,而是“够用就好”。建议在项目初期就建立量化评估流水线,将PPL、任务准确率、吞吐、延迟纳入CI/CD,每次模型更新自动跑一遍量化验证,确保上线质量。