我们衡量 LLM 压缩的方式可能错了

社区文章 发布于 2025 年 6 月 21 日

我们都在参加一场竞赛。一场将庞大的大型语言模型(LLM)缩小到可以在我们的笔记本电脑、手机,甚至有一天可能在我们的智能烤面包机上运行的竞赛。首选技术是什么?量化。将构成模型权重的那些笨重的 16 位浮点数,压缩到 8 位、4 位甚至 2 位。

社区在这方面已经做得非常出色。我们每周都会看到这样的头条新闻:“Mixtral 8x7B 以 4 位运行”、“Llama 3 70B 以 3 位运行”,然后我们都争相下载 GGUF 或 AWQ 版本。我们检查 MMLU 分数,发现它只下降了一两分,就称之为胜利。

但如果我告诉你,MMLU 分数背后隐藏着一个黑暗的秘密呢?如果我们衡量量化模型“好坏”的整个方法从根本上就是错误的呢?

让我们一起踏上一段小小的旅程。我们将从我们思考量化的标准方式开始,然后慢慢揭开层层面纱,以展示一种更细致、更强大,坦白说,也更*正确*的方法。

等等,稳定的准确率也可能是坏事?来认识一下“翻转”

让我们想象一下你是一名老师。你给你最优秀的学生“FP16-Model”一份有 100 道题的历史测验。他们答对了 90 道题。这是你的基准。

现在,你通过一个神秘的过程(量化)创建了这个学生的“克隆体”,名为“INT4-Model”。你给这个克隆体同样的测验。他们*也*得了 90/100。太棒了,对吧?这个克隆体同样聪明!

但当你仔细观察时,你将他们的答题卡并排比较,发现了一些令人不安的事情。

  • FP16-Model 答对的 5 道题,INT4-Model 答错了。
  • FP16-Model 答错的另外 5 道题,INT4-Model 凭着纯粹的运气或推理方式的改变,答对了。

最终分数完全相同,但学生的*知识*已经被悄悄地破坏了。行为发生了改变。这就是“翻转”背后的核心思想,这个术语在研究论文 **“你需要的不仅仅是准确率”** 中得到了精彩的阐述。

翻转是指模型对问题的答案在量化后从错误变为正确,或者更令人担忧地,从正确变为错误的任何情况。

这不仅仅是一个假设。看看论文中的数据。他们使用了一个 Llama2-13B 模型并开始对其进行压缩,同时测量 MMLU 准确率的下降和翻转的百分比。

image/png

看图的左侧。当他们丢弃网络的最后几层时(在 x 轴上从 0.0 移动到 0.1),蓝色的线“准确率差异”几乎没有移动。它保持在零附近。按照传统指标,这个模型是完美的!但看看红色的线,“翻转”。它立即跃升到超过 5%。这意味着每 20 个答案中就有 1 个发生了改变,即使最终得分保持不变。模型的行为已经开始出现显著的偏差。

我们量化的目标不仅仅是让模型在基准测试中获得高分。**我们的目标是创建一个与*原始*模型行为尽可能一致的较小版本。**我们希望保留其推理路径、安全训练和个性。高翻转率是一个危险信号,表明我们创造了一个科学怪人——它外表看起来一样,但内在却截然不同。

好吧,那我们该如何衡量这种损害呢?KL 散度登场。

“我明白了,”你可能会说。“翻转是坏事,准确率分数会骗人。那么,我们如何在不运行百万次基准测试的情况下衡量翻转的可能性呢?”

很长一段时间里,社区的答案是**困惑度(Perplexity,PPL)**。它衡量模型对一段文本序列的“惊讶”程度。它似乎是模型质量的一个不错的替代指标,所以它也应该是量化误差的一个好替代指标,对吧?

错了。对于这项任务来说,困惑度是一个出人意料的欺骗性指标。

想象一下原始模型正在预测“The cat sat on the ___”中的下一个词。它的输出概率分布可能如下:

  • 垫子: 40%
  • 地毯: 30%
  • 地板: 10%
  • ...(其他所有词的概率都非常低)

现在,看我们量化模型的预测:

  • 垫子: 35%
  • 地毯: 34%
  • 地板: 5%
  • 桌子: 4%
  • ...(其他概率发生了变化)

困惑度主要关心的是分配给*正确*词元(`mat`)的概率。它看到概率从 40% 降到了 35%——这是一个很小的下降,所以 PPL 的变化会很小。但看看全局!模型确定性的整体“形状”已经被扭曲了。困惑度通过只关注一个点,错过了这种几何上的变化。这就像只看左上角的像素来判断两张图片是否相同。

这就是 **Kullback-Leibler (KL) 散度**发挥作用的地方。

KLD 并不是一个新概念,但将其作为量化误差的黄金标准来应用,却是一项颠覆性的改变。KLD 衡量两个概率分布之间的“距离”。它不只看一个词元;它比较从原始模型到量化模型的*整个*概率向量。它会问:“当我们用量化分布来近似原始分布时,会损失多少信息?”

再次引用《你需要的不仅仅是准确率》这篇论文中的一个绝对关键的发现:**KL 散度与翻转高度相关。** 这就是我们的罗塞塔石碑。

image/png

看看这些图表。每个蓝点都是一个模型的不同压缩版本。X 轴是翻转的百分比。Y 轴是测得的 KL 散度。这种关系是不可否认的。这些点形成了一条清晰的上升直线。斯皮尔曼相关系数达到了惊人的 `0.96` 和 `0.97`!

这就是我们需要的证据。通过最小化原始模型和量化模型输出之间的 KLD,我们正在直接且可靠地最小化翻转的风险。我们现在有了一个敏感且理论上合理的指标来指导我们的整个量化策略。

那么,什么是明智的量化方式?

有了这个新目标(最小化翻转)和我们的北极星指标(最小化 KLD),我们的策略会如何改变?

当前流行的方法是*统一量化*:加载一个模型,选择一种格式(如 NF4),然后将其应用于网络中几乎所有的线性层。这种方法简单,但它是一个笨拙的工具。就像用大锤做手术一样。

关键的洞见是**并非所有层都是生而平等的。**

想想现代的混合专家(MoE)模型,比如 Mixtral 或 Grok。这些模型体量巨大,但方式很巧妙。对于每个词元,它们只使用其总参数的一小部分。它们的大部分体积来自于“专家”,这些专家本质上是庞大的前馈网络(FFN)。

这种架构给了我们一个独特的机会。如果我们不把所有东西都量化到 4 位呢?如果我们更有策略地处理这个问题呢?

  1. 高影响、低敏感度层: MoE 专家层是进行激进量化的完美候选者。它们占模型总参数的*巨大*百分比。将它们从 16 位量化到,比如说,2 位或 3 位,可以极大地减小模型大小。关键在于,因为任何单个专家只用于一小部分词元,所以对其进行重度量化所引入的误差通常会被网络的其余部分“淹没”或补偿。

  2. 低影响、高敏感度层: 现在,想想注意力机制——`Q`、`K` 和 `V` 投影。这些层用于*每一个词元*。它们是模型理解词元之间关系能力的中坚力量。它们极其敏感。即使将这些层量化到 4 位,引起的 KLD 飙升也可能是巨大的。

这就是权衡的体现:**我们在最不重要的地方(MoE 专家)牺牲精度,以保留在最重要的地方(注意力、嵌入层)的精度。**

付诸实践:智能量化蓝图

这不仅仅是理论。以下是你如何实际实现这种智能、选择性的量化方法:

  1. 分析你的模型: 不要猜测哪些层是敏感的,要去测量它。使用你的 FP16 模型和一个校准数据集(从多样化的语料库中选取几百个样本就足够了)。

    • 对于每一层(或每种类型的层),进行一次“模拟”量化。只量化*那一层*,然后测量最终输出 logits 与原始模型相比的平均 KL 散度。
    • 这会给你网络中每个部分的“敏感度得分”。你很可能会发现 `attention.q_proj` 的 KLD 敏感度比 `block_sparse_moe.experts.0.w1` 高得多。
  2. 设定你的比特预算: 决定你的目标最终模型大小。这就是你的“比特预算”。例如,你希望将 90GB 的 FP16 模型压缩到 25GB 左右。

  3. 智能分配比特: 现在,你需要解决一个优化问题。

    • MoE FFNs: 这些层显示出较低的 KLD 敏感度,但体积庞大。给它们分配最少的比特(例如,2.5 比特)。这能在减小尺寸方面给你带来最大的效益。
    • 注意力层(QKV/O): 这些层非常敏感。它们获得最多的比特。将它们保持在 6 位、8 位,甚至 bfloat16。它们不占用太多空间,所以保持它们高精度的“成本”很低。
    • 其他层: 填补中间部分。也许 MLP 的 `gate` 和 `down_proj` 层可以处理 4 位,而嵌入层需要 8 位。你的分析数据将指导你做出决定。

结果是一个混合、混合精度的模型,它被智能地压缩了。它比原始模型小得多,但通过保留网络中最敏感的部分,它具有比同样大小的统一量化模型低得多的 KLD,因此翻转率也低得多。

是时候用不同的方式来处理量化了

一刀切的量化时代即将结束。随着模型变得越来越复杂,我们对它们既要强大又要易于访问的需求日益增长,我们的压缩技术也必须随之进化。

  1. 超越基准测试: 停止仅仅依赖 MMLU。开始测量**翻转**,以了解你是否保留了模型的真实行为。
  2. 使用 KL 散度: 将平均 KLD 作为量化误差的基准指标。正如我们所见,它比困惑度更可靠,是翻转的一个极佳的代理指标。
  3. 智能量化,而非粗暴量化: 分析你的模型。对大型、鲁棒的组件(如 MoE 专家)应用激进的低比特量化,并用更高的精度保护脆弱、关键的层(如注意力层)。

这就是我们如何精巧地处理问题,构建出的模型不仅更小,而且更忠实于它们所源自的原始巨型模型。

社区

非常喜欢这篇博客❤️,感谢分享😄

非常感谢这篇精彩的文章!
用非常简单的方式记下了所有概念!
但我有一个问题,或者说是一个类比想请教 -

当我们谈论 KLD 时,我们当然是检查整个分布,而不是向量之间的某种距离之类的,
当我们说到前向 KLD 时,模式/峰值覆盖行为就凸显出来了。那么在量化时,当你说我们保留量化模型像原始模型一样时,我们是在遵循那种模式覆盖行为吗?
images (5).png

·
文章作者

感谢您的美言,真的很高兴您喜欢这篇文章!

我们通常计算**前向 KL**
**KL(P‖Q)**,其中 **P** 是原始(全精度)模型的输出分布,而 **Q** 是量化模型的输出分布。

这种前向方向确实强调了*模式覆盖*——它惩罚量化模型对原始模型认为可能的词元分配过少概率的情况。所以是的,如果 Q 将其概率分布得更广,它会更宽容,但如果它“错过”了 P 的关键峰值,它就会惩罚 Q。

所以回到你的类比:**是的**,当我说保留原始模型的行为时,我*确实*倾向于这种“模式覆盖”的视角。我们的想法是,我们希望量化模型对与原始模型相同的可能输出保持关注。如果它偏离太远——比如说,忽略了全精度模型偏好的一个高置信度词元——那么前向 KL 就会捕捉到这一点(这也是翻转更可能出现的地方)。

一个提醒:反向 KL(KL(Q‖P))的行为会非常不同——它惩罚量化模型中原始模型没有的过度自信,这在某些情况下也可能有用,但在 P 分配低概率时,它在实践中通常不太稳定。

非常感谢你用如此详尽且易于理解的语言解释了所有概念!

太喜欢了!❤️

我有一个高度实验性的概念,用于存储 1.58-2 比特的数据,使其占用空间接近 1.3 比特。但它很可能需要在加载时解码回完整的 2 比特。

尽管它将一个 6 比特块的组合减少到仅 4 比特(*具体来说是 15/64 的组合*),并且在量化过程中,需要智能地决定是否应该微调一个值以略微提高/降低它。15^11(*为了减少一个比特*)将占用 43 比特,或者每个值仅为 1.30_ 比特,取值范围从 -1 到 2,而不是 66 比特。否则它将以 4 比特存储 6 比特的数据。(*所有这些都严重依赖于平均预期值和有限的开启比特数...*)

当您高于 3 时,它会更接近 1.58 的存储空间,但保留了更多 2 比特的值。11/66 的开启比特将占用 40 比特,而 22/66 的开启比特将占用 57/66(*每个值高达 1.72 比特,同时可能保留大部分 2 比特的值*)。

特别针对 2 比特,使用 16/64 将导致 49/64 比特(*每个约 1.53 比特*)

如果允许对量化值进行轻微调整,我可以详细解释编码的工作原理。虽然它有点数学密集,但可以用简单的算术解码。

注册登录 发表评论