第一次把一个大模型压到 4-bit 时,我注意到的不是推理速度的提升,而是量化损伤的表现方式。输出行为出现了微妙的偏差:同一道逻辑题能解,同一个知识问答却开始一本正经地给出错误答案;困惑度只涨了一点点,某些能力却断崖式下跌。后来把每一层单独降精度做对照才发现,这种损伤并不是均匀分布在所有参数上的,而是集中在少数敏感位置。标题里那句“Why the Next Bit Should Be Spent Globally”想说的正是这个:决定下一个比特花在哪里,不该只盯着某张权重表自身的统计量,要看它对最终输出的伤害放大效应。
这是全文的核心判断:量化损伤有结构,比特分配是一个全局预算问题,不是局部压缩问题。明白这一点,你才不会在量化部署时做反了方向的优化。
1. 先接受一个反直觉的事实:量化损伤不是均匀的
很多人的第一直觉是:量化约等于有损压缩,每个参数都丢一点精度,误差像噪声一样均匀撒开,模型最终表现也应该均匀地下降一点。这个直觉只在很小的局部成立,放到整个模型上基本是错的。
只要动手做过逐层实验,很快就会看到另一幅图景:某些层被砍到 4-bit 后,模型的输出几乎无变化;另一些层从 8-bit 降到 7-bit,任务指标就已经明显下滑。举例来说,很多人在逐层实验里会观察到,attention 的 Q 投影和 KV 投影对精度下降的容忍度并不一样,单独降其中一个,输出看起来还能接受,两个一起降,配合某些上下文长度时,生成稳定性就会明显变差。这种差异不是来自计算误差大小的不同,而是来自这些模块在信息流里的位置不同。
同一个模型内部,不同位置的“耐伤能力”可以差出好几个量级。这不是神秘现象,而是模型自身的结构决定的。也正是因为这样,量化损伤才有资格被称作“有结构”——它像真实世界的创伤一样,有位置、有深度、有传播路径,而不是均匀弥漫的噪声。
这个事实直接决定了你后续所有的策略选择。如果损伤是均匀的,那么最简单的 uniform quantization 就已经足够——反正处处都一样,松紧都无所谓。正因为损伤是有结构的,讨论“比特应该花在哪里”才有了意义。对普通使用者来说,这意味着“能跑 4-bit”不等于“每个 4-bit 一样能用”;对部署者来说,这意味着选择量化方案之前,先要搞清楚伤害最重的位置在哪。
实际操作中,我建议把“量化能做吗”和“量化之后哪些能力变了”分开看。前者是工程问题,后者才是这篇内容真正关心的核心问题。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 损伤的结构从哪里来:三个叠加因素
2.1 激活离群特征:少数通道承载了大部分语义
关于 LLM 量化损伤,被反复验证的第一个观察是:激活值存在明显的离群通道。模型某些特征维度的数值会远高于其他维度,这些维度在语义上也往往更关键。它们经过注意力计算和 FFN 之后,会影响后续大量 token 的生成,属于整个模型信息流里的“主干道”。
如果量化时没有对离群通道做特殊处理,最常见的后果是截断误差:为了迁就绝大多数普通数据而设置一个窄小的量化范围,会直接把这些大数值通道的细节削平。细节一旦削平,对应语义特征的区分度就消失了,模型输出的质量就会整体劣化。
一个容易理解的类比是图像压缩:一幅图大部分区域可以放心压缩,但少数承载轮廓和对比度的边缘区域如果失真,整张图的可辨识度会明显下降。离群激活通道就是大模型里的那些“轮廓线”。这也等价于说,仅仅看数值大小还不够,还要看这些通道在后缀计算里被放大了多少倍。
2.2 权重敏感度:大参数不等于重要参数
只看权重幅值做判断,是新手最常犯的错误。直觉上我们会觉得大权重容不得误差,小权重随便丢。但最优脑手术(OBS)这类经典方法早就指出,一个权重被扰动后造成的损失变化,更多取决于损失表面对它所在方向的曲率,而不只是它本身的数值大小。
也就是说,有些权重看起来很小,却恰好位于损失函数的陡峭区域,动它一点,最终 loss 就明显上升;而有些大权重位于平缓区域,误差带来的损失增量反而很小。量化时如果只按幅值分配精度,就很容易把宝贵的比特花在不敏感的大权重上,却忽视了那些真正被激活放大的小权重。
在常见开源模型的逐层敏感度分析里,我通常看到注意力投影层和部分 FFN 层比 embedding 更敏感。但这在不同模型、不同任务上会有差异,不要把它当作固定结论。正确的做法是自己对部署的模型做一次敏感性定位,而不是直接套别人的结论。
2.3 层间放大与误差累积:局部小伤会变成全局灾难
前两个因素描述的是“单个张量内部的不均匀”,第三个因素要提醒你:损伤还会跨层传播。某一层的输出会成为后续很多层的输入,一层引入的小误差经过残差连接、归一化和非线性变换后,可能被抑制,也可能被不断放大。
这带来的直接影响是:即便你单独看每一层,都发现量化误差不大,组合之后的任务表现却可能崩坏。反过来也是同样的道理——有些位置单独看损失很大,但因为后续结构有很强的鲁棒性,最终影响反而有限。也就是说,损伤是一种系统涌现属性,不是单个张量的局部属性。
理解了这一点,就会明白为什么“逐层单独优化”并不等于“全局最优”。每一层都在降低自己的重构误差,看起来没问题,但层与层之间的交互效应是局部视角完全看不到的。“全局分配”正是冲着这一层去的。
3. 从“局部最优”走向“全局比特分配”
3.1 为什么逐张量和逐通道量化只解决了一半问题
逐张量量化为整个权重或激活张量设定一个 scale 和 zero-point,目标是最小化这个张量内部的重构误差;逐通道量化把 scale 按通道拆开,让离群通道不至于被截断得那么惨。这两种做法都能显著改善量化质量,但它们优化的对象仍然只是“当前这个张量的输出误差”。
问题在于,模型最终的任务损失并不等于各层重构误差的简单加和。某层的输出误差虽然很小,但可能正好作用在关键语义通道上,随后被放大;另一层的输出误差虽然相对大,却落在冗余通道上,整体影响微乎其微。逐通道量化不知道这些信息,所以它永远停留在局部最优。
把逐通道量化当成基线是合理的,但如果你把模型压到 4-bit 以下,或者目标任务是长文本生成这类对细节敏感的场景,就一定要把视角切换到全局。性能上限的差距,主要来自“有没有把误差放到整个模型的影响面上去评价”。
3.2 把比特当成预算:边际收益决定分配优先级
“下一比特应该花在全球范围内”,本质上是把模型的比特总量看成一个预算,目标是在给定预算下让最终任务损失最小。这里的关键不是看谁“贵”,而是看增加一单位投入时,谁的产出增量最高——也就是边际收益。
打个比方:一个团队要花一笔培训预算,正确的做法不是把钱平均分给每个人,也不是投给技能最差的人,而是评估“给这个人再加一小时培训,能多提升多少产出”。比特分配的底层逻辑完全一样:把第 N 个比特给 layer A,能降低多少最终损失;给 layer B,又能降低多少。应该优先把它给边际收益更高的那一个。
这套思路落到实现上,需要全模型级别的敏感度信号。常见来源有三个:一是梯度,代表输出对参数变化的敏感程度;二是二阶信息,比如对角 Hessian,代表损失景观的陡峭程度;三是激活统计,用来标识哪些通道会在推理时被放大。把统一信号按模块聚合后排序,就能得到一张“先降谁、后降谁、坚决不降谁”的优先级表。
3.3 现有主流方法其实都在做同一件事
这几年常见的后训练量化方案,表面看是不同流派,底层其实都在朝同一个方向走:不再把量化当成每层独立的压缩问题,而是把误差放在整个模型的敏感结构里去评价。
GPTQ 使用 Hessian 信息做逐层误差补偿,本质上是把“哪个方向容不得误差”纳入考虑,而不是只看参数大小。AWQ 用激活统计给关键权重通道加权,明确地把“重要性”从权重本身的幅值,改成了“被激活放大后的影响”。LLM.int8 把离群通道分离出来,让它们继续保留高精度,其余通道才走低精度量化。SmoothQuant 则调整权重和激活之间的数值分布,把量化难度从尖峰明显的激活迁移到更容易压的权重,再配合均衡策略。
这些方法各有侧重,但共同点已经很清楚:局部统计量只是起点,最终决定方案质量的是它对全局输出的影响。需要说明的是,它们都是工程上的近似,并不是严格意义上的全局最优。真正的全局分配还要面对推理引擎支持、kernel 兼容性、通信带宽等现实约束,这也是后面要单独讨论的部分。
4. 一个可落地的损伤评估与比特分配流程
4.1 先把“损伤”的定义说清楚
如果把损伤定义成“困惑度上升”,那评估门槛会比实际情况低很多。困惑度是一个平均量,它可以把少数 token 上的灾难性错误稀释掉。我见过不止一次这样的情况:模型 4-bit 量化后困惑度只涨了 0.2,但在具体任务上犯错的模式已经明显变差。
更稳妥的定义是“一组有区分度的指标集合”。建议至少包含三块:困惑度作为整体基线、2 到 3 个针对性较强的下游任务(比如指令跟随、知识问答、代码生成)、以及同一 prompt 下多次生成的输出稳定性。没有哪个单一指标能代表全部,所以一开始就要把口径搭宽。
4.2 三步定位敏感模块
定位敏感模块,推荐按下面的顺序走。
第一步,单点降精度实验。逐个模块做“只把这个模块降到 4-bit,其余保持 8-bit”的对照测试,记录每个模块单独造成的指标下降。这个实验成本高,但信息量也高,能直接看出哪些模块是重灾区。
第二步,用敏感度信号排序。收集一小批校准数据,计算各层输出对最终 loss 的梯度或近似曲率,把所有模块按敏感度从高到低排列。这一步可以用现成的量化工具库完成,不需要自己写底层实现。
第三步,组合验证。单点实验遗漏了交互效应,所以对前两步选出的“高风险模块”做几次两两组合测试,确认这些模块同时降精度时不会出现超预期的叠加崩坏。
如果模型规模很大,单点实验跑不动,可以退而求其次:先只测因果注意力投影和 FFN 的 down/up 投影这几类常见敏感区域,抓到主要矛盾后再决定要不要细化。
4.3 按边际收益分配比特,并验证收益
拿到敏感度排序后,分配动作本身很简单:高风险模块保持 8-bit,或者使用更细的 group size;低风险模块降到 4-bit 甚至 3-bit。关键是验证环节,你需要回答一个朴素的问题:花出去的比特,到底换回来了多少指标收益?
推荐做三组对照:均匀 8-bit、均匀 4-bit、以及按敏感度分配后的混合精度。对比三组在同一套指标集合上的表现,同时记录显存占用和推理吞吐。如果混合精度相比均匀 4-bit 只多花了 10% 的内存,却换回了 80% 的能力恢复,那这次“全局分配”就是值得的;如果收益微乎其微,说明你的模型本来就很均匀,不需要为它设计复杂的分配方案。
下面是一个混合精度分配结果的示例结构,不代表某个真实工具的配置格式:
json复制{
"bit_allocation": {
"layer.0.attn.q_proj": 8,
"layer.0.attn.o_proj": 8,
"layer.0.mlp.down_proj": 4,
"layer.1.attn.q_proj": 4,
"layer.1.mlp.down_proj": 8
},
"group_size": 128,
"calibration_set": "task_mixed_sample_v3"
}
4.4 落地时的参数经验与后端约束
关于参数,几个常见经验可以先记下。group size 128 是很多方案的默认值;如果目标指标对细节非常敏感,可以改成 64,但显存和带宽占用会上升。校准集建议几百条到几千条,数量太少会过拟合到校准分布;数量太多则评估成本高,收益递减。校准数据最好来自你实际部署时最可能出现的任务分布,而不是随便选一份通用语料。
此处最容易被低估的是后端约束。推理引擎、kernel 库或者部署框架不一定支持任意层级的混合精度。分配做得再精细,如果后端根本不认这种配置,结果只能在导出阶段被强行改回统一精度。所以分配比特之前,先查三件事:引擎支持哪些量化精度、是否支持逐层覆盖、导出格式是否保留混合精度信息。
把这些搞清楚,流程才算真正闭环:先体检,再定位,再分配,最后验证,而不是跳到最后一步直接压比特数。
5. 最容易误判的四个环节与排查路径
5.1 只看困惑度,把均值当全部
现象:量化后困惑度看着很漂亮,直接上线。等用户反馈变差才发现,问题集中在某些特定类型的长尾输出上。排查顺序是:先把困惑度按 token 或按样本拆分,看是不是有一小块区域的 loss 明显放大;再对比量化前后这些区域的输出样本,确认是不是结构性的语义变化。均值指标只能筛掉明显错乱的模型,筛不掉局部灾难。
5.2 只测单任务,换分布就翻车
现象:在某个评测集上指标几乎不掉,换个领域任务就崩。原因很可能是你的敏感度排序依赖了测试任务的分布。不同任务激活的通道和层不同,损伤重灾区自然也不同。排查时不要只做单任务验证,至少准备三个分布差异较大的任务指标,让敏感度排序在多套口径下都保持稳定,再开始分配比特。
5.3 校准集和推理分布不一致
现象:校准阶段指标正常,真实线上表现很差。这一般不是量化方法本身的问题,而是校准数据来源和部署场景错位。排查链路是:先确认线上样本的输入分布,再对比校准集里的文本类型、长度、语言和任务占比,最后重新收集与线上更接近的数据做校准。校准集不是越多越好,而是越像越好。
5.4 后端不支持你分配出来的混合精度
现象:导出时报错,或者导出的模型被自动转回统一精度,所有分配努力失效。排查链路是:先看推理引擎支持哪些 bit 宽度,再看导出格式是否保留逐层精度信息,最后用后端提供的 profiling 工具确认实际生效的精度。这类问题往往在工程上比量化误差本身更费时间,所以越早排查越好。
这四类误判有一个共同特征:你看到的“量化效果”不是量化方案真实能力的反映,而是评估口径或者后端支持的假象。评估口径不对,方案再好也会被误判;后端支持不对,分配再好也落不了地。
6. 这一判断对部署实践意味着什么
把故事再拉回到开头。第一次做 4-bit 量化时,我以为是“整体性能均匀下降”,后来才发现是“某些关键位置受伤”。这个视角的转变,才是量化部署里真正值钱的经验:量化不是一个压缩问题,而是一个预算分配问题。你的比特就这么多,怎么花,取决于它们在哪里能换回最多的模型能力。
对普通开发者来说,这个判断意味着两件事。第一,当模型量化后某些任务崩掉时,不要急着换量化方法,先做一次损伤体检,找到重灾区,再去选方案。第二,看量化工具的说明时,不要只看它能压到几比特,要看它如何处理离群通道、如何衡量敏感度、是否支持细粒度的逐层精度控制。
对更长期的方向来说,我倾向于认为,量化技术的下一次进步,不会来自把统一精度再压低一个比特,而来自把精度选择的粒度变得更细、更智能:针对不同模块、不同任务、甚至不同输入动态分配比特。全局比特分配这套思路,会是后续很多工具的共同底色。
下一个比特应该花在全球范围内。这句话的实操版本是:先找到你的模型哪里最怕受伤,然后把仅剩的精度预算,果断集中到那里。
