1.2 量化基础概念:比特宽度、对称与非对称量化及校准 上一节我们把“为什么”讲清了。这一节开始补“是什么”。量化听起来玄乎,本质上就是一个把高精度实数“翻译”成低比特整数的映射过程。把这层窗户纸捅破,后面所有方法(GPTQ、AWQ、GGUF)你都能一眼看穿它们在优化什么。我会从比特宽度讲起,再到对称/非对称两种映射方式,最后落到决定 INT4 成败的“校准”上。 一、比特宽度:模型体积的刻度尺 “比特宽度”(bit-width)就是用来表示一个数值的比特数。比特越少,能表达的状态越少,存储越小,但精度越粗。大模型常用的精度构成一条“阶梯”: 每往下一格,参数体积大致减半。从 FP16(2 字节)到 INT4(0.5 字节)正好 4 倍。
上一节我们把“为什么”讲清了。这一节开始补“是什么”。量化听起来玄乎,本质上就是一个把高精度实数“翻译”成低比特整数的映射过程。把这层窗户纸捅破,后面所有方法(GPTQ、AWQ、GGUF)你都能一眼看穿它们在优化什么。我会从比特宽度讲起,再到对称/非对称两种映射方式,最后落到决定 INT4 成败的“校准”上。
“比特宽度”(bit-width)就是用来表示一个数值的比特数。比特越少,能表达的状态越少,存储越小,但精度越粗。大模型常用的精度构成一条“阶梯”:
每往下一格,参数体积大致减半。从 FP16(2 字节)到 INT4(0.5 字节)正好 4 倍。注意 FP8 和 INT8 都是 8 比特、1 字节,但一个是浮点、一个是整型,数值行为和硬件路径不同:FP8 保留浮点的动态范围特性,INT8/INT4 则是纯整型,依赖“缩放因子”把实数区间映射到整数格。
一个常被问到的问题:INT4 是不是精度的下限? 理论上还能做 INT2(0.25 字节),但 2 比特只有 4 个档位,量化误差大到模型基本“失能”,只在极特殊研究场景出现。工程上 INT4 是当前可用的激进下限,INT8 是稳的底线。
不管方法多花哨,量化/反量化的数学骨架就两行:
量化:
q = round(r / scale) + zero_point
反量化:r_hat = (q - zero_point) * scale
其中 r 是原始实数(权重或激活),q 是量化后的整数,scale(缩放因子)把实数区间“缩”到整数格距,zero_point(零点)负责把实数轴的某个值对齐到整数 0。反量化得到的 r_hat 是近似还原值,误差 r - r_hat 就是量化噪声。所有量化算法的核心任务,就是找一组最优的 scale 和 zero_point,让这个噪声最小。
下面这段 Python 用最小代码演示了这个过程(以 INT4 有符号范围 [-8, 7] 为例):
import numpy as np def quantize_int4(r, symmetric=True): # INT4 有符号范围 [-8, 7] qmin, qmax = -8, 7 if symmetric: # 对称:零点为 0,scale 取最大绝对值 scale = max(abs(r.min()), abs(r.max())) / max(abs(qmin), abs(qmax)) zero_point = 0 else: # 非对称:把 [r_min, r_max] 映射到 [qmin, qmax] scale = (r.max() - r.min()) / (qmax - qmin) zero_point = qmin - r.min() / scale q = np.clip(np.round(r / scale + zero_point), qmin, qmax) r_hat = (q - zero_point) * scale # 反量化 return q, r_hat, scale, zero_point w = np.array([-1.7, -0.3, 0.0, 0.9, 2.4, -2.6]) q, r_hat, s, zp = quantize_int4(w, symmetric=True) print("scale:", s, "zero_point:", zp) print("量化值 q:", q) print("反量化 r_hat:", np.round(r_hat, 3)) print("量化误差:", np.round(w - r_hat, 3))
跑这段代码你会直观看到:原本连续的权重,被“钉”到了 -8 到 7 之间的整数上,反量化回来已经和原数有偏差——这就是量化噪声的具象。
选择 scale/zero_point 的两条路线,对应两种映射哲学:
zero_point = 0,即实数 0 映射到整数 0,格点关于原点对称。它最适合权重——因为神经网络权重大多零均值、围绕 0 分布。公式上 scale = max(|r|) / (2^(b-1) - 1)。好处是实现简单、推理时少一次加法(无需减 zero_point),计算快。zero_point ≠ 0,把实数区间的最小值对齐到整数 0。它适合激活值,尤其像 ReLU 这类输出恒 ≥0、分布明显偏离 0 的张量——若强行对称,一半整数格会被浪费在永远用不到的负数区,精度白白损失。实践中的经验法则:权重用对称 INT4,激活用非对称 INT8(或对称 INT8,取决于运行时),这是精度和效率的平衡点。很多 INT4 方案(如 GPTQ)对权重采用对称 per-group 量化,正是这个原因。
需要澄清一个常见误解:为什么不能“权重对称、激活也对称”一刀切?因为激活的分布形态和权重不同——权重围绕 0 对称,而激活(尤其经过 ReLU/GELU 之后)常常一边倒地偏正,最小值接近 0、最大值很大。若对激活强行对称,整数格里代表负值的那一半(比如 INT8 的 -128 到 -1)永远用不上,等于白白丢掉一半分辨率。非对称量化通过 zero_point 把“实数最小值”对齐到整数 0,让每一档都用在刀刃上。一句话:对称省一次减法、适合零中心分布;非对称多用一次偏移、适合偏态分布。
“用几套 scale”决定了量化的粗细,是影响 INT4 质量的关键旋钮:
group_size = 128),每组一个 scale。这是 INT4 的标配(GPTQ、AWQ、GGUF 的多数方案都用 group_size 128)。为什么?因为大模型权重里存在“离群通道”——极少数通道数值极大,会污染全局 scale;切成小 group 后,离群值被限制在它所在的组里,其余组的 scale 可以“贴合”真实分布,精度大幅提升。代价是:group 越细,scale 和 zero_point 的存储开销越大,反量化时的查表/计算也略慢。group_size 128 是反复验证过的甜点;调小(如 64)更准但更慢更占空间,调大(如 256)反之。
这里补一个常被忽略的算术直觉:INT4 每组 128 个权重存 1 个 scale(通常 FP16,2 字节),于是每组 128 个 INT4 权重只占 64 字节,加上 2 字节 scale,开销约 5.1%;若 group_size 翻倍到 256,scale 占比降到约 2.6%,但离群值“连累”相邻权重的范围更大、精度更差。这就是为什么 128 是质量与开销的黄金交叉点。再往下走,per-channel 因每组覆盖整条输出通道(数千权重),scale 占比可忽略,但对离群通道完全无能为力——这正是 INT4 必须下沉到 per-group 的根本原因。
必须单独强调一个点,因为它是 INT4 比 INT8 难那么多的根本原因:大模型权重和激活中存在少量“离群值”(outlier)——数值比平均值大几十甚至上百倍的通道。
如果对这些离群通道和正常通道用同一套 scale,要么离群值被截断失真,要么正常通道被压到几乎没有分辨率。研究者发现,MoE 这类巨型模型离群现象更显著,这也是为什么“随便四舍五入(RTN)做 INT4”往往翻车,而 GPTQ/AWQ 这类方法专门设计来处理离群值。第 2 章会展开这些方法各自的思路。
前面所有公式都依赖 scale 和 zero_point,而它们怎么定?不能只看权重本身的最小值最大值,还要看模型实际跑起来时激活的真实分布——因为最终误差发生在推理的前向传播里。确定这些参数的过程叫“校准”,需要一小批有代表性的数据(校准集,calibration set):
范围估计(range estimation)的几种主流做法:
校准集的质量直接决定量化后模型“像不像原来的模型”。经验上,校准数据要覆盖你真实任务的分布:用中文对话数据校准的模型,去做英文代码任务可能掉点。这也是为什么通用量化模型和“领域微调量化模型”质量有差距。
关于校准集,有三个实践要点值得单独拎出来:
第一,数量够用即可,重在“代表性”而非“海量”。多数 INT4 方案的校准集只要几十到几百条样本就能收敛,堆到上万条边际收益极低,反而拖长量化耗时。关键不是多,而是每条样本都能“激活”模型不同的行为模式。
第二,警惕“脏校准”。如果校准数据里混入与正式任务无关的格式(比如全是超短问答,而你要做的是长文档摘要),量化后的模型会在长上下文上明显掉链子。校准分布应当尽量贴齐你上线后的真实输入形态。
第三,校准集一旦选定就不要随意换。对比不同量化方法的效果时,务必用同一份校准集,否则你分不清是“方法更强”还是“校准集更对症”——这是量化实验里最容易被忽视的变量控制。
最后铺垫一个分类,后面章节会深挖:
给读者的主张:如果你只想快速验证一个模型能不能跑,RTN 类方案(如 GGUF 的 Q4_K_M)够用且极快;如果你要把 INT4 模型用于生产、且对精度敏感,请直接上 GPTQ 或 AWQ,不要省这一步。
最后提醒一点:量化质量的“好坏”不能只看一个总准确率数字。同一份权重,在常识问答上可能几乎不掉点,但在多步算术、长程指代、代码语法正确性上却悄悄退化——这是因为 INT4 的误差会沿推理链累积,越到“需要精确保持中间状态”的任务越容易暴露。所以评估一个 INT4 模型时,务必用你真实任务里最“刁钻”的几类样本做人工复核,而不是只信公开的通用榜单。把这点养成习惯,能帮你避开绝大多数“上线后才发现变傻”的事故。
为了把本节的概念落到“可操作”,给你一张选型速查表,写代码前先对照一遍:
| 你要量化什么 | 推荐方式 | 比特 | 粒度 | 校准 |
|---|---|---|---|---|
| 权重(绝大多数层) | 对称 | INT4 | per-group 128 | 需校准集 |
| 激活值 | 非对称 | INT8 | per-tensor/channel | 需校准集 |
| KV Cache | 非对称 | INT4/INT8 | per-token 可选 | 通常免校准 |
| 快速验证原型 | RTN | INT4 | per-group | 免校准 |
记住这张表,第 2 章讲具体方法时你就不会迷失在参数里——它们无非是在这张表的格子里做不同取舍。若你暂时记不住细节也别慌:只要守住“权重对称 INT4 per-group 128 + 校准集覆盖真实分布”这两条铁律,就已经避开了 90% 的 INT4 翻车现场。
读完这节,你应该能一句话说清量化是什么:量化就是用更少的 bits 把高精度实数“翻译”成整数——通过 scale 和 zero_point 完成映射;权重常用对称 per-group INT4 来压制离群值,而 scale 的好坏由校准集和范围估计法决定,这正是 INT4 质量分水岭所在。
下一章我们将正式拆解 GPTQ、AWQ、GGUF 这几条主流 INT4 量化方法,看它们各自如何聪明地“保住精度”。