K-quants 把说明书也量化之后,一个 160 亿参数的模型,量化常量从约 2 GB 砍到了约 1 GB。
但事情还没完。面前还有两个问题。
第一个:到目前为止,量化都是一对一的——一个权重对应一个整数编码。这叫标量量化。能不能一次处理一组权重?8 个权重打包,共享一个编码。
第二个:前面不管是 legacy 还是 K-quants,所有 block 一视同仁。但有些权重改一点点,输出就天翻地覆;有些改得面目全非,模型几乎不受影响。能不能让重要的权重分到更宽的桶?
这两个问题的答案,就是 I-quants 和重要性矩阵。它们是同一时期引入的,概念上独立,但经常一起出现。下载页里的 IQ2、IQ3,那个 I 指的就是"importance"。
八个打包,挑一个
前两篇里的量化是标量级别的。一个权重 → 一个 INT4 整数。一对一。
向量量化把 8 个权重编成一组,看作一个 8 维向量。不给每个权重单独找桶,而是给这整组向量找一个"最像的参考向量"。参考向量的编号就是编码。
想象一个极简版:把维度降到 2,密码本缩小到 4 个参考向量:
$$ \text{codebook} = \{(1, 0),\ (0, 1),\ (1, 1),\ (0.5, 1.5)\} $$现在有一个权重向量 $\mathbf{w} = [-0.8,\ 1.2]$。找最近邻:
第一步,取绝对值:$|\mathbf{w}| = [0.8,\ 1.2]$。为什么取绝对值?密码本里全是正向量——这能省一半空间。正负号另外存。
第二步,算到四个参考向量的距离。$(0.5, 1.5)$ 最近(你可以心算一下欧氏距离验证)。密码本编号 = 3(从 0 开始)。
第三步,还原长度。scale $S$ 是原始向量的模除以参考向量的模:
$$ S = \frac{\|\mathbf{w}\|}{\|\mathbf{r}\|} = \frac{\sqrt{0.8^2 + 1.2^2}}{\sqrt{0.5^2 + 1.5^2}} = \frac{\sqrt{2.08}}{\sqrt{2.5}} = \frac{1.442}{1.581} \approx 0.912 $$第四步,存符号。$\mathbf{w}$ 的第一维是负、第二维是正 → 符号字节 = 0b01(或者说 $0 \times 2^0 + 1 \times 2^1 = 2$,怎么编码都行,细节不重要)。
还原时用 $S \times$ 参考向量,再乘回符号:
$$ \tilde{\mathbf{w}} = S \times \mathbf{r} \times \text{signs} = 0.912 \times (0.5, 1.5) \times (-1, +1) = (-0.456,\ 1.368) $$误差 = $(-0.344,\ 0.168)$。不小。但别忘了这是在 2 维、4 个参考向量的极端简化下。GGUF 实际用的是 8 维、256 个参考向量,加上符号字节让有效数量膨胀到 $256 \times 2^8 = 65536$——精度远高于这个玩具例子。
回到实际的存储计算。一个 8 权重向量用 IQ2 量化:
| 项目 | 大小 |
|---|---|
| 符号字节 | 8 bit |
| 密码本编号(256 选 1) | 8 bit |
| scale S(FP16,256 向量共享) | $16 / 256 = 0.0625$ bit |
对比 legacy Q4_0 的 4.5 bpw 和 K-quant Q4_K 的约 4.3 bpw,压缩率直接翻了一倍。一个 160 亿参数的模型:Q4_0 约 9 GB,Q4_K 约 8.6 GB,IQ2 约 4 GB。
4 GB。刚好塞进一张 8 GB 显卡,还有充裕的空间给 KV cache。
代价也明显。标量量化丢的是每个权重的尾数,向量量化连"方向"都丢了。8 个权重之间的比例关系消失了——只能还原整体长度。这也是为什么 IQ2 的困惑度通常比 Q4_K 差一截。不是在同一个赛道上比的——标量 4 bit vs 向量 2 bit,差了整整一倍的基础精度。
密码本里存的 256 个参考向量来自哪里?代码里直接硬编码的,没有训练过程(有个 PR 引用了 E8 晶格的论文,但实际代码似乎没用)。8 维空间的 256 个方向——大概是通过某种均匀采样选的。Kawrakow 的原话引用了 QuIP# 论文作为灵感来源,但细节只有代码知道。
重要的人坐前排
向量量化解决的是"怎么组织桶"。重要性矩阵解决的是"桶分给谁"。
核心洞察很简单:不是所有权重都平等。
考虑一个权重矩阵 $W$,输入激活 $x$,输出 $y = Wx$。如果某个权重 $w_{ij}$ 改变了一个很小的量,输出 $y_i$ 却变化很大——这个权重是"重要的"。反过来,改完跟没改一样——不重要。
GGUF 用激活值的平方来量化这个观念。跑一次校准数据集的推理,拿到每一层输出激活 $y$:
$$ I_i = y_i^2 $$$I_i$ 越大的行,说明这行权重对输出有更大影响力。再叠加上权重本身的大小:
$$ I_{ij} = y_i^2 + \sqrt{\sigma^2 + w_{ij}^2} $$$\sigma$ 是这一行的权重标准差——防止 $w_{ij}$ 恰好为零时整项消失,纯工程细节。
有了重要性矩阵,量化的逻辑多了一步。之前我们用一个 scale $S$ 和零点 $Z$ 做完量化和反量化,所有 block 平等对待。现在反量化引入一套独立的参数 $S'$ 和 $Z'$,专门服务重要的权重。
目标是让重要权重的重建误差尽可能小,不重要的可以大一些:
$$ L = \sum_i \sum_j I_{ij} \cdot (w_{ij} - \tilde{w}_{ij})^2 $$不重要权重的 $I_{ij}$ 小 → 误差被打了折扣。重要权重的 $I_{ij}$ 大 → 误差被放大,优化器会优先照顾它们。
固定 $S$ 和 $Z$(还是按之前的方式从区间极值算),$S'$ 和 $Z'$ 有闭式解——一个带权最小二乘问题。GGUF 还多做了一步:在 $S$ 附近扫 36 个候选值,挑让加权损失最小的那个。大一点的 $S$ 意味着 clip 掉更多极端值,把精度倾斜给靠近零的权重——这些往往数量多,量化后整体误差更容易控制。
整个过程不增加任何推理开销。重要性矩阵只在量化时多算了几步,最终的 GGUF 文件里只多存了一组更"聪明"的 $S'$ 和 $Z'$,不存额外数据。从文件外部完全看不出一个模型有没有用过重要性矩阵(GitHub 上有人为此很抓狂——没法追溯一个 GGUF 文件到底是怎么量化的)。
实际效果:同样的 Q4_K_M,加上重要性矩阵后困惑度能降低 10-30%。低 bit 场景下改善明显——IQ2 这种极端压缩,没有重要性矩阵几乎没法用。
校准数据集通常用 Wikipedia 的几百条文本。有人担心过拟合——模型会不会变成 Wiki 专家?作者认为不太可能,但最稳妥的做法是用跟你的场景接近的数据做校准。写代码的用代码数据集,做法律的用法律文本。
最后那排名字
回到第一篇开头让我愣住的那一排名字。Q4_0、Q4_K_M、Q5_1、IQ2、IQ3。
现在能翻译了。
Q 后面的数字是基础 bit 数。下划线后面的内容告诉你方案类型:
_0 和 _1:legacy 对称/非对称量化。桶少,说明书大,朴素但可靠。
_K:K-quant。套娃压缩了说明书,super-block 让内存访问更连续。后缀 S/M/L 决定敏感层的保护力度——S 省空间但激进,M 折中(大多数人的选择),L 保守。
IQ:I-quant。向量量化,8 个权重打包匹配密码本。bit 数是约数——IQ2 约 2 bpw,IQ3 约 3 bpw,IQ4 约 4 bpw。后缀同样控制混合精度策略。
我之前觉得这一排名字是密码。现在看,它确实是一套密码——只是加密算法不难。双字母体系:Q 开头是标量量化,IQ 开头是向量量化。数字是基础 bit,下划线后面是具体的压缩策略和敏感层分配。
选择模型的过程,就是一个权衡三角形:
Q8_0 → 几乎无损,但文件跟 FP16 差不了多少。跑不起就别想。
Q4_K_M → 多数人的答案。4 bit 基础配 K-quant 的说明书压缩,M 档给关键层留余量。
IQ2 → 最小、最快、最笨。显存实在不够时的最后退路。
尽头
这趟从 legacy 走到 I-quants,本质上是一个不断追问"还能省哪里"的过程。
先省权重:FP16 → INT4,16 bit 砍到 4 bit。
再省说明书:FP16 → INT8 scale,每 block 省 6 bit。
然后省桶的组织方式:标量 → 向量,8 个权重共享一个编码。
最后省桶的分配:不重要权重的误差打个折,把精度留给关键层。
每一步都在多丢一点信息。丢到 IQ2 的时候,丢失的已经不单是每个权重的尾数了,连权重之间的比例关系都消失了。
量化不是魔术。它只是在告诉你:你愿意用多少精度,换多大的模型。
diet 没有尽头。尽头是你的显存。