2、量化基础:数值表示(定点/浮点)、量化误差来源、对称与非对称量化、量化参数(scale/zero-point)

TinyML 模型在部署到 MCU、DSP 或 NPU 等资源受限设备时,几乎无一例外地采用整数运算。浮点模型权重和激活值动辄占据数百 KB 甚至数 MB 的 Flash 与 RAM,而多数低功耗芯片的算力与存储远不足以支撑 Float32 推理。训练后量化(Post-Training Quantization, PTQ)的核心任务,就是将训练好的 Float32 模型映射到低比特整数域(常见为 INT8),同时尽量保持精度损失可控。理解数值表示、误差来源、量化策略与量化参数,是掌握 PTQ 全流程的第一道门槛。

数值表示 量化策略 量化参数 Float32 定点 Qm.n 动态范围大 / 硬件开销高 TinyML 中仅用于离线训练 对称量化 非对称量化 zero-point=0 / 适合权重 zero-point≠0 / 适合激活 Scale (s) Zero-point (z) 浮点步长 / 每单位整数 整数偏移 / 对齐浮点零点 校准数据集 统计 min/max 计算 s 与 z 量化误差来源 舍入误差(rounding) | 截断误差(clipping) | 精度损失(precision loss) 动态范围不匹配 | 离群点放大 | 累积误差传播

上图展示了本章的核心知识框架:数值表示决定了量化映射的数学基础,量化策略决定了映射方式,而量化参数则是具体映射的数值载体。下面逐一展开。

2.1 数值表示:定点与浮点

核心原理

浮点数(Float32)由符号位、指数位和尾数位组成,能够以极高动态范围表示极小和极大的数值。但浮点运算单元在 MCU 上面积大、功耗高、速度慢。定点数(Fixed-point)则是在整数基础上通过约定小数位位置来表示实数,格式记为 Qm.n,其中 m 为整数位宽,n 为小数位宽,总位宽为 m+n+1(含符号位)。例如 Q1.7 表示 1 位符号、1 位整数、7 位小数,可表示范围约为 [-2, 1.9921875],精度为 2⁻⁷。

在 TinyML 中,定点数通常不直接以 Q 格式存储,而是采用整数 + scale + zero-point 的映射方式。这种方式本质上是一种更灵活的定点表示,它允许任意浮点范围映射到整数域,而不必受限于 2 的幂次。

判断方法

  • 硬件支持:检查目标芯片是否具备 FPU(浮点单元)。Cortex-M4/M7 部分支持单精度浮点,但 Cortex-M0/M0+ 完全没有 FPU,只能整数运算。
  • 内存预算:Float32 模型权重为 4 字节/参数,INT8 为 1 字节/参数,4 倍差距在 Flash 和 RAM 上往往决定能否部署。
  • 功耗约束:整数乘加(MAC)运算功耗远低于浮点运算,对电池供电设备至关重要。

案例拆解

假设一个语音唤醒模型包含 50 万参数,Float32 占用 2MB Flash。某款低功耗蓝牙 SoC 仅有 1MB Flash,直接部署失败。改用 INT8 量化后,权重仅占 0.5MB,成功烧录。推理速度从 120ms/帧提升至 35ms/帧,功耗降低约 60%。

经验提醒:不要盲目追求低比特(如 INT4),先确认硬件是否原生支持。许多 MCU 的 SIMD 指令仅优化到 INT8,INT4 反而需要额外的解包操作,导致性能下降。

常见误区

误区一:认为定点数就是整数。实际上定点数包含小数部分,只是小数位固定。误区二:认为 Float16 是好的中间方案。Float16 在部分硬件上缺乏支持,且其动态范围与精度并不一定优于 INT8 配合 scale 的表示。

2.2 量化误差来源

核心原理

量化过程本质上是将连续的浮点值映射到离散的整数点,这一过程必然引入信息损失。误差主要来自三个方面:

  1. 舍入误差(Rounding Error):浮点值落在两个相邻整数之间时,需要四舍五入到最近的整数点,最大误差为 0.5 × scale。
  2. 截断误差(Clipping Error):当浮点值超出量化范围 [min, max] 时,会被截断到边界值,误差可能远大于舍入误差。
  3. 精度损失(Precision Loss):量化后的整数分辨率有限,无法区分原始浮点值之间的微小差异,导致信息粒度变粗。

判断方法

量化误差的评估通常通过量化前后张量的均方误差(MSE)或余弦相似度来衡量。对于权重,可以直接计算;对于激活值,需要在校准数据集上统计分布。若 MSE 超过 1e-3 或余弦相似度低于 0.99,则量化方案需要调整。

误差类型产生原因影响程度缓解手段
舍入误差整数分辨率有限较小,均匀分布增大位宽 / 优化 scale
截断误差动态范围超出量化区间较大,集中在尾部使用非对称量化 / 裁剪离群点
累积误差多层误差逐层传播严重,可能导致发散逐层校准 / 混合精度

案例拆解

某图像分类模型在量化后 Top-1 准确率从 85% 跌至 72%。分析发现,第一层卷积的激活值分布存在少量极端值(最大值为 12.8,而 99% 的值集中在 [-2, 2])。若采用对称量化,scale = 12.8/127 ≈ 0.1008,导致 [-2, 2] 区间内的有效量化步长过大,精度严重受损。改用非对称量化后,min=-2.1, max=12.8,scale = (12.8+2.1)/255 ≈ 0.0584,有效精度提升近一倍,准确率恢复至 83.5%。

风险提示:激活值中的离群点(outliers)是 PTQ 的主要敌人。在统计 min/max 时,建议使用百分位数(如 99.99%)而非绝对 min/max,以避免个别异常值拉大量化范围。

常见误区

误区一:认为量化误差只与位宽有关。实际上,scale 的选择对误差影响更大。误区二:忽略逐层误差累积。浅层的小误差经过深层放大后可能变得显著,因此需要逐层评估而非只看最终精度。

2.3 对称量化与非对称量化

核心原理

对称量化将浮点范围 [-max, max] 映射到整数范围 [-127, 127](INT8),zero-point 固定为 0。其数学表达式为:

q = round(r / scale)
scale = max / 127

非对称量化将浮点范围 [min, max] 映射到整数范围 [0, 255](UINT8)或 [-128, 127](INT8),zero-point 不为 0。其表达式为:

q = round(r / scale) + zero_point
scale = (max - min) / 255
zero_point = round(-min / scale)

判断方法

  • 权重:通常分布近似对称(正负值都有且幅度相近),优先使用对称量化,省去 zero-point 计算,硬件实现更简单。
  • 激活值:经过 ReLU 后分布非负,使用非对称量化能更充分利用整数范围,减少量化误差。
  • 硬件约束:部分 NPU 仅支持对称量化,此时即使激活值非负,也只能使用对称量化,但可以通过减去均值预处理来缓解。

案例拆解

以 MobileNetV1 为例,其深度可分离卷积的激活值经 ReLU6 后分布在 [0, 6] 区间。若采用对称量化,scale = 6/127 ≈ 0.0472,有效整数范围仅使用 0~127 的一半(因为负半轴浪费)。若采用非对称量化,scale = 6/255 ≈ 0.0235,分辨率提升一倍。实测表明,非对称量化使 Top-1 准确率提升 0.8%。

实战建议:在 TensorFlow Lite 中,默认对权重使用对称量化,对激活值使用非对称量化。若使用 PyTorch 的 torch.ao.quantization,可通过配置 qconfig 分别指定权重和激活的量化方式。

常见误区

误区一:认为非对称量化总是优于对称量化。实际上,非对称量化需要额外的 zero-point 运算,在部分硬件上会增加延迟。误区二:忽略 zero-point 的溢出风险。当 zero-point 超出整数范围时,需要做截断处理,否则会产生错误映射。

2.4 量化参数:scale 与 zero-point

核心原理

scale(缩放因子)表示每个整数单位对应的浮点步长,是一个浮点数。zero-point(零点偏移)表示浮点值 0 对应的整数表示。两者共同定义了浮点到整数的仿射变换:

r = (q - zero_point) × scale

反量化(dequantization)用于将整数还原为浮点,在混合精度推理或部分算子(如 BatchNorm)中需要用到。量化参数的选择直接决定了量化误差的大小。

操作流程

  1. 收集统计量:在校准数据集上运行浮点模型,记录每个张量的 min/max 或直方图分布。
  2. 计算 scale:根据量化策略(对称/非对称)和位宽,按公式计算 scale。
  3. 计算 zero-point:对于非对称量化,根据 min 和 scale 计算 zero-point,并做取整和截断。
  4. 验证:将量化参数应用于张量,计算量化前后误差,必要时调整校准策略。

案例拆解

某张量的浮点范围为 [-3.2, 6.4],采用 INT8 非对称量化:

scale = (6.4 - (-3.2)) / 255 = 9.6 / 255 ≈ 0.03765
zero_point = round(-(-3.2) / 0.03765) = round(85.0) = 85

验证:浮点值 0 映射为整数 85,反量化后为 (85-85)×0.03765 = 0,正确。浮点值 6.4 映射为整数 255,反量化后为 (255-85)×0.03765 ≈ 6.4,正确。

参数对称量化非对称量化备注
scalemax / 127(max-min) / 255始终为正浮点数
zero-point固定为 0round(-min/scale)需截断到 [-128, 127]
计算开销低中zero-point 需参与运算
适用场景权重、对称分布激活值、非负分布根据张量分布选择

常见误区

误区一:scale 越小越好。scale 过小会导致整数范围溢出,需要截断,反而引入更大的截断误差。误区二:zero-point 可以随意取整。zero-point 的取整误差会直接叠加到所有量化值上,应使用 round 而非 floor 或 ceil。误区三:忽略 scale 的数值稳定性。当 scale 过小时,反量化时可能出现浮点下溢,建议在硬件实现中使用定点乘法替代浮点除法。

经验总结:量化参数的选择本质上是动态范围与精度的权衡。范围越大,scale 越大,精度越低;范围越小,越容易截断。优秀的 PTQ 工具(如 TensorRT、AIMET)会使用 KL 散度或熵最小化方法自动寻找最优的 min/max 截断点,而非简单使用绝对 min/max。