不能绝对保证完全一致。模型量化的本质就是:
把连续/高精度数值,压到低 bit 离散格点上。所以权重、激活、KV cache 的数值一定会变。能保证的是:
误差足够小 → logits 排序基本不变 → 输出结果大体一致但不是数学上 100% 完全相同。
1. 量化到底改变了什么?
以 INT8 / INT4 为例,原始浮点数x会被映射成整数:
q = round(x / scale)再推理时近似还原:
x_hat = q × scale所以真正参与计算的是:
x_hat ≈ x不是原来的x。
误差是:
error = x_hat - x如果是均匀量化,单个数的最大量化误差大约是:
|error| <= scale / 2也就是说,scale 越小,量化越精细,误差越小。
2. 为什么误差小,输出还能基本一致?
大模型最终输出 token,是看 logits:
logits = model(x)然后选择概率最高的 token。
如果量化前:
token_A logit = 12.0 token_B logit = 9.0量化后有一点误差:
token_A logit = 11.8 token_B logit = 9.2排序没变,输出还是 token_A。
但如果量化前两个 token 很接近:
token_A logit = 10.01 token_B logit = 10.00量化后可能变成:
token_A logit = 9.98 token_B logit = 10.02那输出就变了。
所以核心判断是:
如果 top1 和 top2 的 logit 差距 > 量化误差影响,输出大概率一致; 如果 top1 和 top2 很接近,量化很容易导致 token 翻转。这也是为什么大模型量化后,经常不是整体崩,而是在某些边界问题上输出变差。
3. 怎么尽量保证推理结果一致?
主要靠这些方法。
第一,选好 scale
量化不是随便除一个数,而是要选 scale。
常见方式:
scale = max(|x|) / qmax例如 INT8 对称量化:
qmax = 127 scale = max(|x|) / 127这样最大值不会溢出。
但如果某一层有极端 outlier,会导致 scale 很大,普通小值的分辨率变差。
比如:
大多数值在 [-1, 1] 但有一个 outlier = 100如果用100 / 127做 scale,那么小值会被量化得很粗,精度损失很大。
所以大模型量化的核心问题之一就是:
怎么处理 outlier。第二,per-channel / per-group 量化
不要整个矩阵共用一个 scale,而是分组。
例如权重矩阵:
W: [out_dim, in_dim]可以:
per-tensor:整个 W 共用一个 scale per-channel:每个输出通道一个 scale per-group:每 32/64/128 个元素一个 scale越细粒度,误差越小:
per-tensor 误差最大 per-channel 更好 per-group 通常更适合 LLM大模型 INT4 常用 group-wise quantization,例如 group size = 32/64/128。
第三,关键层保留高精度
不是所有层都适合量化。
通常比较敏感的部分包括:
embedding lm_head RMSNorm / LayerNorm attention softmax 部分 activation 少数 outlier 明显的层所以工程上常见做法是:
大部分权重量化到 INT4 / INT8 Norm 保持 FP16/BF16 激活保持 FP16/BF16 或 INT8 lm_head 有时保持 FP16/BF16这叫 mixed precision。
也就是说:
不是整个模型一刀切量化。第四,校准 calibration
PTQ,也就是 Post-Training Quantization,通常需要校准数据。
流程是:
拿一批代表性样本 跑一遍模型 统计每层 activation 分布 决定 scale / zero point / clipping 范围如果 calibration 数据和真实推理场景接近,量化效果就更稳。
例如你做机器人视觉语言模型,校准数据最好包含:
真实相机图像 真实任务指令 真实机械臂场景 真实深度/视觉分布而不是随便拿通用文本。
第五,处理 outlier
大模型里很多误差来自 outlier channel。
例如某些 activation 通道数值特别大:
普通通道:[-2, 2] 异常通道:[-80, 80]这些 outlier 会破坏量化 scale。
所以很多方法会做:
SmoothQuant:把 activation 的 outlier 转移到 weight AWQ:保护对输出影响最大的权重通道 GPTQ:用二阶近似减少权重量化后的输出误差这些方法的本质不是“数值不变”,而是:
让量化后的矩阵乘输出尽量接近原模型输出。4. 数学上为什么不能严格保证一致?
因为神经网络是多层复合函数:
y = f_L(...f_2(f_1(x, W_1), W_2)..., W_L)量化后变成:
y_hat = f_L(...f_2(f_1(x, W_1 + ΔW_1), W_2 + ΔW_2)...)每一层都有误差:
W_hat = W + ΔW单层误差可能很小,但经过很多层后会累积。
尤其 Transformer 里有:
MatMul Attention Softmax Residual MLP MoE routing LayerNorm / RMSNorm这些结构会让误差传播路径很复杂。
所以严格来说:
量化不能保证所有输入下输出 token 完全一致。它只能保证:
在测试集/校准集/真实业务分布上,精度下降足够小。5. LLM 推理里“一致”到底怎么衡量?
不是只看一句话是否完全一样。
更常用的是这些指标:
1. logits 误差 2. top-k token 是否一致 3. perplexity 是否上升 4. benchmark 分数是否下降 5. 真实任务成功率是否下降 6. 长文本稳定性是否下降 7. 多轮对话是否更容易胡说如果是确定性解码:
temperature = 0 top_p = 1可以比较 token 是否完全一致。
如果是采样解码:
temperature > 0 top_p < 1即使不量化,每次输出也可能不一样,这时就不能要求逐 token 完全一致,只能比较统计质量。
6. 对你写推理引擎来说,最关键的是这几点
如果你自己做 INT8 / INT4 推理引擎,要优先保证:
1. scale 计算正确 2. zero point 正确 3. group size 正确 4. weight layout 正确 5. dequant 公式正确 6. accumulation 精度正确 7. RoPE / RMSNorm / softmax 保持高精度 8. logits 和原模型误差可测尤其注意 accumulation。
例如 INT8 GEMM 不是直接 INT8 累加到 INT8,而是:
INT8 × INT8 → INT32 accumulate → FP16/BF16/FP32 outputINT4 也类似:
INT4 weight × FP16 activation ↓ dequant ↓ FP16/BF16 accumulate 或 Tensor Core 路径如果 accumulation 精度不对,模型很容易崩。
7. 最简洁结论
量化不会让模型数值完全不变。
它保证推理结果接近,靠的是:
1. 量化误差足够小 2. logits 排序基本不变 3. 敏感层保留高精度 4. per-channel / per-group scale 减少误差 5. calibration 数据匹配真实分布 6. GPTQ / AWQ / SmoothQuant 等方法修正 outlier 和输出误差 7. 用 benchmark / perplexity / logits 误差验证一句话:
量化不是保证“数值完全一致”,而是保证“误差不改变模型的主要决策边界”。当 top1 和 top2 很接近时,量化后的输出 token 发生变化是正常的。
可以。用几个最小数学例子说明:量化改变数值,但为什么推理结果还能保持一致。
1. 一个最简单的线性层例子
假设模型某一层是:
y = w1*x1 + w2*x2原始 FP16/FP32 权重:
w = [0.52, -1.37] x = [2.0, 1.0]原始输出:
y = 0.52*2.0 + (-1.37)*1.0 = 1.04 - 1.37 = -0.33现在把权重量化成 INT4。
假设 scale = 0.2,INT4 范围用[-7, 7]。
量化公式:
q = round(w / scale)所以:
q1 = round(0.52 / 0.2) = round(2.6) = 3 q2 = round(-1.37 / 0.2) = round(-6.85) = -7反量化:
w_hat = q * scale得到:
w_hat = [3*0.2, -7*0.2] = [0.6, -1.4]量化后输出:
y_hat = 0.6*2.0 + (-1.4)*1.0 = 1.2 - 1.4 = -0.2对比:
原始输出:-0.33 量化输出:-0.20 误差:0.13数值变了,但如果下一步只是判断正负:
y < 0 → 类别 A y > 0 → 类别 B那么:
原始:-0.33 < 0 → A 量化:-0.20 < 0 → A结果一致。
2. 为什么有时结果会变?
还是同一个判断边界:
y < 0 → A y > 0 → B如果原始输出非常接近 0:
原始 y = 0.03量化误差是:
error = -0.08那么量化后:
y_hat = 0.03 - 0.08 = -0.05结果就变成:
原始:0.03 > 0 → B 量化:-0.05 < 0 → A所以关键不是“数值是否改变”,而是:
量化误差有没有跨过决策边界一句话:
离边界远,量化后大概率不变;离边界近,量化后容易变。
3. 对应到大模型 logits 的例子
大模型最后会输出一组 logits,比如三个候选 token:
token A: 12.0 token B: 9.5 token C: 3.0模型会选最大值:
A 最大 → 输出 A量化后 logits 可能变成:
token A: 11.7 token B: 9.8 token C: 3.1虽然数值变了,但排序还是:
A > B > C所以输出还是 A。
这就是量化后仍然一致的原因:
logits 排序没有变4. logits 很接近时,就容易翻转
假设原始 logits 是:
token A: 10.01 token B: 10.00 token C: 2.00原始输出:
A 最大 → 输出 A量化后可能变成:
token A: 9.98 token B: 10.02 token C: 2.01此时排序变了:
B > A > C输出就变成 B。
所以量化不会保证每个 token 完全一致,它保证的是:
大多数情况下,logits 的主要排序结构不被破坏5. 用矩阵乘看量化误差
Transformer 里最核心的是矩阵乘:
y = Wx量化后权重变成:
W_hat = W + ΔW所以输出变成:
y_hat = W_hat x = (W + ΔW)x = Wx + ΔW x也就是:
y_hat = y + ΔW x其中:
ΔW x = 量化带来的输出误差所以只要:
|ΔW x| 足够小模型输出就接近原模型。
这就是 GPTQ、AWQ、SmoothQuant 等方法的核心目标:
不是让 W_hat = W 而是让 W_hat x ≈ W x因为模型真正关心的是每一层的输出,而不是每个权重是否完全相同。
6. 一个二维分类边界例子
假设模型最后做二分类:
score = 2*x1 - x2判断规则:
score > 0 → 类别 1 score < 0 → 类别 0输入:
x1 = 3 x2 = 4原始:
score = 2*3 - 4 = 2结果:
score = 2 > 0 → 类别 1现在量化后权重有误差:
2 → 1.9 -1 → -1.1量化后:
score_hat = 1.9*3 - 1.1*4 = 5.7 - 4.4 = 1.3结果仍然:
score_hat = 1.3 > 0 → 类别 1虽然 score 从 2 变成了 1.3,但没有跨过 0,所以分类不变。
但是如果原始输入是:
x1 = 2.01 x2 = 4原始:
score = 2*2.01 - 4 = 4.02 - 4 = 0.02离边界非常近。
量化后:
score_hat = 1.9*2.01 - 1.1*4 = 3.819 - 4.4 = -0.581结果变成:
原始:类别 1 量化:类别 0这说明:
靠近决策边界的样本,量化后更容易改变结果。7. 为什么 per-group 量化误差更小?
假设一组权重:
W = [0.1, 0.2, 0.3, 10.0]如果整个 tensor 共用一个 INT4 scale:
scale = max(|W|) / 7 = 10 / 7 ≈ 1.43那么前三个小值量化:
0.1 / 1.43 ≈ 0.07 → round → 0 0.2 / 1.43 ≈ 0.14 → round → 0 0.3 / 1.43 ≈ 0.21 → round → 0反量化后:
[0, 0, 0, 10.01]小权重全没了。
如果分组,把前三个小值单独一组:
group1 = [0.1, 0.2, 0.3] scale1 = 0.3 / 7 ≈ 0.043量化后:
0.1 / 0.043 ≈ 2 0.2 / 0.043 ≈ 5 0.3 / 0.043 ≈ 7反量化:
[0.086, 0.215, 0.301]就接近原始值。
所以:
per-tensor 量化容易被 outlier 破坏 per-group / per-channel 量化可以减少误差这就是大模型 INT4 通常用 group-wise quantization 的原因。
8. 最核心数学结论
量化后:
W_hat = W + ΔW模型输出变成:
y_hat = W_hat x = Wx + ΔW x如果:
|ΔW x| 很小那么:
y_hat ≈ y如果最终 logits 满足:
top1_logit - top2_logit > 量化误差影响则输出 token 不变。
如果:
top1_logit - top2_logit ≈ 0那么一点量化误差就可能改变输出。
所以一句话:
量化不是保证数值完全一样,而是保证误差没有大到改变模型的主要决策边界。