量化这个词,但凡碰过大模型部署的人,肯定天天挂在嘴边。我最早真正被量化"逼着"去研究,是某一次想在本地卡上跑一个开源对话模型——显存只有十几GB,模型权重FP16单份就要接近二十GB,压根装不进去。后来把权重压到4bit,模型跑起来了,回答质量也没有想象中那么拉垮。从那一刻起我就明白:量化不是锦上添花的优化手段,而是把大模型真正用起来的前置条件。
这篇就集中聊两件事:一是大模型为什么要量化,把底层账算明白;二是量化领域里那些主流技术到底是怎么工作的,以及你在实际部署中应该怎么选、怎么避坑。适合刚接触大模型推理优化的人,也适合已经跑过量化但只知其然、不知其所以然的朋友。
1. 算清显存与带宽这笔账:量化到底解决了什么
很多人理解量化,只知道"省显存"这三个字。实际上量化解决的不只是存储问题,还有一个常常被忽略的瓶颈——内存带宽。先把这两笔账分别算清楚。
1.1 一次推理到底要吃多少显存
推理时显存占用不是只有模型权重这一块。峰值显存大致由三部分构成:
模型权重。一个70B级别的模型,FP16精度下每个参数占2字节,光权重就是70×2=140GB。这个数字已经超过目前单张主流加速卡的显存容量了,更别提还要留空间给后续的计算。这也是为什么很多超大模型不开量化根本没法在单卡上推理。
激活值与中间张量。推理过程中每一层都要产生中间结果,激活值大小跟batch size和序列长度强相关。batch为1、序列长度几千时,激活值大概会额外吃几GB到十几GB的显存,具体取决于网络结构和框架实现。
KV Cache。自回归生成时要缓存历史token的Key和Value,它随序列长度线性增长。算一下量级:某个7B模型,hidden size大概是4096,层数32层,每个token的KV Cache就是4096×2×2字节×32层,约1MB左右。序列长度2048时,光KV Cache就要吃掉2GB上下。这只是个示意量级,不同模型差异很大,但趋势是明确的——长上下文场景下,KV Cache往往是压垮显存的最后一根稻草。
把这三块加起来,一个70B模型想在FP16下跑起来,单卡显存需求轻松超过150GB。而市面上消费级产品的主流显存还停留在十几到二十几GB,专业卡也不过80GB量级。你说不量化怎么办?要么切碎模型做分布式,要么把精度降下来。
1.2 内存带宽才是推理提速的隐形瓶颈
再算一笔性能账。大模型推理的每个生成步骤,都需要把全部权重从显存搬到计算单元里参与矩阵乘。注意,是全部权重都要搬一遍。一个7B模型的FP16权重是14GB,假设你的卡内存带宽是1TB/s,搬完一遍理论最快也要14毫秒。这个数字已经很接近实际生成的单token延迟量级了。
这说明什么?大模型推理是典型的访存密集而不是计算密集。显卡的计算单元大多时候在空等数据搬运,真正的计算时间远小于搬数据的时间。量化把权重从2字节压到1字节甚至0.5字节,搬运量直接减半或减到四分之一,等效于把可用带宽翻倍。这就是为什么很多场景下量化后不仅显存够了,生成速度也实打实地变快了——不是幻觉,是带宽账算出来的必然结果。
1.3 量化换来的不是精度,是部署自由度
当然,量化不是没有代价。把连续浮点映射到稀疏整数码值,一定会损失信息,模型输出质量可能下降。但你要算另外一笔账:不量化的代价是模型根本跑不起来,或者要用好几张卡才能跑。量化是用可接受的精度损失,换取部署的自由度——单卡跑更大模型、同样的卡跑更多并发、更低的硬件成本、更低的延迟。
这个逻辑有点像视频压缩:无损原始文件你存不下、传不动,有损压缩之后体验上差别不大,但能正常看了。大模型量化也是同理。理解了"为什么"之后,再去看"怎么做",思路就清晰了。
2. 量化在底层做了什么:位宽、Scale、Zero Point与三种粒度
量化听起来玄乎,核心思想其实很简单:把原本用FP16或FP32表示的一组浮点数,映射到更低位宽的整数上,比如INT8、INT4。难点从来不在于"映射"本身,而在于怎么映射才能让精度损失最小。
2.1 量化的数学本质:一段浮点区间映射到整数码值
先回顾一下浮点数的结构。FP16有1位符号位、5位指数位和10位尾数位,BF16则是8位指数加7位尾数。它们能表示的范围和精度不一样,但共同点是开销高。量化要做的,就是抛弃这种"宽动态范围 + 高精度"的表达方式,改用整数码值去近似原值。
最朴素的量化是线性映射。假设一个权重向量里的值分布在某个区间内,我们要把它映射到INT8的码值范围。映射需要两个关键参数:
Scale缩放因子:决定一个整数码值代表多大的浮点步长。
Zero Point零点:决定浮点0对应到哪个整数码值。
对称量化里零点恒等于0,公式很干净:q = round(x / scale),反量化就是x_approx = q × scale。scale的计算方式是max(|x|) / (2^(b-1) - 1),b是位宽。假如权重分布在[-1.0, 1.0],INT8的scale就是1/127,约等于0.0079。
非对称量化则多一个零点偏移,公式变成q = round(x / scale) + zero_point,scale用(max - min) / (2^b - 1)计算,zero_point等于round(-min / scale)。非对称量化能贴合任意分布区间,但代价是矩阵乘实现更复杂,因为整数运算里多了一个非零偏移项。
举个实际的例子感受下误差。假设一组权重实际分布在[-0.5, 0.5],用INT8对称量化,scale=0.5/127≈0.00394。某个权重是0.2,量化成q=round(0.2/0.00394)≈51,反量化回来是51×0.00394≈0.201。误差百分比不到1%,还算可以接受。但如果你把这组权重强行套到[-1.0, 1.0]的scale上,同样的0.2只能对应到25或26,反量化回来误差就接近2%,翻了一倍。这说明量化误差的上限,很大程度取决于你的scale跟实际分布贴不贴合。
2.2 对称量化与非对称量化:怎么选
对称量化的好处在于反量化简单、推理时整数运算没有零点偏移,很多矩阵乘的底层实现更高效。坏处是它对分布有要求:如果权重的浮点分布整体偏向一侧,比如都集中在[0.0, 1.0],对称量化还会用[-127, 127]的整个码值范围去套,结果一半码值编码区间的浪费,有效精度相当于直接砍半。
非对称量化的"零点"能智能移动,让码值范围完全覆盖实际分布区间。对于激活值或者某些分布明显偏斜的权重张量,非对称量化往往能显著降低误差。代价是实现成本高一些,目前大部分支持非对称量化的推理框架也都做得很成熟了,建议优先考虑后端支持程度,而不是一味追求某一种对称性。
2.3 量化粒度:一套尺子还是每块区域一把尺子
刚才说的scale和zero_point,是针对整组数据算一份,还是分组各算各的,这就是量化粒度的选择。业界常见三种:
Per-tensor:整个张量共享一份scale和zero_point。实现最简单,但代价是如果一个张量里有少数特别大的离群值,整个scale都会被拉大,其余多数正常值被迫挤到很窄的码值区间,误差飙升。
Per-channel:每个输出通道单独算一份scale。精度比per-tensor好不少,因为不同通道的数值分布差异往往很大,一个通道一套尺子能贴合自己的分布。开销是一个张量要存若干组scale,但相对权重本身占用来说这点额外存储可以忽略。
Per-group:把张量拆成固定大小的小块,比如128个元素一组,每组单独算scale和zero_point。这是目前4bit量化的主流做法。原因很简单:位宽越低,码值越少,粗粒度量化根本顶不住误差累积,必须用更精细的group粒度。
打个比方你就明白了:per-tensor是拿一把全屋通用的尺子量所有房间,遇到一个房间特别大,其他房间的测量精度统统变差;per-channel是每个房间配一把尺子,精度好了不少;per-group是每个角落里都挂一把尺子,哪里量哪里准。量化粒度越细,精度越高,代价是存储和计算scale的开销也越大,所以在工程上是一个需要权衡的参数。
3. 主流量化技术路线全拆解:从8bit到4bit的演进路径
搞懂了量化基本原理,再去看业界那些眼花缭乱的量化方案就有谱了。按照是否需要训练,量化分成两大路线:训练后量化PTQ和量化感知训练QAT。绝大多数应用场景走的都是PTQ,因为不需要动训练流程、不需要额外数据标注、转换速度也快。
3.1 动态量化与混合精度:对离群值的及时处理
最早的实用化方案之一是8bit动态量化。它的思路很直接:推理时对每个token或每个矩阵乘动态计算scale,而不是事先静态定好。这样能适应输入分布的变化,比静态量化更稳。
典型的代表做法是LLM.int8()方案里提出的思路:作者观察到大模型激活值里存在少量数值很大的离群特征,这些特征如果按普通scale量化,会把整段精度拉崩。于是他们把矩阵分成两路——大部分普通值走INT8量化计算,少量包含离群值的列保留FP16原样计算,最后把两部分结果合并。相当于"体检报告里个别指标太异常,医生就单独标注出来用精密仪器复查"。这种混合精度思路在8bit场景下效果很好,但再往下探到4bit就比较吃力了。
3.2 GPTQ式二阶近似:用Hessian信息做更好的补偿
8bit动态量化解决的是"量化那一刻怎么最准",而GPTQ这一类方案解决的是"量化完一批权重之后,怎么补偿误差"。
它的原理说有启发意义:想象你要把一组权重改成低bit版本,每个权重一量化就引入了误差,但你可以不急着认命——利用校准数据算出来的二阶信息(Hessian矩阵),去调整尚未量化的剩余权重,让它们分摊一部分已经被引入的误差。本质上是在做有补偿的逐层量化:量化一部分,剩余部分跟着修正,最终让整体输出分布尽量接近原始模型。
GPTQ类方案在4bit场景下表现相当不错,是目前离线转换大模型时最常用的选择之一。它有几个特点:一次量化一个层,整个过程跑完只需要几分钟到几十分钟;量化过程中要用校准数据计算统计量,校准集质量和模型最终精度强相关;量化完成后的权重可以直接用支持对应group格式的推理框架加载,推理阶段没有额外负担。
3.3 AWQ激活感知量化:不是所有权重都同样重要
GPTQ思考的是"怎么量化误差更小",而AWQ换了一个角度:是不是所有权重都值得同等精度对待?答案是显然不是——模型里存在一些"重要通道",它们对最终输出的影响远大于其他通道。
AWQ通过观察校准数据在每一层产生的激活值幅度来判断哪些通道重要。激活幅度大的通道,对应权重对输出影响也大,所以AWQ会给这些通道的权重乘以一个额外的缩放因子,相当于在量化时给它们分配更高的有效比例。这样的做法有几个好处:不需要反向传播,不需要训练,完全基于权重和激活统计就能完成转换;计算成本不高,转换速度也快。AWQ在4bit场景下的表现跟GPTQ属于同一梯队,实际选择时更多看你的推理框架支持哪一个。
3.4 SmoothQuant平滑激活:把激活的"刺头"转移到权重上
前几种方案主要量化权重,激活默认还是FP16。但如果你想追求更高的吞吐,连激活一起量化为INT8,就会遇到一个棘手的问题:激活值中存在明显的离群值,动态范围远大于权重,直接量化误差很大。
SmoothQuant的思路是:既然激活里有刺头,权重分布相对平滑,那就把激活里的数值波动"迁移"一部分到权重上。具体做法是对每个通道施加一个平滑因子,让激活分布变得更平坦,同时权重分布稍微变得崎岖一点,最终两者都落在可量化的范围里。这样整个网络在推理时权重和激活都走INT8,计算效率和显存收益比只量化权重高一个量级。适合追求极致推理性能、且精度容忍度比较好的场景。
我把主流的PTQ方案放在一起对比一下:
| 方案 | 核心思想 | 典型位宽 | 是否需要训练 | 精度表现 | 适合场景 |
|---|---|---|---|---|---|
| 动态量化 | 按token动态算scale,离群值保留高精度 | 8bit | 否 | 良好 | 快速部署、兼容性优先 |
| GPTQ式二阶近似 | 用Hessian信息补偿未量化权重误差 | 4bit | 否 | 优秀 | 离线转换大模型、追求压缩比 |
| AWQ激活感知 | 识别重要通道,给予更高有效精度 | 4bit | 否 | 优秀 | 4bit部署、框架支持完善的场景 |
| SmoothQuant | 平滑激活分布,激活权重双INT8 | 8bit | 否 | 良好 | 追求极致吞吐、激活量化场景 |
3.5 量化感知训练:什么时候才值得上
PTQ再优秀也有上限。你要压到2bit、3bit这种极致低位,或者你的任务对精度极度敏感(比如医疗、金融类的结构化输出),训练后量化往往撑不住。这时候就得走QAT——量化感知训练。
QAT的原理一句话就能讲清:在训练或微调阶段,把量化的舍入误差模拟进前向过程,让模型在训练中主动适应"未来会被量化"这件事。具体实现里通常会用fake quant节点模拟量化-反量化,反向传播时用直通估计绕过不可导的舍入运算。
代价也很明显:需要训练脚本、计算资源和数据,整体成本比PTQ高一到两个数量级。所以我的判断是,除非PTQ精度已经明显打不过业务需求,否则优先考虑PTQ就好。QAT一般是"实在不行了"的兜底手段,或者是你有长期固定模型需要反复迭代部署时的前置投资。
另外提一句新硬件上的新格式。最近一两年加速卡原生支持FP8甚至MXFP4这类微缩放格式,本质上还是在低位宽上做文章——FP8用E4M3或E5M4两种指数尾数配比覆盖不同动态范围,MXFP4则通过块级共享缩放因子实现比普通4bit整数更好的精度表现。这些属于"硬件帮你把scale算好了"的升级版量化,如果你用的推理引擎和加速卡支持,尽量优先用硬件原生格式,性能和精度都比纯软件模拟好得多。
4. 量化实测:显存、延迟、精度的三方权衡
讲了一堆原理,来看点实际的。我用一个开源7B对话模型做过一轮FP16、INT8、INT4三种精度的对比测试,下面这组数据是我个人实测的大致量级,不同硬件和框架下会有浮动,但趋势非常有代表性。
| 精度格式 | 权重显存占用 | 相对速度(生成token/秒) | 常见任务精度(相对FP16) |
|---|---|---|---|
| FP16 | 约14GB | 1.0倍基准 | 100% |
| INT8 | 约7GB | 约1.3-1.5倍 | 98-99% |
| INT4(group量化) | 约3.5GB | 约1.5-1.8倍 | 95-98% |
4.1 显存确实省了,速度也确实快了
从表里看,INT8比FP16省一半显存,速度提升三到五成;INT4再砍一半显存,速度继续往上走。原因就是我前面说的带宽账——低位宽意味着单位时间能搬更多参数进计算单元,生成吞吐自然上去了。这里有个容易误解的点:模型越小,量化带来的速度收益越明显,因为小模型的计算比例更低、访存瓶颈更突出;反过来,模型大到一定规模,量化省下的显存可能让你能开更大的batch,吞吐收益就更夸张。
4.2 精度下降不是均匀的,有些任务特别受伤
量化对模型能力的损伤并不是"所有任务等比例下降",而是有明显的偏向。以我测过的模型为例:日常问答、短文本摘要、信息抽取这类任务,INT4下下降通常不超过2个点,体感差异很小;但数学计算、多步推理、代码逻辑生成这类任务,INT4下错误率可能翻倍甚至更高。我还遇到过一个有意思的现象:某些模型量化后对长上下文的记忆力下降明显,对话稍微多轮就开始"忘事"。
原因也不难理解——推理类任务对每一步计算的微小误差高度敏感,误差会在多步推导中不断累积放大;而简单生成类任务容错空间大,个别数值不精确不影响大局。所以评估量化效果时千万别只看综合指标,一定要把你业务里最典型、最困难的任务单独拎出来对比。
4.3 显存小了不等于速度一定快:三个容易忽略的因素
我在实际部署里发现,量化后速度反而更慢的情况虽然不多,但确实存在。常见干扰因素有三个。
第一个是反量化开销。如果推理框架实现得不好,每次计算前都要先把低位宽权重反量化回FP16,这一步的显存访问开销可能吃掉压缩带来的收益。底层算子优化到位的框架,可以直接在整数域做矩阵乘,速度才有保证。
第二个是算子回退。某些框架对特定group size或特定shape支持不全,遇到不支持的情况就自动回退到FP16计算,你辛辛苦苦压到4bit,运行时压根没走4bit内核。
第三个是硬件差异。有些加速卡对INT8/INT4有专门的计算单元,有些则没有,纯靠通用单元硬算,加上反量化开销,速度自然上不去。所以选型的时候,别只看理论压缩比,最好拿目标硬件实测一轮。
5. 工程落地的关键动作:校准集、推理后端与KV Cache量化
原理有了、方案清楚了,最后拼的是工程细节。量化部署这件事,很多坑都藏在"看起来差不多"的细节里。
5.1 校准集怎么选:分布匹配比数量更重要
PTQ方案几乎都需要一小批校准数据来统计权重和激活的分布。很多人以为校准集越大越好,其实不是。以GPTQ类方案的经验来看,128到256条高质量样本通常就足够,再多反而可能过拟合到校准集本身的分布上。
校准集最重要的原则是跟线上真实输入分布一致。如果你做的是法律文档问答,就别拿通用百科语料去校准;如果你线上输入普遍偏长,校准样本的序列长度就要覆盖长文。我见过最典型的反例:某开发者拿通用评测集做校准,离线指标很漂亮,上线后对业务里的专业术语和长文档完全不在状态,就是因为校准分布和真实分布差了十万八千里。
5.2 推理后端选型与量化格式兼容性
量化是一个前端动作,最终跑起来靠的是推理后端。不同的后端对量化格式的支持差异非常大,选型时不要只看"支不支持4bit",要看到具体支持哪种group size、哪种量化方案、哪些算子走量化内核。
我的建议是:确定一个模型后,先查目标后端对应的算子兼容表,重点关注Attention、FFN、Embedding这几个关键模块的量化支持情况。如果某个算子在你的目标位宽下不支持,运行时会走回退,轻则速度损失,重则直接OOM。另外,很多后端提供"动态量化"和"预量化"两种模式:动态量化加载时现算,灵活但每次加载有额外开销;预量化是提前转好格式,加载即用,适合固定模型反复部署的场景。生产环境优先用预量化。
5.3 KV Cache量化:长上下文的显存救星
前面算过,KV Cache随序列长度线性增长,长上下文场景下它的显存开销可能飙到跟权重一个量级。很多人量化了权重却不量化KV Cache,结果序列一长照样OOM。
KV Cache量化的思路是给缓存里的Key和Value也用INT8甚至更低位宽存储,推理时再反量化到FP16参与attention计算。好处非常直接:长上下文下显存占用砍半以上,能处理的文档长度大幅提升。代价是精度会有一定损失,注意力分数的数值误差可能累积。
我个人的实践建议是:做长上下文场景时,KV Cache量化值得优先开8bit。这一步的收益大、风险低,开了之后再评估更激进的4bit KV Cache。另外注意,某些框架的KV Cache量化是按per-token或per-head维护scale的,看起来是细节,实则会直接影响精度,选型时留意一下。
5.4 上线前的验证清单
量化模型上线前,我建议至少过一遍这个清单:
- 业务指标对比:用跟线上最贴近的评测集,对比FP16和量化版的关键指标,别只看综合分,要看分任务的表现。
- Badcase逐条对比:固定随机种子,让两个版本对同一批输入分别生成结果,人工过一遍差异大的case,判断是否不可接受。
- 长文本压力测试:用最大业务序列长度跑一轮,观察显存峰值和生成质量,确认KV Cache量化配置正确生效。
- 并发与峰值显存验证:量化省下的显存是否被并发请求吃掉,需要实测峰值,别只看单请求的理论占用。
- 数据格式落盘验证:确认量化模型文件能稳定加载,没有版本兼容问题,避免上线当天才发现格式不匹配。
6. 量化部署踩坑实录:五个典型的翻车现场
最后分享几个我踩过、或者身边朋友踩过的真实场景,每一个都对应一个容易被忽略的细节。把这些坑提前排掉,能帮你省下大量排查时间。
6.1 只量化权重不处理激活,精度直接崩掉
有个项目把一个7B模型压到4bit,量化后模型能加载、能生成,但输出明显语无伦次。排查后发现问题出在激活值上:权重被压到4bit了,激活还是FP16,但如果权重量化时没有同时考虑激活分布,某些离群输入在计算时会把激活推到一个极端范围,导致后续层输出漂移。后来换成了感知激活的量化方案,问题就消失了。
这条经验是:4bit量化方案一定要选考虑了激活分布的,要么用AWQ式思路,要么用带校准激活统计的group量化,别天真地以为只压权重就万事大吉。
6.2 校准集与业务分布错配,线上输出漂移
有位开发者用公开评测集校准了一个量化模型,离线看指标一切都好,上线后却发现模型对用户实际提问的回答风格产生了明显漂移——变得空泛、套话多,关键信息丢失。原因正是校准集分布跟线上数据分布不一致。后来他从线上日志里抽取了几百条真实Prompt重新校准,重新评测后漂移问题基本消失。
这条经验是:校准集不在于多,而在于准。动手前先花半小时从日志里采样一批真实输入,比你费劲清洗公开数据集有用得多。
6.3 量化后反而变慢,问题出在算子回退
有一次我把一个模型切到4bit,预期速度提升没有出现,延迟反而增加了30%。用性能分析工具定位后发现,模型里的某个自定义算子在这个推理框架下压根没有4bit内核,每次计算都先反量化成FP16再跑矩阵乘,额外开销远超压缩收益。换到另一个对算子支持更全的框架后,延迟立刻恢复正常。
这条经验是:量化方案定了之后,先用性能分析工具确认所有算子都真的走了量化内核,不要相信框架的"自动转换",自动转换往往会默默回退。
6.4 长上下文OOM:忘了KV Cache这回事
还有一次,短文本场景下量化模型跑得很稳,但一喂长文档就OOM。当时权重已经压到4bit,按理说显存很宽裕,问题就出在KV Cache——序列长度一上去,KV Cache的显存开销线性爆炸,直接吃完了所有剩余空间。后来开了KV Cache 8bit量化,把长文本处理能力翻了将近一倍。
这条经验是:量化部署时一定要把KV Cache单独拎出来算账。权重省出来的显存,很容易被长上下文的KV Cache原封不动吃回去。
6.5 低比特矩阵乘的内核兼容性
最后一个坑比较隐蔽。某个模型在转换时选了group size为128,但在目标推理框架里,这个group size只对部分矩阵乘法算子有优化支持,其余算子自动走通用路径。结果就是显存确实降低了,但速度没上来,部分算子的延迟甚至比量化前还差。换成框架默认支持的group size之后,性能立刻正常。
这条经验是:group size不是随便选的,先查推理框架的算子支持表,再决定用128还是其他尺寸。选一个框架原生优化好的参数,比理论上更精细的参数靠谱得多。
如果你也在量化部署上踩过类似的坑,那很正常——这个领域发展太快,文档永远跟不上实践。我个人的默认动作是:新模型到手,先FP16跑一遍基线,再跑8bit和4bit两个版本,在业务评测集上一字排开对比。数字骗不了人,量化好不好,跑完一轮就知道。