ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

vLLM INT8 W4A8 量化实战指南:用 LLM Compressor 实现 INT4 权重 + INT8 激活的模型压缩与高效推理

vLLM INT8 W4A8 量化实战指南:用 LLM Compressor 实现 INT4 权重 + INT8 激活的模型压缩与高效推理 vLLM INT8 W4A8 量化实战指南用 LLM Compressor 实现 INT4 权重 INT8 激活的模型压缩与高效推理【免费下载链接】vllmA high-throughput and memory-efficient inference and serving engine for LLMs项目地址: https://gitcode.com/GitHub_Trending/vl/vllmvLLM 支持将模型权重量化为 INT4、激活值量化为 INT8即 INT8 W4A8 格式在显著降低模型体积的同时保持较好的推理精度。本文基于仓库文档 INT8 W4A8 展开完整覆盖从环境准备、校准数据准备、GPTQ 量化配方到 vLLM 加载与精度评测的全流程并结合 vLLM 源码中的量化 scheme 匹配与内核选择逻辑帮助你理解 W4A8 模型在 vLLM 中是如何被识别和执行的。读完本文你将能够独立完成一个 W4A8 模型的量化与导出、选择 Groupwise 或 Channelwise 两种精度-性能权衡方案、在 vLLM 中加载并评测量化模型以及看懂 vLLM 侧的 W4A8 量化方案判定代码。1. 前提条件与依赖环境使用 W4A8 量化需要安装 llm-compressor 库vllm-project 维护的模型优化工具(venv-llm-compressor) pip install llmcompressor同时在另一个vLLM 环境中安装vllm和评测工具lm-evaluation-harness(venv-vllm) pip install vllm lm-eval[api]0.4.12原文档特别强调vLLM 与 llm-compressor 应使用彼此独立的环境两者直接混装可能存在兼容问题。这一建议的合理性在于量化侧依赖llmcompressor/compressed_tensors等推理优化栈而 vLLM 运行时也内嵌了compressed_tensors的解析逻辑见 compressed_tensors.py两套库版本不一致时容易产生行为分歧。W4A8 在整个 LLM Compressor 量化系列中的位置可以参考量化功能总览 README该系列还包括 FP8 W8A8fp8.md、INT4 W4A16int4.md和 INT8 W8A8int8_w8a8.md。W4A8 的独特之处在于同时把权重压到 4-bit、激活值压到 8-bit兼顾模型体积与推理算力。2. 量化流程概览整个流程包含四个主要步骤加载模型Loading the model准备校准数据Preparing calibration data应用量化Applying quantization在 vLLM 中评测精度Evaluating accuracy2.1 加载模型使用transformers的标准 AutoModel 类加载模型与分词器from transformers import AutoTokenizer, AutoModelForCausalLM MODEL_ID meta-llama/Meta-Llama-3-8B-Instruct model AutoModelForCausalLM.from_pretrained( MODEL_ID, dtypeauto, ) tokenizer AutoTokenizer.from_pretrained(MODEL_ID)2.2 准备校准数据将激活值量化为 INT8、权重量化为 INT4 时需要用样例数据来估计激活值的缩放因子scale。校准数据应尽量贴近实际部署时的输入分布对于通用指令微调模型可以使用ultrachat类数据集from datasets import load_dataset NUM_CALIBRATION_SAMPLES 512 MAX_SEQUENCE_LENGTH 2048 # Load and preprocess the dataset ds load_dataset(HuggingFaceH4/ultrachat_200k, splittrain_sft) ds ds.shuffle(seed42).select(range(NUM_CALIBRATION_SAMPLES)) def preprocess(example): return {text: tokenizer.apply_chat_template(example[messages], tokenizeFalse)} ds ds.map(preprocess) def tokenize(sample): return tokenizer(sample[text], paddingFalse, max_lengthMAX_SEQUENCE_LENGTH, truncationTrue, add_special_tokensFalse) ds ds.map(tokenize, remove_columnsds.column_names)注意这里先通过apply_chat_template把对话还原成模型训练时使用的模板文本再统一截断到MAX_SEQUENCE_LENGTH保证校准输入与线上请求格式一致——这正是校准数据贴合部署数据的落地方式。2.3 应用量化Groupwise 与 Channelwise 两种配方以下配方都会生成 W4A8 模型INT4 权重、INT8 激活值。在 Arm CPU 上该格式可通过 KleidiAI 库加速。原文档给出的选择原则是Groupwise组量化精度更好Channelwise通道量化推理性能更好。两种配方都用GPTQModifier完成基于 GPTQ 的量化dampening_frac0.01控制 Hessian 正则强度ignore[lm_head]表示输出投影层不做量化。Groupwise 配方GPTQModifier直接以schemeW4A8高层入口配置from llmcompressor import oneshot from llmcompressor.modifiers.quantization import GPTQModifier # Configure the quantization algorithms recipe [ GPTQModifier( targetsLinear, schemeW4A8, ignore[lm_head], dampening_frac0.01 ), ] # Apply quantization oneshot( modelmodel, datasetds, reciperecipe, max_seq_lengthMAX_SEQUENCE_LENGTH, num_calibration_samplesNUM_CALIBRATION_SAMPLES, ) # Save the compressed model: Meta-Llama-3-8B-Instruct-W4A8-G128-Dynamic-Per-Token SAVE_DIR MODEL_ID.split(/)[1] -W4A8-G128-Dynamic-Per-Token model.save_pretrained(SAVE_DIR, save_compressedTrue) tokenizer.save_pretrained(SAVE_DIR)Channelwise 配方用config_groups手工指定 weights/activations 的量化参数from llmcompressor import oneshot from llmcompressor.modifiers.quantization import GPTQModifier from compressed_tensors.quantization import QuantizationStrategy, QuantizationType scheme { targets: [Linear], weights: { num_bits: 4, type: QuantizationType.INT, strategy: QuantizationStrategy.CHANNEL, symmetric: True, dynamic: False, group_size: None, }, input_activations: { num_bits: 8, type: QuantizationType.INT, strategy: QuantizationStrategy.TOKEN, dynamic: True, symmetric: False, observer: None, }, output_activations: None, } recipe [ GPTQModifier( targetsLinear, config_groups{group_0: scheme}, ignore[lm_head], dampening_frac0.01, ), ] oneshot( modelmodel, datasetds, reciperecipe, max_seq_lengthMAX_SEQUENCE_LENGTH, num_calibration_samplesNUM_CALIBRATION_SAMPLES, ) # Save the compressed model: Meta-Llama-3-8B-Instruct-W4A8-Channelwise-Dynamic-Per-Token SAVE_DIR MODEL_ID.split(/)[1] -W4A8-Channelwise-Dynamic-Per-Token model.save_pretrained(SAVE_DIR, save_compressedTrue) tokenizer.save_pretrained(SAVE_DIR)对比两份配方的量化语义可以提炼出 vLLM 支持 W4A8 的硬性条件参数Groupwise 配方Channelwise 配方含义权重位宽4 bit4 bitINT4 权重权重策略GROUP默认 G128从输出目录名-G128-可见CHANNELgroup_sizeNone分组量化 vs 逐通道量化权重对称性对称对称symmetric: TruevLLM 侧仅支持对称权重量化权重动态性静态静态dynamic: Falsescale 量化时确定推理时不再变化激活位宽/策略8 bit / per-token8 bit / per-token动态 per-token 量化激活动态性动态动态dynamic: True每个 token 在推理时在线计算 scale激活对称性—非对称symmetric: FalsevLLM 侧对称/非对称激活均支持2.4 在 vLLM 中加载与精度评测量化完成后直接用 vLLM 的LLM类加载Groupwise 模型from vllm import LLM llm LLM(./Meta-Llama-3-8B-Instruct-W4A8-G128-Dynamic-Per-Token)Channelwise 模型from vllm import LLM llm LLM(./Meta-Llama-3-8B-Instruct-W4A8-Channelwise-Dynamic-Per-Token)再用lm_eval评测精度以 GSM8K、5-shot、抽样 250 条为例# Groupwise lm_eval --model vllm \ --model_args pretrained./Meta-Llama-3-8B-Instruct-W4A8-G128-Dynamic-Per-Token,add_bos_tokentrue \ --tasks gsm8k \ --num_fewshot 5 \ --limit 250 \ --batch_size auto# Channelwise lm_eval --model vllm \ --model_args pretrained./Meta-Llama-3-8B-Instruct-W4A8-Channelwise-Dynamic-Per-Token,add_bos_tokentrue \ --tasks gsm8k \ --num_fewshot 5 \ --limit 250 \ --batch_size auto!!! 注意 量化模型对bostoken 的存在与否可能比较敏感。运行评测时务必带上add_bos_tokenTrue如上述--model_args中的add_bos_tokentrue否则评测结果可能与训练分布不一致。3. 源码纵深vLLM 如何识别并执行 W4A8 量化模型3.1 量化方案的自动判定llm-compressor 保存的模型通过compressed_tensors格式在config.json中携带量化配置quantization config。vLLM 加载时会在 compressed_tensors.py 中按层匹配方案。其中 W4A8 的判定函数_is_dynamic_token_w4a8_int约 L501-L523精确编码了第 2.3 节表格里的条件staticmethod def _is_dynamic_token_w4a8_int( weight_quant: QuantizationArgs, input_quant: QuantizationArgs ) - bool: is_weight_4_bits weight_quant.num_bits 4 is_activation_8_bits input_quant.num_bits 8 weight_strategy ( weight_quant.strategy QuantizationStrategy.GROUP.value or weight_quant.strategy QuantizationStrategy.CHANNEL.value ) is_token ( weight_strategy and input_quant.strategy QuantizationStrategy.TOKEN.value ) is_dynamic not weight_quant.dynamic and input_quant.dynamic # Both symmetric and asymmetric input quantization supported. # Only symmetric weight quantization supported. return ( is_weight_4_bits and is_activation_8_bits and is_token and weight_quant.symmetric and is_dynamic )也就是说vLLM 只接受权重 4-bit 且对称、策略为 GROUP 或 CHANNEL、权重 scale 静态激活 8-bit、per-token、动态。这解释了为什么原文档的两份配方都能被 vLLM 支持而任何偏离例如权重用非对称 scale都不会命中该方案。判定通过后create_scheme约 L870-L878会把该层交给CompressedTensorsW4A8Intif self._is_dynamic_token_w4a8_int(weight_quant, input_quant): is_static_input_scheme input_quant and not input_quant.dynamic return CompressedTensorsW4A8Int( num_bitsweight_quant.num_bits, strategyweight_quant.strategy, group_sizeweight_quant.group_size, is_static_input_schemeis_static_input_scheme, input_symmetricinput_quant.symmetric, )3.2 线性层权重布局与内核选择具体执行逻辑在 compressed_tensors_w4a8_int.py 的CompressedTensorsW4A8Int中几个实现细节值得关注权重以 int8 容器存储 4-bit 值create_weights中weight_packed的 dtype 是torch.int8L111-L119即每 8-bit 槽位装一个 INT4 值这也是压缩格式的通用约定Groupwise 与 Channelwise 的 scale 布局不同当group_size is None时视为 channelwiseself.group_size -1scale 形状为(out, 1)使用ChannelQuantScaleParametergroupwise 时 scale 形状为(out, in/group_size)使用GroupQuantScaleParameterL121-L136group_size 必须整除分区维度TP 并行下调用verify_group_size_divides_partition校验L81-L84若你自定义的 group size 不能整除张量并行切分后的输入维度加载会直接报错内核自动选择通过MPLinearLayerConfigchoose_mp_linear_kernelL91-L107按权重/激活类型、group_size 等条件挑选具体的混精线性内核如 Cutlass W4A8、CPU 动态 4-bit 等见 kernels/linear/mixed_precision/并在日志中打印所选后端。对应的 CUTLASS 内核实现位于 cutlass_w4a8/ 目录含w4a8_utils.cu、w4a8_mm_entry.cu、w4a8_grouped_mm_entry.cu等单元测试见 test_cutlass_w4a8.py 与 test_cutlass_w4a8_moe.py。3.3 MoE 模型的 W4A8 路径如果你量化的是 MoE 模型vLLM 走的是另一条路径compressed_tensors_moe_w4a8_int8.py 中的CompressedTensorsW4A8Int8MoEMethod。其类注释明确说明了该方法的定位与数据布局 CPU-only MoE method using dynamic 4-bit matmul kernels on Arm Platform - Weights: int4 (stored as int8 values in [-8,7], packed to uint8 nibbles) - Scales: Fp32 for Channelwise , bf16 for groupwise quantization - Bias: Same data type as original weights - Activations: FP32/Bf16 dynamic per-token (A8 Int), quantized inside the kernel 可以推断MoE 的 W4A8 主要面向 Arm CPU 平台与原文档提到的 KleidiAI 加速相呼应激活在内核内部做动态 per-token INT8 量化scale 数据类型上channelwise 用 FP32、groupwise 用 BF16L78-L87。内核后端由 oracle/w4a8_int8.py 的select_w4a8_int8_moe_backend依据平台与量化键选择。4. 最佳实践原文档给出的量化调参建议配合上文条件可以进一步落地校准样本量从 512 开始若精度下降明显再增大NUM_CALIBRATION_SAMPLES序列长度从 2048 起步MAX_SEQUENCE_LENGTH与部署时的典型上下文长度对齐可让激活 scale 估计更准确使用模型训练时对应的 chat/instruction 模板如上例中apply_chat_template避免校准分布漂移微调模型建议混入训练数据如果模型经过 fine-tune用一部分训练数据作为校准集能显著改善量化后的精度保持。5. 排错与支持若加载 W4A8 模型时报 No compressed-tensors compatible scheme was found优先检查配置是否满足 3.1 节的判定条件权重 4-bit 对称、激活 8-bit per-token 动态、权重策略 GROUP/CHANNEL以及 group_size 是否整除张量并行分区维度评测结果异常波动时确认是否遗漏了add_bos_tokenTrue量化侧llm-compressor的问题或功能需求按原文档指引到 llm-compressor 仓库vllm-project/llm-compressor提 issuevLLM 推理侧的问题可参考 usage/troubleshooting.md。【免费下载链接】vllmA high-throughput and memory-efficient inference and serving engine for LLMs项目地址: https://gitcode.com/GitHub_Trending/vl/vllm创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表