优化一:混合精度,好钢用在刀刃上优化二:两级分组 + 双重量化写在最后
想在自己的电脑上跑大模型,第一道坎就是显存。一个 7B 的模型原封不动塞进内存,十几个 G 起步,普通机器直接劝退。这时候 llama.cpp 就派上用场了——它靠一手量化优化,硬是把模型"瘦身"到能跑的程度。Ollama 这类工具之所以好用,底层站着的就是它。
量化原理本身不难理解,就是把模型里的浮点权重从 FP16 压到 INT4,用精度换体积。但 llama.cpp 的厉害之处在于,它不光会压,还压得有讲究。今天就把它的两个核心优化拆开看看:混合精度和双重量化。
llama.cpp 里的量化类型五花八门,有 I-Quants、K-Quants 两大类,K-Quants 下面又分 Q4_K_M、Q5_K_M 等等。挑个最有代表性的说,就是 Q4_K_M——用得最多,官方也默认推荐。
这三个字母各代表啥?Q4 表示用 4 位来量化权重,K 表示用的是 K-Quant 优化算法,M 则是"中等平衡"的意思。说白了,它是在精度和体积之间找了个性价比最高的档位。
大模型是一层一层摞起来的,Transformer 架构里,注意力层这种关键部分,重要性跟普通层不是一个量级。如果所有层统统用 INT4 一刀切,那就是吃大锅饭——不管重不重要,待遇一样。
混合精度的思路很简单:大部分层用 4 位,但给注意力层这类重要层的关键张量多分点精度,比如 5 位或 6 位。
有人可能要问,张量是啥?简单说,数值是标量,一维数组是向量,二维数组是矩阵,这些统称张量。模型权重本质上就是一堆张量,量化就是对它们逐块压缩。
这个策略翻译成人话就是:重要的地方多给点预算,不重要的地方能省则省。模型瘦了身,精度损失还控制在可接受范围内。
这部分才是真正的硬核操作。
量化不是把整个权重矩阵一股脑压成 INT4,而是分组进行的。llama.cpp 的做法是搞了两级分组:
![]()
第一级,把权重分成一个个超级块,每个超级块含 256 个权重参数。第二级,每个超级块内部再分成 8 个子块,每个子块 32 个权重参数。
为什么不直接按 32 个一组分一次就完事?这就得说到量化的"密钥"问题了。
量化本质上有点像加密:把 A 转成 B,用的时候再转回来。转回来靠的是啥?缩放因子(scale)和偏移量(min),这就是量化的"密钥",得跟着模型一起存。
算笔账就明白了:假设 512 个权重参数,按 32 个一组,一共 16 组。每组存两个 FP16 的密钥,光密钥就得 512 位。而所有权重按 INT4 量化,本身也就 512 位——好家伙,密钥的体积跟权重一样大,模型直接又胖回去了。
怎么办?聪明人一眼就看出路子了:把密钥也量化了呗。这就是双重量化——子块的密钥不直接用 FP16 存,而是压成 6-bit 整数。但问题来了:量化密钥也得有"密钥的密钥"才能还原,放哪?
放上一级。没有上一级?那就创造上一级——两级分组就是这么来的。
于是每个超级块额外存两个高精度 FP16 的"密钥的密钥",用来还原子块那些 6-bit 的密钥。再算一笔账:512 个权重,按 256 个一组分两个超级块,超级块存 2×2 个 FP16 共 64 位;16 个子块的密钥用 6-bit 存,6×2×16=192 位。加起来 256 位,对比一级分组 512 位的消耗,正好省一半。
子块分组小(32 个),量化粒度细,精度保住了;双重量化又把密钥的体积膨胀压了下去。这就是 llama.cpp 的平衡艺术——在精度和体积之间,抠出那个性价比的天花板。
回头看看,llama.cpp 的优化思路其实很朴素:不搞花活,就是算账。哪里重要就给哪里多投点精度,元数据太占地方就给它也瘦个身。整套设计环环相扣,不得不服。
你在本地部署大模型的时候用过 Q4_K_M 吗?还是喜欢别的量化档位?评论区聊聊你的实测体验。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.