编程 vLLM INT8 W8A8 量化:Blackwell 卡不支持,环境还得和推理分开

2026-09-27 00:03:47

vLLM INT8 W8A8 量化:Blackwell 卡不支持,环境还得和推理分开

vLLM 支持把权重和激活都量化为 INT8(W8A8),节省内存、加快推理,模型体积减小的同时性能基本保持。下面是完整的离线量化流程、评估方式和几个常踩的坑。

硬件与依赖边界

注意:INT8 计算只在计算能力大于 7.5 的 NVIDIA GPU 上得到支持,覆盖 Turing、Ampere、Ada Lovelace、Hopper。

Blackwell 限制:计算能力 >= 10.0 的 GPU(如 RTX 6000 Blackwell)不支持 INT8,需要改用 FP8 量化,或者换到 Hopper / Ada / Ampere 架构上运行。

依赖:

pip install llmcompressor==0.1.0

另外需要安装 vllm 和 lm-evaluation-harness 用于评估。

环境要分开:请为 vLLM 和 llm-compressor 使用独立的 Python 环境,两者混装在同一环境里可能无法协同工作(依赖版本冲突)。量化是一次性离线流程,推理是线上常驻流程,两者解耦之后各自升级互不影响。

量化过程分 4 个主要步骤:加载模型 → 准备校准数据 → 应用量化 → 评估 vLLM 的准确性。

1)加载模型

使用包装了 AutoModelForCausalLM 的 SparseAutoModelForCausalLM:

from llmcompressor.transformers import SparseAutoModelForCausalLM
from transformers import AutoTokenizer

MODEL_ID = "meta-llama/Meta-Llama-3-8B-Instruct"

model = SparseAutoModelForCausalLM.from_pretrained(
MODEL_ID, device_map="auto", torch_dtype="auto"
)
tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)

2)准备校准数据

把激活值量化为 INT8 时,需要样本数据来估计激活尺度,最好使用与部署数据高度匹配的校准数据。通用指令微调模型可以用 ultrachat 数据集:

from datasets import load_dataset

NUM_CALIBRATION_SAMPLES = 512
MAX_SEQUENCE_LENGTH = 2048

ds = load_dataset("HuggingFaceH4/ultrachat_200k", split="train_sft")
ds = ds.shuffle(seed=42).select(range(NUM_CALIBRATION_SAMPLES))

def preprocess(example):
return {
"text": tokenizer.apply_chat_template(example["messages"], tokenize=False)
}

ds = ds.map(preprocess)

def tokenize(sample):
return tokenizer(
sample["text"],
padding=False,
max_length=MAX_SEQUENCE_LENGTH,
truncation=True,
add_special_tokens=False,
)

ds = ds.map(tokenize, remove_columns=ds.column_names)

3)应用量化

from llmcompressor.transformers import oneshot
from llmcompressor.modifiers.quantization import GPTQModifier
from llmcompressor.modifiers.smoothquant import SmoothQuantModifier

recipe = [
SmoothQuantModifier(smoothing_strength=0.8),
GPTQModifier(targets="Linear", scheme="W8A8", ignore=["lm_head"]),
]

oneshot(
model=model,
dataset=ds,
recipe=recipe,
max_seq_length=MAX_SEQUENCE_LENGTH,
num_calibration_samples=NUM_CALIBRATION_SAMPLES,
)

SAVE_DIR = MODEL_ID.split("/")[1] + "-W8A8-Dynamic-Per-Token"
model.save_pretrained(SAVE_DIR, save_compressed=True)
tokenizer.save_pretrained(SAVE_DIR)

这个过程创建一个 W8A8 模型,权重和激活都量化为 8 位整数。

4)评估准确性

量化后可以直接在 vLLM 加载运行:

from vllm import LLM

model = LLM("./Meta-Llama-3-8B-Instruct-W8A8-Dynamic-Per-Token")

使用 lm_eval 评估:

lm_eval --model vllm \
--model_args pretrained="./Meta-Llama-3-8B-Instruct-W8A8-Dynamic-Per-Token",add_bos_token=true \
--tasks gsm8k --num_fewshot 5 --limit 250 --batch_size 'auto'

注意:量化模型可能对 bos token 的存在很敏感,评估时务必包含 add_bos_token=True,否则分数可能异常波动。

最佳实践

  • 以 512 个样本作为校准数据开始(如果准确性下降则增加样本数量)
  • 使用序列长度 2048 作为起点
  • 采用模型所训练的聊天模板或指令模板
  • 如果已经微调过模型,考虑使用一部分训练数据进行校准
  • 量化时固定忽略 lm_head 输出层

故障排除

  1. Blackwell 上无法使用 INT8:CC >= 10.0 的 GPU 不支持该方案,改用 FP8 量化或换用 Hopper / Ada / Ampere。
  2. 加载时报 No compressed-tensors compatible scheme:用报错中打印的 weight_quant / input_quant 字段检查位宽、策略与动态性是否落在受支持组合内。
  3. 量化环境与推理环境冲突:确认 llm-compressor 与 vLLM 分环境部署。
  4. 更复杂的量化问题:到 vllm-project/llm-compressor 仓库 issue 区提交。

vLLM 加载时如何分派量化方案

vLLM 加载时会读取 checkpoint 的 quantization_config(compressed-tensors 格式),按权重尺度策略(channel / tensor)× 激活动态/静态 × 激活是否对称自动分派到 CompressedTensorsW8A8Int8 方案,无需手动指定量化参数。compressed-tensors 格式的消费端在 vllm/model_executor/layers/quantization/compressed_tensors/compressed_tensors.py。

相关链接

  • llm-compressor 仓库:
  • Hugging Face 上可直接用于 vLLM 的 INT8 量化 checkpoint 集合
  • vLLM 量化文档

Tags: int8量化, vLLM, llm-compressor, GPTQ, SmoothQuant, W8A8

推荐文章

程序员茄子在线接单