量化基础:定点与浮点表示、对称/非对称量化、量化公式推导、scale与zero-point的定义
在进入PTQ(训练后量化)的误差定位之前,必须先建立统一的量化语言。很多工程师在排查精度掉点问题时,往往直接跳到"哪个层出了问题",却忽略了最底层的表示误差——定点与浮点的映射关系、对称与非对称的选择、以及scale和zero-point的数学含义。本章将系统梳理这些基础概念,并推导出后续所有误差分析所依赖的核心公式。
上图展示了量化基础知识的整体框架。从数值表示出发,区分定点与浮点的本质差异,再根据数据分布特性选择对称或非对称量化,最终落到scale与zero-point的计算与使用。这张图将贯穿本章所有内容,也是后续章节进行误差定位时的思维导图。
2.1 定点与浮点表示:量化问题的起源
核心原理
计算机中的数值表示主要分为定点(Fixed-point)和浮点(Floating-point)两种。浮点数(如FP32、FP16)通过符号位、指数位和尾数位表示,动态范围大、精度高,但硬件计算单元复杂、功耗高。定点数则使用固定的小数点位置,用整数运算模拟实数运算,硬件实现简单、速度快,但动态范围受限。
神经网络模型在训练时通常使用FP32,因为反向传播需要高精度梯度。但在推理阶段,尤其是部署到边缘设备(如手机、嵌入式设备、FPGA)时,FP32的存储和计算开销过大。量化(Quantization)的核心思想就是:将FP32的权重和激活值映射到低比特整数(如INT8、INT4),同时尽量保持模型精度。
| 特性 | 浮点表示(FP32) | 定点表示(INT8) |
|---|---|---|
| 动态范围 | 约1e-38 ~ 3.4e38 | -128 ~ 127(有符号) |
| 精度 | 约7位有效数字 | 固定步长,均匀分布 |
| 硬件成本 | 高(需要指数对齐) | 低(整数ALU即可) |
| 存储占用 | 4字节/参数 | 1字节/参数(4倍压缩) |
| 适用场景 | 训练、高精度计算 | 推理、边缘部署 |
判断方法
在实际工程中,判断一个张量(Tensor)是否适合定点化,主要看三个指标:
- 数值分布范围:如果数据集中在很小的区间(如[-1, 1]),定点化损失较小;如果分布极不均匀(如存在长尾),则需要考虑非对称量化或更高比特。
- 对误差的敏感度:权重和激活的敏感度不同。通常权重的量化误差对精度影响更大,因为权重是共享的;激活的误差则逐层传递。
- 硬件支持:某些硬件(如NPU)对对称量化有优化指令,非对称量化可能需要额外计算。
案例拆解:一个卷积层的定点化决策
假设我们有一个3x3卷积层,权重分布范围为[-0.5, 0.5],激活值分布范围为[-10, 10]。如果直接使用对称INT8量化:
- 权重:scale = 0.5/127 ≈ 0.00394,量化误差较小。
- 激活:scale = 10/127 ≈ 0.0787,但激活值大部分集中在[-2, 2]区间,导致小值区域的量化步长过大,相对误差高达10%以上。
这种情况下,激活使用非对称量化更合适:将[-10, 10]映射到[0, 255],scale = 20/255 ≈ 0.0784,zero-point = 128。虽然步长没有变小,但零点偏移使得小值区域也能被有效表示,减少了截断误差。
2.2 对称量化与非对称量化:如何选择
核心原理
对称量化(Symmetric Quantization)要求浮点零值精确映射到整数零值,即zero-point = 0。其映射关系为:
q = clamp(round(r / scale), -127, 127) // INT8有符号
r = q × scale
非对称量化(Asymmetric Quantization)允许零点偏移,浮点零值映射到任意整数zero-point:
q = clamp(round(r / scale) + zero_point, 0, 255) // INT8无符号
r = (q - zero_point) × scale
对称量化的优势在于计算简单,不需要额外处理zero-point的加减法,适合权重(通常分布关于0对称)。非对称量化则能更好地利用量化范围,适合激活值(通常分布偏向正区间)。
判断方法
| 维度 | 对称量化 | 非对称量化 |
|---|---|---|
| zero-point | 固定为0 | 可配置,通常为128(INT8) |
| 计算复杂度 | 低(无需偏移) | 高(需额外加减) |
| 范围利用率 | 低(若分布不对称) | 高(可覆盖任意分布) |
| 硬件支持 | 广泛(多数NPU原生支持) | 部分支持(需软件模拟) |
| 典型应用 | 权重、偏置 | 激活值、中间特征图 |
案例拆解:激活值分布不对称时的量化对比
某层激活值分布为[-1, 15],均值约为3。若使用对称量化:
- scale = 15/127 ≈ 0.118,但[-1, 0]区间只有约8个量化级别,精度严重不足。
- 若使用非对称量化:scale = (15-(-1))/255 ≈ 0.0627,zero-point = round(-(-1)/0.0627) ≈ 16,整个范围被均匀覆盖。
实际测试中,非对称量化在该层的信噪比(SNR)比对称量化高约6dB,最终模型精度提升0.8%。
2.3 量化公式推导:从浮点到定点的数学映射
核心原理
量化的本质是寻找一个映射函数 f: R → Z,将浮点数r映射到整数q,并保证反量化误差最小。标准公式为:
量化:q = clamp(round(r / scale) + zero_point, q_min, q_max)
反量化:r_hat = (q - zero_point) × scale
其中,scale(缩放因子)和zero-point(零点)是两个关键参数。推导过程如下:
- 确定浮点范围 [r_min, r_max] 和整数范围 [q_min, q_max]。
- 计算scale:scale = (r_max - r_min) / (q_max - q_min)。
- 计算zero-point:zero_point = q_min - round(r_min / scale)。
对于对称量化,r_min = -r_max,q_min = -q_max,则zero_point = 0。
操作流程:手动计算一个张量的scale和zero-point
假设浮点张量 r = [-2.5, -1.0, 0.0, 1.5, 3.0],目标INT8(q_min=-128, q_max=127)
1. 确定范围:r_min = -2.5, r_max = 3.0
2. 计算scale:scale = (3.0 - (-2.5)) / (127 - (-128)) = 5.5 / 255 ≈ 0.02157
3. 计算zero-point:zero_point = -128 - round(-2.5 / 0.02157) = -128 - (-116) = -12
4. 量化:q = round(r / 0.02157) + (-12)
- r=-2.5 → round(-115.9) = -116 → q = -128
- r=0.0 → round(0) = 0 → q = -12
- r=3.0 → round(139.1) = 139 → q = 127
5. 反量化:r_hat = (q - (-12)) × 0.02157
- q=-128 → r_hat = -2.502
- q=-12 → r_hat = 0.0
- q=127 → r_hat = 2.998
常见误区
- 误区1:认为scale必须等于最大值/127。实际上,scale由整个范围决定,而非单点。
- 误区2:忽略clamp操作。如果r超出[r_min, r_max],量化结果会溢出,必须截断。
- 误区3:zero-point计算后未取整。zero-point必须是整数,否则反量化时无法精确还原零点。
2.4 scale与zero-point的定义:误差定位的基石
核心原理
scale(缩放因子)决定了量化步长,即相邻两个整数之间的浮点距离。scale越小,量化精度越高,但需要更大的整数范围。zero-point(零点)是浮点零值在整数域中的映射,它保证了浮点零值能被精确表示,避免"零漂移"问题。
在误差定位中,scale和zero-point的异常往往是精度掉点的直接原因。例如:
- scale过大 → 量化步长粗 → 小值被"抹平" → 激活值精度下降。
- scale过小 → 大值溢出 → 截断误差 → 权重精度下降。
- zero-point计算错误 → 零点偏移 → 反量化后均值偏移 → 后续层累积误差。
判断方法:如何检查scale和zero-point是否合理
| 检查项 | 正常范围 | 异常信号 |
|---|---|---|
| scale值 | 与数据范围同量级 | 过大(>10×数据标准差)或过小(<0.001×标准差) |
| zero-point | 在[q_min, q_max]内 | 超出范围或与128偏差过大(非对称时) |
| 反量化误差 | 相对误差 < 1% | 相对误差 > 5% 或出现系统性偏差 |
| 零点映射 | 浮点0.0 → 整数zero-point | 浮点0.0映射后反量化不为0 |
案例拆解:一个scale异常导致的精度掉点排查
背景:某图像分类模型在PTQ后,Top-1精度从80.2%降至72.5%,掉点严重。
初始现象:逐层检查发现,第3个卷积层的输出特征图分布异常,大量值集中在[-0.1, 0.1]区间,但scale被计算为0.5。
分析过程:
- 打印该层激活值的统计信息:min=-0.08, max=0.12, mean=0.01, std=0.03。
- 计算理论scale:若使用非对称量化,scale = (0.12-(-0.08))/255 ≈ 0.00078。
- 实际scale为0.5,说明量化配置错误——可能使用了全局统计值而非该层实际分布。
解决方案:重新计算该层的scale和zero-point,使用校准数据集(Calibration Dataset)统计真实分布。修正后精度恢复至79.8%。
复盘经验:PTQ中,每层的scale必须基于该层的实际数据分布计算,不能使用全局统一值。尤其是BatchNorm层融合后,激活分布会发生变化,需要重新校准。