2、量化基础:数值表示(定点/浮点)、量化误差来源、对称与非对称量化、量化参数(scale/zero-point)
TinyML 模型在部署到 MCU、DSP 或 NPU 等资源受限设备时,几乎无一例外地采用整数运算。浮点模型权重和激活值动辄占据数百 KB 甚至数 MB 的 Flash 与 RAM,而多数低功耗芯片的算力与存储远不足以支撑 Float32 推理。训练后量化(Post-Training Quantization, PTQ)的核心任务,就是将训练好的 Float32 模型映射到低比特整数域(常见为 INT8),同时尽量保持精度损失可控。理解数值表示、误差来源、量化策略与量化参数,是掌握 PTQ 全流程的第一道门槛。
上图展示了本章的核心知识框架:数值表示决定了量化映射的数学基础,量化策略决定了映射方式,而量化参数则是具体映射的数值载体。下面逐一展开。
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%。
常见误区
误区一:认为定点数就是整数。实际上定点数包含小数部分,只是小数位固定。误区二:认为 Float16 是好的中间方案。Float16 在部分硬件上缺乏支持,且其动态范围与精度并不一定优于 INT8 配合 scale 的表示。
2.2 量化误差来源
核心原理
量化过程本质上是将连续的浮点值映射到离散的整数点,这一过程必然引入信息损失。误差主要来自三个方面:
- 舍入误差(Rounding Error):浮点值落在两个相邻整数之间时,需要四舍五入到最近的整数点,最大误差为 0.5 × scale。
- 截断误差(Clipping Error):当浮点值超出量化范围 [min, max] 时,会被截断到边界值,误差可能远大于舍入误差。
- 精度损失(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%。
常见误区
误区一:认为量化误差只与位宽有关。实际上,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%。
常见误区
误区一:认为非对称量化总是优于对称量化。实际上,非对称量化需要额外的 zero-point 运算,在部分硬件上会增加延迟。误区二:忽略 zero-point 的溢出风险。当 zero-point 超出整数范围时,需要做截断处理,否则会产生错误映射。
2.4 量化参数:scale 与 zero-point
核心原理
scale(缩放因子)表示每个整数单位对应的浮点步长,是一个浮点数。zero-point(零点偏移)表示浮点值 0 对应的整数表示。两者共同定义了浮点到整数的仿射变换:
r = (q - zero_point) × scale
反量化(dequantization)用于将整数还原为浮点,在混合精度推理或部分算子(如 BatchNorm)中需要用到。量化参数的选择直接决定了量化误差的大小。
操作流程
- 收集统计量:在校准数据集上运行浮点模型,记录每个张量的 min/max 或直方图分布。
- 计算 scale:根据量化策略(对称/非对称)和位宽,按公式计算 scale。
- 计算 zero-point:对于非对称量化,根据 min 和 scale 计算 zero-point,并做取整和截断。
- 验证:将量化参数应用于张量,计算量化前后误差,必要时调整校准策略。
案例拆解
某张量的浮点范围为 [-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,正确。
| 参数 | 对称量化 | 非对称量化 | 备注 |
|---|---|---|---|
| scale | max / 127 | (max-min) / 255 | 始终为正浮点数 |
| zero-point | 固定为 0 | round(-min/scale) | 需截断到 [-128, 127] |
| 计算开销 | 低 | 中 | zero-point 需参与运算 |
| 适用场景 | 权重、对称分布 | 激活值、非负分布 | 根据张量分布选择 |
常见误区
误区一:scale 越小越好。scale 过小会导致整数范围溢出,需要截断,反而引入更大的截断误差。误区二:zero-point 可以随意取整。zero-point 的取整误差会直接叠加到所有量化值上,应使用 round 而非 floor 或 ceil。误区三:忽略 scale 的数值稳定性。当 scale 过小时,反量化时可能出现浮点下溢,建议在硬件实现中使用定点乘法替代浮点除法。