拓冰建站拓冰建站
首页 / 资讯中心 / 正文

大模型量化实战:从INT8到GPTQ与AWQ的部署优化指南

大模型跑起来最肉疼的往往是推理阶段的显存和带宽。特别是模型要放进生产环境的时候一张80GB的A100看着很大一个70B模型光FP16权重要占140GB单卡根本塞不下。这也是量化这几年从“奇技淫巧”变成部署必修课的原因。我这篇内容从INT8一路写到GPTQ和AWQ把量化的原理、选型、实战和踩坑一次说清楚。适合正在做大模型部署、推理优化和成本控制的同学参考刚接触量化的朋友也能通过这篇文章把整条技术线建立起来。1. 量化到底在优化什么显存、带宽与计算的三方博弈1.1 先搞清楚模型推理的成本结构很多人以为大模型推理最贵的是算力其实真正卡脖子的是显存容量和显存带宽。模型在推理时每一层都要把权重从显存搬到计算单元70B模型哪怕只生成一个token也要把所有权重扫一遍。这个过程中计算单元大部分时间在等数据而不是在算数据所以模型越大带宽越容易成为瓶颈。如果把权重从FP16变成INT4权重体积直接缩到原来的四分之一同样一张卡能塞下更大的模型单位时间能从显存搬出更多权重。对batch size较小的在线推理场景来说这样的带宽收益几乎直接转化为生成速度的提升。量化减少的不仅是存储空间更是推理链路里最贵的搬运成本。1.2 INT8量化的核心公式scale和zero pointINT8量化本质上是把一个浮点数值映射到-128到127的整数区间。映射过程需要两个参数一个是缩放系数scale一个是零点zero point。反量化公式是real_value (int_value - zero_point) * scale。正向量化就是先除scale再加zero point最后做四舍五入和截断。这里的关键问题是scale怎么选。最常用的是对称量化也就是把浮点范围取绝对值最大值然后映射到对称区间。很多场景会用非对称量化因为权重和激活值往往不是对称分布的非对称量化能减少截断误差。对激活值来说ReLU之后基本都是非负值用非对称量化优势更明显。实际推理时INT8乘法的结果需要反量化回FP16继续累加。这里是数值精度最容易出问题的地方一个很小的scale会让相邻整数代表的浮点值间隔很小但超出范围的数值会被粗暴截断。所以scale的选取本质上是在精度和范围之间做取舍。1.3 量化粒度从per-tensor到per-group量化粒度决定了多少个数值共享同一组scale和zero point。最简单的per-tensor量化是整个张量一个scale开销最小但精度最差尤其当权重分布存在明显离群值时一个极端值就能把整个量化区间撑大其他权重全部失去精度。per-channel量化是每个输出通道单独一套参数精度明显提升也是ONNX Runtime等框架里INT8静态量化的常见配置。再往前一步是per-group量化比如把128个数值分成一组每组单独计算scale这是GPTQ、AWQ这些4bit方案的核心思路。group size越小量化越精细但存储scale和zero point的开销也会变大实际使用时会用128或64作为平衡点。我一直和团队强调一个观点看到量化精度下降不要急着怀疑算法本身先检查量化粒度。很多模型的精度问题只是per-tensor换成per-channel就解决了。2. 从训练后量化到量化感知训练精度与收益怎么平衡2.1 PTQ成本最低的量化路线训练后量化Post-Training QuantizationPTQ不需要重新训练模型拿一个已经训练好的模型喂一些样本统计数值范围就能完成量化。INT8级别的PTQ在多数场景下精度损失很小这也是ONNX Runtime、TensorRT里最常用的路线。但PTQ有个天然软肋它只能基于有限的校准样本来估计权重和激活值的分布。如果校准数据分布和线上真实数据偏差大量化参数就会不准。另一个问题是PTQ无法修正权重本身所有补偿都是在量化误差出现后做的“事后补救”。到了4bit级别直接用普通PTQ基本不可行所以GPTQ和AWQ才会用各种方法在量化过程中补偿误差。2.2 QAT用训练时间换精度量化感知训练Quantization-Aware TrainingQAT是把量化过程模拟进训练流程。训练时权重仍然是浮点但前向传播会模拟量化的舍入效果让模型在训练阶段就适应量化带来的噪声。反向传播里通过直通估计器绕过舍入函数不可导的问题从而保证梯度能正常流动。QAT的效果通常比PTQ好尤其是模型较小、任务较敏感的场景。代价也很明显需要训练数据和训练资源训练时间变长整个流程不再是“下载模型直接量化”这么简单。对大模型来说全量QAT的成本很高所以实际中很多团队只对最后几层做QAT或者先用PTQ量化再用少量数据微调恢复精度。我见过不少项目在INT8精度不达标时直接上QAT其实先试试更好的校准集、更细的量化粒度往往就能解决问题。QAT应该是最后的手段而不是首选手段。2.3 校准数据集很多人忽略的关键变量静态量化需要一个校准数据集来统计激活值的分布。这个数据集不需要很大几百到上千条有代表性的样本就够用但“有代表性”三个字特别重要。实际项目里最常见的错误是随便拿一批训练数据当校准集。训练数据分布和推理时真实业务数据如果差得远统计出来的量化范围就是偏的。比如做对话模型线上输入可能都是短文本你却拿长文档做校准激活值范围整体偏大或偏小量化精度自然受影响。选校准集时我会让业务方抽几天的线上真实样本先做脱敏和截断再混合一部分通用数据。另外校准集样本之间要保持多样性不要几百条全是相似内容否则统计方差太小等于没校准。 校准集的数量不是越多越好关键是分布覆盖度。3. GPTQ、AWQ与ONNX INT8三种实战路线怎么选3.1 GPTQ基于二阶信息的权重补偿GPTQGenerative Pre-trained Transformer Quantization是目前4bit量化里应用最广的方法之一。它的核心思路是逐层量化权重同时用Hessian矩阵的二阶信息来补偿量化带来的误差。简单理解把某一层的权重矩阵看成一个整体量化掉其中一部分数值后模型输出会产生偏差。GPTQ不是在每个值上独立做四舍五入而是动态调整当前层剩余未量化的权重让整层的输出分布尽量接近量化前。这种“拆东墙补西墙”的补偿策略让4bit的精度在很多任务上能逼近FP16。实际使用中最需要考虑的参数是group size和desc_act。desc_act表示是否按激活值大小重排列顺序开启后精度更高但推理时会更慢。在transformers里用GPTQ很简单加载时直接指定quantization_config即可。下面这段代码是7B模型量化后加载的标准姿势from transformers import AutoModelForCausalLM, AutoTokenizer, GPTQConfig model_id meta-llama/Llama-2-7b-chat-hf quantize_config GPTQConfig( bits4, group_size128, desc_actFalse, tokenizerAutoTokenizer.from_pretrained(model_id) ) model AutoModelForCausalLM.from_pretrained( model_id, quantization_configquantize_config, device_mapauto )3.2 AWQ让激活值说话AWQActivation-aware Weight Quantization和GPTQ的出发点不太一样。GPTQ关注的是如何补偿量化误差而AWQ更关注哪些权重更重要。AWQ观察到权重的重要性并不完全取决于权重本身而取决于对应激活值的大小。如果某个通道的激活值普遍很大那么这个通道的权重即使只量化错一点对输出影响也很大。AWQ的做法是基于激活值分布识别出重要通道在对这些通道做量化时不要直接量化而是乘一个缩放因子来保留精度。这个超参数通过小规模搜索确定整个过程不依赖反向传播所以速度很快。用AutoAWQ量化模型也很直接核心是让数据集走一遍前向统计激活分布。下面是最小示例from awq import AutoAWQForCausalLM from transformers import AutoTokenizer model_path meta-llama/Llama-2-7b-chat-hf quant_path llama-2-7b-awq model AutoAWQForCausalLM.from_pretrained(model_path) tokenizer AutoTokenizer.from_pretrained(model_path) quant_config { zero_point: True, q_group_size: 128, w_bit: 4, version: GEMM } model.quantize(tokenizer, quant_configquant_config) model.save_quantized(quant_path) model AutoAWQForCausalLM.from_quantized(quant_path)AWQ量化后的模型可以用vLLM加载生成吞吐往往比同配置GPTQ略好一些原因在于AWQ的kernel实现更便于batch推理。具体选哪个还得看你的推理框架和硬件兼容性。3.3 ONNX Runtime INT8量化部署侧的稳妥方案很多人在大模型语境里只提GPTQ/AWQ但实际生产环境里最常用的量化手段其实是ONNX Runtime的INT8量化。特别是中小模型比如embedding模型、BERT类模型、多模态模型用ONNX INT8能拿到很稳定的加速比而且部署生态非常成熟。ONNX量化分为动态量化和静态量化。动态量化不需要校准数据推理时实时计算激活值的scale实现简单但加速有限静态量化需要校准流程推理时激活值用的是预计算的scale性能更好。对Transformer模型来说静态量化几乎必然是首选。具体操作可以直接用onnxruntime的quantize_static接口import onnx from onnxruntime.quantization import quantize_static, QuantType from onnxruntime.quantization.preprocess import quant_pre_process model_path model.onnx preprocessed_path model_preprocessed.onnx quantized_path model_int8.onnx quant_pre_process(model_path, preprocessed_path) from onnxruntime.quantization import CalibrationDataReader class Dataloader(CalibrationDataReader): def __init__(self, samples): self.samples samples self.iter iter(samples) def get_next(self): return next(self.iter, None) calib_samples [...] # 建议准备100~500个真实输入 quantize_static( preprocessed_path, quantized_path, Dataloader(calib_samples), per_channelTrue, weight_typeQuantType.QInt8, activation_typeQuantType.QInt8 )量化前建议先做一遍onnx-simplifier优化把Constant折叠、冗余节点清理掉。否则量化时很多算子类型不匹配还得花时间改图。3.4 选型对比不同方案适合什么场景方案量化位数是否需要校准数据精度表现主要优势适合场景ONNX INT8静态量化8bit是通常接近FP16部署生态成熟中小模型、CPU/边缘设备INT8动态量化8bit否略差接入简单快速验证、小模型GPTQ4bit/3bit/2bit否4bit下接近FP16精度补偿好大模型显存受限AWQ4bit/3bit/2bit否4bit下接近FP16重要通道保留精度大模型高吞吐推理QAT任意是训练数据最优量化感知训练精度极度敏感场景我个人经验是70B以上模型先用AWQ跑因为它在高batch场景的kernel优化更成熟13B到30B级别的模型GPTQ和AWQ都行哪个框架和你现有服务兼容用哪个7B以下模型除非显存真的紧张否则优先INT8精度和速度都比较均衡。4. 实战指南从量化到部署的完整流程4.1 第一步确定精度目标和硬件约束动手量化之前不要直接调参先把一件事想清楚精度的底线是什么硬件的上限是什么。我一般会先明确这些问题模型在线上要跑多大的batch单卡显存是多少延迟要求是多少精度目标是用什么指标衡量。这些答案直接决定量化方案。如果延迟要求极高、batch size又小那INT8甚至FP8的收益可能不够明显不如直接上4bit如果显存还够但带宽吃紧可以考虑INT8加增大batch来摊薄带宽。所有部署优化的本质都是在延迟、吞吐、显存和精度之间找平衡点。4.2 第二步用AutoGPTQ量化一个7B模型按我的习惯先拿7B模型跑一遍完整流程确认工具链没问题再往更大的模型上迁移。AutoGPTQ除了transformers内置的GPTQConfig之外还有自己的命令行工具用起来更直观pip install auto-gptq python -m auto_gptq.quantization \ --model_dir meta-llama/Llama-2-7b-chat-hf \ --output_dir llama-2-7b-gptq \ --bits 4 \ --group_size 128 \ --desc_act这个命令会先加载模型跑一段校准数据然后逐层做量化。量化完成后目录里会生成模型权重和配置文件之后直接用AutoModelForCausalLM加载即可。有几个细节要提醒desc_act开启后精度会好一点但会导致推理慢一些尤其是单batch场景。group size建议128起步64虽然精度更高但存储开销变大实际收益可能没那么明显。位数建议先试4bit如果显存还紧张再往3bit压不要一上来就直接2bit那个精度在很多任务上基本没法用。4.3 第三步用AWQ量化并做推理验证AWQ的量化过程比GPTQ要快不少因为它没有复杂的逐层补偿重计算。命令行工具同样支持一行式量化pip install autoawq python -m awq.entry \ --model_path meta-llama/Llama-2-7b-chat-hf \ --quant_path llama-2-7b-awq \ --w_bit 4 \ --q_group_size 128 \ --zero_point量化完成后的加载方式各家框架略有差异。HuggingFace transformes可以直接通过AWQ模型目录加载vLLM则需要在启动时指定量化方式python -m vllm.entrypoints.openai.api_server \ --model llama-2-7b-awq \ --quantization awq \ --dtype float16 \ --gpu-memory-utilization 0.9vLLM加载AWQ之后我建议先用一段固定prompt做多次请求查看首token延迟和生成速度是否稳定。如果数值异常先确认模型是量化版本还是原始版本这是我踩过的坑目录里混放了两套权重结果框架加载了错误路径。4.4 第四步性能验证与回退策略量化完之后不能只看“能跑就完事”要建立一套回退机制。我会在量化模型上跑三组测试一组用公开评测集看通用能力一组用业务自己的测试集看具体任务指标一组跑真实线上请求样本看生成质量和延迟。一旦量化模型在关键指标上不达标不要硬调直接回退一档。比如AWQ 4bit精度不行先试group size从128改成64还不行就换GPTQ或者回到INT8实在不行再上QAT。量化方案的选择不是一锤子买卖要把整套配置做成可回退的版本参数。每次改动记录好配置、评测结果和显存占用这样后期调优才能有据可查。5. 常见问题与排查技巧实录精度下降、报错与边缘设备部署5.1 int8量化后精度明显下降数值基本不动这个现象在边缘设备上尤其常见很多人在RKNN上做INT8量化后模型输出要么全是固定值要么和原始模型差距巨大。出现“数值不动”通常是量化后的激活值被截断到某个区间或者某些层被错误地过度压缩导致信息全部丢失。我排查这类问题的顺序是先用单层对比工具逐层比较量化前后输出。哪个层输出开始剧烈变化问题就出在哪。接下来看这一层的权重分布如果有明显的离群值先试试per-channel量化能不能解决。再不行就把该层从量化中排除很多推理框架支持设置排除算子列表。不要一开始就怀疑量化工具多数情况下是模型里存在对数值极其敏感的层比如归一化层、某些特殊激活函数所在的层。把这些层保留为浮点其他层INT8量化问题往往立刻缓解。5.2 报错ValueError / cannot find the config file for AWQ使用AWQ加载量化模型时遇到过类似报错先报ValueError说缺少config再提示找不到AWQ的配置文件。这个问题的原因基本集中在三点。第一是量化路径下的文件夹结构和HuggingFace格式不一致。确保目录里至少有config.json、tokenizer文件、量化后的权重文件以及可能需要的量化配置节点。第二是模型实际类型不是AWQ但加载代码里写了quantizationawq。这种情况我遇到过很多次下载的模型其实是普通FP16版本文件名看着像AWQ实际没有量化参数。第三是transformers或autoawq版本太旧无法解析新格式的AWQ配置。处理办法很简单先把transformers、autoawq都升到最新版重新检查目录结构。如果还不行就用AutoAWQForCausalLM.from_pretrained而不是from_quantized加载试一下有些模型的配置节点放在文件头部旧解析逻辑会漏掉。5.3 ONNX转RKNN时的INT8量化问题边缘推理设备上RKNN工具链的INT8量化是很多人绕不过去的坎。ONNX转RKNN的过程中最常碰到的是算子在转换后数值异常。特别是一些回归类模型FP32推理正常一转INT8输出就不对劲。这类问题要从两个方向排查。先看RKNN量化时是否选择了正确的数据归一化方式尤其是输入输出的scale和zero point很多模型的预处理代码里已经做了归一化RKNN里又做一遍数值自然就偏了。再看模型里是否有量化工具不支持的算子比如某些自定义ROI层或者动态shape操作这类算子很容易在转换时被错误处理。建议先用工具打印每一层的推理输出逐个判断哪些层是“带病工作”。5.4 调参避坑心得汇总量化调参没有银弹但我积累了几个重点排查方向整理成表格供参考现象可能原因优先排查项量化后精度掉很多校准数据集分布偏差换成线上真实分布样本输出数值固定激活值截断检查scale范围、排除敏感层4bit精度不稳group size过大128改成64或32GPTQ推理变慢desc_act开启关闭或换AWQAWQ加载报错版本或目录问题升级库、检查配置文件RKNN转换数值异常归一化重复或算子不支持逐层对比输出另外提醒一句量化模型的评测一定要在同一套prompt模板下做不同的模板风格有时比量化本身带来的差异还大。线上用什么样的prompt评测就用什么样的prompt这样才能真正对比出量化损失。最后再分享一个小技巧每次做量化实验时把Hessian矩阵计算、激活分布统计、量化后模型输出这三份信息保存下来。下次再遇到精度问题直接对比这三份信息能省下大量重复排查时间。量化这条路没有终点模型更新一版量化流程就要重新验证一遍。把这些分析和调试习惯沉淀成团队内部的标准流程比死记某一个参数组合可靠得多。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门