前面的 L06 和 L12 已经讲透了量化的"原理"——为什么几个比特就能近似一个浮点数、各种格式的字节又是怎么排布的。这一课换个角度,讲"怎么用工具真把模型压小":一行 llama-quantize 命令,就能把一个十几 GB 的 fp16 模型变成三五 GB 的 Q4_K_M;再配上 imatrix(重要性矩阵),同样的比特数还能把掉下去的质量再拉回来一截。
换句话说,L06/L12 是"懂原理",这一课是"会操作":知道每个旗标在调什么、不同档位是怎么取舍体积与质量的、以及 imatrix 这把"质量回血"的钥匙到底怎么用。量化是让大模型能在普通显卡、甚至纯 CPU 上跑起来的关键一步,而这一课就是教你亲手把它完成。
这一课的两个主角是 tools/quantize(压缩工具本体)和 tools/imatrix(生成重要性矩阵的配套工具)。我们先看怎么用 quantize 一键压缩、它背后调的是哪个公共 API,再看 imatrix 凭什么能在不加比特的前提下把质量做得更好。
最常见的用法只有一行:llama-quantize in.gguf out.gguf Q4_K_M——输入一个 fp16/fp32 的 GGUF,指定一个目标档位(这里是 Q4_K_M),它就吐出一个压缩好的小 GGUF。入口在 tools/quantize/main.cpp(很薄),主体逻辑在 quantize.cpp,而真正干活的是它调用的公共 API llama_model_quantize(in, out, ¶ms)——注意这是 L25 那套 llama.h 里的函数,所以量化能力对外也是开放的,并不只有命令行能用,你完全可以在自己的程序里调它。
// 量化工具的核心: 一行命令背后调的公共 API (简化自 tools/quantize/quantize.cpp) llama_model_quantize_params params = llama_model_quantize_default_params(); params.ftype = LLAMA_FTYPE_MOSTLY_Q4_K_M; // 目标档位 params.imatrix = imatrix_data; // 可选: 喂入重要性矩阵 params.dry_run = false; // true 则只算体积, 不真压 llama_model_quantize("in.gguf", "out.gguf", ¶ms);
那个 params(llama_model_quantize_params)藏着不少实用旋钮:ftype 选目标档位;dry_run 设成 true 就只试算压缩后多大、并不真的压(选档位时特别省事);output_tensor_type / token_embedding_type 能给个别关键张量单独定一个更高的精度;keep_split 保持分片结构。换句话说,量化不是"一刀切到底",而是可以精细到每一类张量、甚至每一层的。
那么"档位"到底是什么?它就是一个 llama_ftype 枚举值,对应一种"平均每个权重用几个比特"(bpw)的方案。quantize.cpp 里有一张表,把每个档位的名字、bpw、以及实测的体积/困惑度代价列在一起。下面挑几个有代表性的档位,看它们在"体积"和"质量"之间各站在哪:
几乎无损,体积大;适合对质量极敏感、显存又够的场景。
社区最常用的"甜点档":体积小一大半,质量损失很小,日常首选。
超低比特、极致省显存;靠 imatrix 撑质量,否则会明显变差。
挑档位的直觉和 L06 一脉相承:bpw 越低,模型越小、跑得越省,但精度损失越大,困惑度(ppl,下一课讲)越高。大多数人会落在 Q4_K_M 这类"甜点档"上——体积已经小到能塞进消费级显卡,质量却几乎看不出退步。只有当显存特别紧张时,才会往 IQ2 这种超低比特走,而那时 imatrix 就成了救命稻草。所以"挑档位"从来不是挑最小的,而是在你的显存预算下,挑那个质量还撑得住的最小档。
这里有个朴素但关键的观察:不是所有权重都一样重要。有些权重在模型干活时几乎总被强烈激活、对输出影响很大;有些则常年"打酱油"。如果量化时一视同仁地给所有权重同样的精度,就太浪费了——重要的权重精度不够会明显伤质量,而给不重要的权重留高精度又是白费比特。imatrix(importance matrix,重要性矩阵)就是来解决这个"比特预算怎么分"的问题的。打个比方,这就像考试时间有限:与其每道题都花同样多时间,不如把时间多花在分值高的大题上、小题快速带过——总分自然更高。imatrix 干的就是给权重"按分值分配精度"的活儿:先搞清楚哪些权重是"大题",再把宝贵的比特预算重点投给它们。没有这份"分值表",量化就只能盲目地一视同仁,难免把精度浪费在无关紧要的地方。
怎么知道哪些权重重要?办法很直接:拿一批校准文本(calibration text,几百段有代表性的语料)真的跑一遍模型,在前向过程中用一个 eval-callback 钩子 collect_imatrix 把每个权重张量每一列的激活幅度累加起来(源码里存成 Stats 的 values / counts)。被激活得越多越强的列,就越"重要"。跑完后,这些统计被存成一个 imatrix.gguf 文件,等量化时再喂回去。
# 第一步: 用校准文本生成重要性矩阵 (tools/imatrix) llama-imatrix -m model.gguf -f calib.txt -o imatrix.gguf # 内部: 前向时 collect_imatrix(t, ...) 累计每个权重张量每列的激活幅度 # 第二步: 量化时把它喂进去, 精度优先留给重要的列 llama-quantize --imatrix imatrix.gguf in.gguf out.gguf IQ2_XS
有了这份重要性清单,量化时就能因材施教:在同样的比特预算下,给重要的权重列分配更准的量化(让它们舍入误差更小),把不可避免的误差更多地推给那些"无关紧要"的列。下面用一个最小例子,看一行权重在 imatrix 加权下是怎么被量化的:
道理其实一句话就能说清:同样的比特,花在刀刃上。普通量化把误差均匀摊给所有权重;imatrix 量化则让重要的权重几乎不损失精度,把误差集中倒给那些本来就影响不大的权重。结果就是:在完全相同的体积(比特数)下,模型整体的困惑度(ppl)更低、表现更接近原始的 fp16。比特数没变,质量却回来了一截——这就是 imatrix 的魔力,也是"测量一下再优化"这种笨功夫换来的实在好处。更妙的是,这一切对使用者完全透明:你下载一个带 imatrix 的量化模型,加载、推理的代码一行都不用改,质量却凭空好了一截——所有的聪明都发生在"压缩那一刻",用的时候只管享受成果。
讲了这么多档位,到底该给自己选哪个?一个实用的决策顺序是:先看显存。把"模型大小"粗略估成"参数量 × bpw / 8",再对照你显卡的显存——能宽裕放下的,就尽量选高一点的档位(质量更好);放不下的,才往下压。比如一个 8B 模型,Q8_0 约 8GB、Q4_K_M 约 4.5GB、IQ2 约 2.5GB,你的卡有多大,基本就框定了可选的范围。
在显存允许的范围内,再看用途。要它写代码、做推理这种"差一点就错"的任务,质量优先,尽量别低于 Q4_K_M;只是闲聊、续写这种容错高的场景,往低压一两档通常也无伤大雅。还有个常被忽略的点:同样大小,宁可选更大模型的低档量化,也别选小模型的高档——一个 13B 的 Q4 往往比一个 7B 的 Q8 更聪明,哪怕它俩体积差不多。这是社区反复验证过的经验法则。
最后,只要往超低比特(IQ2、IQ3)走,就一定优先选带 imatrix 的版本;普通 Q4/Q5 这类中高档,带不带 imatrix 差别没那么大,但带上通常也只赚不亏。把"显存框范围、用途定底线、超低比特认 imatrix"这三步记住,你就能在满屏的量化文件名里快速锁定最适合自己的那一个。
最后两个折叠,补两个动手时一定会撞上的实际问题:那些古怪的档位名到底怎么读,以及除了选档位还有哪些实用旗标。
档位名是有规律的。Q4_0 里的 Q 是 quantize、4 是每权重约 4 比特、0 是早期的简单方案。Q4_K_M 里多出的 K 表示这是"K-quant"(一种更聪明的分块量化,质量更好),M 是 medium(中等档,另有 S=small、L=large 微调体积)。而 IQ2_XS 里的 IQ 表示"带 imatrix 的超低比特"方案,2 是约 2 比特,XS 是 extra small。一句话速记:Q=基础、K=更聪明的分块、IQ=超低比特靠 imatrix、后缀 S/M/L=同档里的大小微调。看懂命名,你就能从一长串文件名里一眼挑出想要的那个,不必每个都去试。
最常用的是 --dry-run(对应 params.dry_run):它只计算并打印量化后的最终体积,并不真的压——在你纠结"选哪个档位才塞得进显存"时,先 dry-run 几个档位对比体积,比真压一遍快太多了。--keep-split 让输出保持和输入一样的分片结构(大模型常被切成多个 .gguf 分卷)。还有 --output-tensor-type / --token-embedding-type 能单独给输出层、词嵌入这两个对质量影响大的张量定更高的精度——很多高质量量化就是靠"主体压狠一点、关键张量留高一点"这种混合策略做出来的。这些旗标背后,正是前面 llama_model_quantize_params 里那些字段,命令行只是把它们暴露出来而已。
L06 and L12 already covered quantization's "principle" - why a few bits can approximate a float, and how each format lays out its bytes. This lesson takes a different angle: how to actually shrink a model with the tool. One llama-quantize command turns a dozen-GB fp16 model into a 3-5 GB Q4_K_M; add imatrix (the importance matrix) and the same bit width claws back a chunk of the lost quality.
In other words, L06/L12 is "understand the principle", this lesson is "operate the tool": knowing what each flag tunes, how different levels trade size against quality, and how to use imatrix, that "quality-restoring" key. Quantization is the crucial step that lets big models run on ordinary GPUs or even pure CPU, and this lesson teaches you to do it by hand.
The two stars here are tools/quantize (the compressor itself) and tools/imatrix (the companion that builds the importance matrix). We first see how quantize compresses in one command and which public API it calls underneath, then why imatrix can raise quality without adding any bits.
The most common use is one line: llama-quantize in.gguf out.gguf Q4_K_M - feed an fp16/fp32 GGUF, name a target level (here Q4_K_M), and it emits a compressed small GGUF. The entry is tools/quantize/main.cpp (thin), the body logic is in quantize.cpp, and the real work is the public API it calls, llama_model_quantize(in, out, ¶ms) - note this is a function from L25's llama.h, so the quantization capability is public too, not only the command line; you can call it from your own program.
// the quantize tool's heart: the public API behind one command (simplified from tools/quantize/quantize.cpp) llama_model_quantize_params params = llama_model_quantize_default_params(); params.ftype = LLAMA_FTYPE_MOSTLY_Q4_K_M; // target level params.imatrix = imatrix_data; // optional: feed in the importance matrix params.dry_run = false; // true = only compute size, do not really compress llama_model_quantize("in.gguf", "out.gguf", ¶ms);
That params (llama_model_quantize_params) hides several practical knobs: ftype picks the target level; dry_run set to true only trial-computes how big the result would be without really compressing (very handy when picking a level); output_tensor_type / token_embedding_type can give a few key tensors their own higher precision; keep_split keeps the shard structure. In other words, quantization is not "one blunt cut", but can be tuned per tensor class, even per layer.
So what is a "level"? It is a llama_ftype enum value, mapping to a scheme of "how many bits per weight on average" (bpw). quantize.cpp has a table listing each level's name, bpw, and measured size/perplexity cost. Below are a few representative levels and where they stand between "size" and "quality":
nearly lossless, large; for quality-critical cases with enough VRAM.
the community's favorite "sweet spot": much smaller, tiny quality loss, the everyday default.
ultra-low-bit, extreme VRAM thrift; leans on imatrix for quality, else clearly worse.
The intuition for picking a level follows L06: the lower the bpw, the smaller and thriftier the model, but the greater the precision loss and the higher the perplexity (ppl, next lesson). Most people land on a "sweet spot" like Q4_K_M - small enough for consumer GPUs, yet barely any visible regression. Only when VRAM is very tight do you go toward ultra-low-bit IQ2, and there imatrix becomes the lifeline. So "picking a level" is never picking the smallest, but picking the smallest level whose quality still holds up under your VRAM budget.
Here is a plain but crucial observation: not all weights matter equally. Some are almost always strongly activated and heavily affect the output; others mostly "sit around". Quantizing them all to the same precision is wasteful - too little precision on important weights clearly hurts quality, while high precision on unimportant ones wastes bits. imatrix (importance matrix) exists to solve this "how to split the bit budget" problem. By analogy, it is like a timed exam: rather than spend equal time on every question, spend more on the high-mark big questions and breeze through the small ones - the total score is naturally higher. imatrix does exactly this "allocate precision by marks" job for weights: first figure out which weights are the "big questions", then pour the precious bit budget mainly into them. Without this "mark sheet", quantization can only blindly treat all alike, inevitably wasting precision on places that hardly matter.
How do we know which weights are important? Directly: take a batch of calibration text (a few hundred representative passages) and actually run the model, and during the forward pass an eval-callback hook collect_imatrix accumulates each column's activation magnitude for every weight tensor (stored in the source as Stats values / counts). The more strongly a column is activated, the more "important" it is. When done, these stats are saved into an imatrix.gguf file, to be fed back at quantize time.
# step 1: build the importance matrix from calibration text (tools/imatrix) llama-imatrix -m model.gguf -f calib.txt -o imatrix.gguf # inside: during the forward pass collect_imatrix(t, ...) accumulates each weight tensor's per-column activation # step 2: feed it at quantize time, precision goes first to important columns llama-quantize --imatrix imatrix.gguf in.gguf out.gguf IQ2_XS
With this importance list, quantization can teach to each according to its aptitude: under the same bit budget, give important weight columns a more accurate quantization (smaller rounding error), and push the unavoidable error more onto the "irrelevant" columns. Below a minimal example shows how one row of weights is quantized under imatrix weighting:
The reason fits in a line: the same bits, spent where they count. Plain quantization spreads error evenly across all weights; imatrix quantization lets important weights lose almost no precision and dumps the error onto weights that hardly mattered anyway. The result: at exactly the same size (bit count), the model's overall perplexity (ppl) is lower and its behavior closer to the original fp16. Same bits, yet quality comes back a notch - that is imatrix's magic, and the real payoff of the plain effort of "measure first, then optimize". Better still, all of this is transparent to the user: you download an imatrix quant, change not a line of your load-and-infer code, yet quality is better out of nowhere - all the cleverness happens "at the moment of compression", and when you use it you simply enjoy the result.
After all this talk of levels, which should you actually pick? A practical decision order is: look at VRAM first. Roughly estimate "model size" as "parameter count x bpw / 8", compare it with your GPU's VRAM - if it fits with room to spare, pick a higher level (better quality); only when it does not fit do you compress further down. For example, an 8B model is about 8GB at Q8_0, 4.5GB at Q4_K_M, 2.5GB at IQ2 - how big your card is roughly frames the range of choices.
Within what VRAM allows, then look at the use. For "a small slip is a real error" tasks like coding or reasoning, prioritize quality and try not to go below Q4_K_M; for high-tolerance scenes like casual chat or continuation, dropping a level or two is usually harmless. One often-overlooked point: at the same size, prefer a low level of a bigger model over a high level of a smaller one - a 13B Q4 is often smarter than a 7B Q8 even if they are about the same size. This is a rule of thumb the community has verified again and again.
Finally, whenever you go to ultra-low bits (IQ2, IQ3), always prefer the imatrix version; for mid-to-high levels like plain Q4/Q5 the difference with or without imatrix is smaller, though having it is usually only a gain. Remember these three steps - "VRAM frames the range, use sets the floor, ultra-low-bit demands imatrix" - and you can quickly lock onto the one best suited to you from a screen full of quant file names.
Two final folds for two practical issues you will surely hit hands-on: how to read those odd level names, and what useful flags exist besides picking a level.
The names follow a pattern. In Q4_0, Q is quantize, 4 is about 4 bits per weight, 0 is the early simple scheme. The extra K in Q4_K_M means it is a "K-quant" (a smarter block quantization, better quality), and M is medium (with S=small, L=large fine-tuning the size). In IQ2_XS, IQ means an "ultra-low-bit scheme with imatrix", 2 is about 2 bits, XS is extra small. A one-line memo: Q=base, K=smarter blocks, IQ=ultra-low-bit via imatrix, suffix S/M/L=size tweak within a level. Read the naming and you can pick the one you want at a glance from a long list of file names, without trying each.
The most useful is --dry-run (matching params.dry_run): it only computes and prints the final quantized size without really compressing - when you are torn over "which level fits VRAM", dry-running a few levels to compare sizes is far faster than really compressing each. --keep-split keeps the output's shard structure the same as the input (big models are often split into several .gguf shards). And --output-tensor-type / --token-embedding-type can give the output layer and token embeddings - two quality-sensitive tensors - their own higher precision; many high-quality quants come from exactly this mix of "compress the body harder, keep key tensors higher". Behind these flags are those fields in the earlier llama_model_quantize_params; the command line merely exposes them.