技术博客

FP8/FP4 量化生产推理实战:TensorRT ModelOpt 完全指南

深入讲解 NVIDIA TensorRT ModelOpt 的 FP8 与 FP4 量化原理、校准数据准备、生产导出流程,以及在 H100/H200/B200 上的性能提升数据,覆盖 Qwen3、Llama4 等主流模型的量化实践。

FP8FP4量化TensorRTModelOptLLM推理优化

量化是 2026 年 LLM 推理成本最主要的优化手段。NVIDIA TensorRT ModelOpt(ModelOpt)是 NVIDIA 官方的统一量化与压缩库,支持 FP8、INT4、MXFP4、INT8 等格式,并直接导出到 TensorRT-LLM、vLLM 和 SGLang 推理引擎。在 H100 上使用 FP8 量化,与 BF16 相比吞吐量可提升 1.5-1.8 倍,质量几乎无损失。

量化格式选型矩阵(2026)

格式 硬件支持 质量损失 吞吐提升 适用场景
FP8(E4M3) H100/H200/B200 极低 1.5-1.8× 生产推理首选
MXFP4(块浮点) B200/GB200 2.5-3× Blackwell 专属高效率
INT8(W8A8) A100 及以上 1.3-1.5× A100 上的最佳选择
AWQ INT4 所有 GPU 2-2.5× 显存受限场景
GPTQ INT4 所有 GPU 2-2.5× 消费级 GPU 离线推理

核心原则:有 Hopper/Blackwell 硬件优先选 FP8,不要用 INT4 在数据中心 GPU 上——INT4 在 H100 上没有专用硬件加速,实际吞吐不如 FP8

安装 ModelOpt

# 安装 ModelOpt(需 CUDA 12.1+)
pip install nvidia-modelopt[all]

# 验证安装
python3 -c "import modelopt; print(modelopt.__version__)"

# 安装 TensorRT-LLM(ModelOpt 导出目标)
pip install tensorrt-llm

FP8 PTQ(训练后量化)流程

1. 准备校准数据

from datasets import load_dataset
import json

# 使用 ShareGPT 格式的对话数据做校准(512-1024 条)
dataset = load_dataset("shareGPT", split="train", streaming=True)
calibration_data = []
for i, item in enumerate(dataset):
    if i >= 512:
        break
    if "conversations" in item:
        for turn in item["conversations"]:
            if turn["from"] == "human":
                calibration_data.append(turn["value"])

# 保存校准数据
with open("calibration_data.json", "w") as f:
    json.dump(calibration_data, f, ensure_ascii=False)

关键:校准数据应和生产数据分布尽量接近。面向代码问答的模型用代码数据校准,面向中文的模型用中文数据校准。

2. 执行 FP8 量化

import torch
import modelopt.torch.quantization as mtq
from transformers import AutoModelForCausalLM, AutoTokenizer

model_path = "/models/qwen3-32b-instruct"
tokenizer = AutoTokenizer.from_pretrained(model_path)

# 加载 BF16 模型
model = AutoModelForCausalLM.from_pretrained(
    model_path,
    torch_dtype=torch.bfloat16,
    device_map="auto"
)

# 准备校准 DataLoader
with open("calibration_data.json") as f:
    calib_texts = json.load(f)

def get_calib_dataloader(texts, tokenizer, batch_size=4, max_length=2048):
    encodings = tokenizer(
        texts,
        return_tensors="pt",
        padding=True,
        truncation=True,
        max_length=max_length
    )
    dataset = torch.utils.data.TensorDataset(
        encodings["input_ids"],
        encodings["attention_mask"]
    )
    return torch.utils.data.DataLoader(dataset, batch_size=batch_size)

calib_dataloader = get_calib_dataloader(calib_texts[:512], tokenizer)

# FP8 量化配置
quant_config = mtq.FP8_DEFAULT_CFG
# 等价于:
# {
#   "quant_cfg": {
#     "*weight_quantizer": {"num_bits": (4, 3), "axis": None},
#     "*input_quantizer": {"num_bits": (4, 3), "axis": -1},
#     "lm_head": {"enable": False},  # 输出层不量化
#   },
#   "algorithm": "max"
# }

# 执行量化(PTQ)
def forward_loop(model):
    for batch in calib_dataloader:
        input_ids = batch[0].cuda()
        attention_mask = batch[1].cuda()
        with torch.no_grad():
            model(input_ids=input_ids, attention_mask=attention_mask)

mtq.quantize(model, quant_config, forward_loop)

print("FP8 量化完成")

3. 导出到 TensorRT-LLM

import modelopt.torch.export as mte

# 导出量化权重(兼容 TensorRT-LLM 格式)
mte.export_tensorrt_llm_checkpoint(
    model,
    decoder_type="qwen",     # 模型架构类型
    dtype=torch.float16,
    export_dir="/models/qwen3-32b-fp8-trtllm",
    inference_tensor_parallel=4,    # 目标 TP 大小
    inference_pipeline_parallel=1
)

4. 编译 TensorRT-LLM Engine

# 编译 FP8 推理引擎(需要目标 GPU 上执行)
trtllm-build \
  --checkpoint_dir /models/qwen3-32b-fp8-trtllm \
  --output_dir /engines/qwen3-32b-fp8 \
  --gemm_plugin fp8 \
  --use_fp8_context_fmha enable \
  --max_batch_size 32 \
  --max_input_len 8192 \
  --max_seq_len 16384 \
  --workers 4

# 编译完成后测试性能
python3 /opt/tensorrt_llm/benchmarks/python/benchmark.py \
  -m qwen3_32b \
  --engine_dir /engines/qwen3-32b-fp8 \
  --batch_size 1 4 8 16 32 \
  --input_output_len "2048,512"

导出到 vLLM(更简便方案)

# 直接导出 vLLM 兼容格式(无需编译步骤)
mte.export_hf_checkpoint(
    model,
    export_dir="/models/qwen3-32b-fp8-vllm"
)
# vLLM 加载 FP8 量化模型
vllm serve /models/qwen3-32b-fp8-vllm \
  --quantization fp8 \
  --tensor-parallel-size 4 \
  --dtype float16 \
  --max-model-len 16384

MXFP4 量化(Blackwell B200 专属)

B200/GB200 原生支持 MXFP4(Microscaling FP4),相比 FP8 进一步提升 1.5-2× 吞吐:

# MXFP4 量化配置
quant_config = mtq.MXFP4_DEFAULT_CFG

# 量化流程与 FP8 相同
mtq.quantize(model, quant_config, forward_loop)

# 导出(指定 Blackwell 架构)
mte.export_tensorrt_llm_checkpoint(
    model,
    decoder_type="qwen",
    dtype=torch.bfloat16,
    export_dir="/models/qwen3-32b-mxfp4-trtllm",
    inference_tensor_parallel=4
)

KV Cache 量化

除了权重量化,KV Cache 量化可进一步减少显存占用,支持更大 batch 或更长 context:

# FP8 KV Cache 量化(TensorRT ModelOpt 10.9+)
quant_config = {
    "quant_cfg": {
        "*weight_quantizer": {"num_bits": (4, 3), "axis": None},
        "*input_quantizer": {"num_bits": (4, 3), "axis": -1},
        # KV Cache 量化(无需自定义插件,TRT 10.9 原生支持)
        "*k_quantizer": {"num_bits": (4, 3), "axis": -1},
        "*v_quantizer": {"num_bits": (4, 3), "axis": -1},
    },
    "algorithm": "max"
}

KV Cache FP8 量化效果:

量化质量评估

from lm_eval import evaluator

# 在标准 benchmark 上对比 BF16 与 FP8 质量
results_bf16 = evaluator.simple_evaluate(
    model="hf",
    model_args=f"pretrained={model_path},dtype=bfloat16",
    tasks=["mmlu", "gsm8k", "humaneval"],
    num_fewshot=5
)

results_fp8 = evaluator.simple_evaluate(
    model="hf",
    model_args=f"pretrained=/models/qwen3-32b-fp8-vllm,dtype=float16",
    tasks=["mmlu", "gsm8k", "humaneval"],
    num_fewshot=5
)

# 对比输出
for task in ["mmlu", "gsm8k", "humaneval"]:
    bf16_score = results_bf16["results"][task]["acc,none"]
    fp8_score = results_fp8["results"][task]["acc,none"]
    diff = (fp8_score - bf16_score) / bf16_score * 100
    print(f"{task}: BF16={bf16_score:.3f}, FP8={fp8_score:.3f}, 差异={diff:+.2f}%")

Qwen3-32B 量化质量对比(实测参考值):

Benchmark BF16 FP8 FP4
MMLU 79.2% 79.0% 78.5%
GSM8K 85.6% 85.4% 84.9%
HumanEval 72.1% 71.8% 71.3%
吞吐(tok/s, bs=32) 2100 3450 5200

生产部署检查清单

# 1. 验证量化模型可正常推理
curl http://localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model": "qwen3-32b", "messages": [{"role":"user","content":"1+1=?"}]}'

# 2. 压测对比(FP8 vs BF16)
python3 benchmark.py \
  --model-url http://localhost:8000 \
  --model-name qwen3-32b \
  --num-prompts 200 \
  --concurrency 16 \
  --output-tokens 256

# 3. 检查 GPU 显存使用(FP8 应比 BF16 少约 40%)
nvidia-smi --query-gpu=memory.used,memory.free --format=csv

# 4. 记录并对比 P50/P99 延迟
# FP8 的 TTFT 与 BF16 基本一致,但 TBT 更低(生成速度更快)

小结

FP8 是 2026 年数据中心 GPU LLM 推理的实际最优选择:H100/H200 原生硬件支持、质量损失 < 0.5%、吞吐提升 1.5-1.8×,没有理由继续在 Hopper/Blackwell 上用 BF16 跑推理。操作路径:ModelOpt PTQ 量化(512-1024 条域内校准数据)→ 导出到 vLLM(快速上线)或 TensorRT-LLM(极致性能)→ Benchmark 验证质量 → 生产切换。