3、量化基础:量化原理、定点与浮点、对称与非对称量化、量化参数(scale/zero-point)

在进入 Ethos-U NPU 的延迟调优之前,我们必须先建立统一的量化语言。量化本质上是将连续(或高精度)的浮点数值空间映射到离散(或低精度)的整数数值空间的过程。对于 Ethos-U 系列 NPU 而言,其核心计算单元通常以 8-bit 或 16-bit 整数执行乘加运算,权重和激活值若以浮点格式存储,不仅会占用大量内存带宽,更会因硬件不支持浮点运算而导致无法推理。因此,理解量化原理、掌握量化参数的含义,是后续分析延迟预算、选择量化策略的基石。

量化核心概念关系与映射链路 浮点域 (FP32/FP16) • 权重: [-1.5, 1.5] • 激活: [-5.0, 5.0] • 连续分布 • 高动态范围 量化参数 • Scale (缩放系数) • Zero-Point (零点) • 映射关系: r = S(q - Z) • 决定精度与范围 定点/整数域 (INT8/UINT8) • 权重: [-128, 127] • 激活: [0, 255] • 离散分布 • 硬件高效计算 校准 映射 对称量化 (Symmetric) • Zero-point = 0 • 范围: [-max, max] • 适合权重 (分布近似对称) • 实现简单,推理快 ⚠ 激活值若偏置,精度损失大 非对称量化 (Asymmetric) • Zero-point ≠ 0 • 范围: [min, max] • 适合激活 (如 ReLU 后非负) • 充分利用动态范围 ⚠ 需要额外存储 zero-point

3.1 核心原理:从浮点域到整数域的数学映射

量化的数学本质是一个仿射变换。假设我们有一个浮点张量 r,我们希望将其映射到整数张量 q。两者之间的关系由以下公式定义:

r = S × (q - Z)

其中:

  • S (Scale):浮点缩放系数,表示整数中每个“步长”对应的浮点数值大小。S 是一个正浮点数。
  • Z (Zero-Point):整数零点,表示浮点数值 0.0 对应的整数表示。Z 的数据类型与量化后的整数类型一致(如 INT8 或 UINT8)。
  • q:量化后的整数值。
  • r:原始的浮点数值。

在 Ethos-U NPU 的硬件实现中,卷积运算的乘加操作全部在整数域完成。例如,两个浮点数的乘积 r1 × r2 可以转化为:

r1 × r2 = S1 × (q1 - Z1) × S2 × (q2 - Z2) = (S1 × S2) × (q1 - Z1) × (q2 - Z2)

由于 S1 × S2 在编译期即可预先计算为一个浮点常数,实际推理时只需要执行整数乘法 (q1 - Z1) × (q2 - Z2),最后再乘以该常数并累加偏置。这种设计使得 NPU 的 MAC(乘加)单元可以完全避免浮点运算,从而在相同功耗预算下获得更高的吞吐量。

关键理解:量化并不是简单地“四舍五入”,而是通过 S 和 Z 两个参数,将浮点数的连续分布“压缩”到有限的整数网格上。S 控制压缩的“粒度”,Z 控制压缩的“偏移”。两者共同决定了量化误差的大小。

3.2 定点与浮点:为什么 NPU 偏爱定点运算

浮点运算(FP32/FP16)虽然精度高,但硬件实现复杂,需要专门的浮点运算单元(FPU),且功耗和面积开销大。相比之下,定点运算(如 INT8)只需要简单的整数乘法器和加法器,功耗低、速度快、逻辑门数量少。对于 Ethos-U 这类面向边缘计算的 NPU,其设计目标是在有限的功耗和面积预算内实现最高的 TOPS/W(每瓦特万亿次运算)性能,因此几乎无一例外地采用定点运算。

在模型部署中,我们通常将训练好的 FP32 模型转换为 INT8 模型。这个过程包括:

  1. 权重量化:将卷积层、全连接层的权重从 FP32 转换为 INT8。
  2. 激活量化:将每一层的输出特征图(激活值)从 FP32 转换为 INT8。
  3. 偏置量化:偏置通常保留为 INT32 或 FP32,以避免精度损失,因为偏置的数值范围较大。

值得注意的是,Ethos-U 的硬件累加器通常使用 INT32 或 INT48 来存储中间累加结果,以防止多次乘加操作后的溢出。这意味着,虽然输入和权重是 INT8,但部分和(Partial Sum)的精度更高,最终在输出阶段再通过 Scale 和 Zero-Point 转换回 INT8。

3.3 对称与非对称量化:适用场景与选择依据

根据 Zero-Point 是否为 0,量化可以分为对称量化和非对称量化两种策略。

对比维度 对称量化 非对称量化
Zero-Point 固定为 0 可为任意整数(通常非 0)
映射公式 r = S × q r = S × (q - Z)
数值范围 [-max, max] [min, max]
硬件实现 无需减法操作,计算更快 需要额外的减法操作
典型应用 权重(分布近似对称) 激活值(如 ReLU 后非负)
精度表现 若数据分布偏斜,精度损失大 能更好地利用动态范围,精度更高

在 Ethos-U 的部署流程中,通常对权重采用对称量化,对激活采用非对称量化。这是因为权重经过训练后,其分布通常近似于均值为 0 的高斯分布,对称量化不会浪费整数表示范围;而激活值经过 ReLU 等激活函数后,往往是非负的,使用非对称量化可以将 [0, 5.0] 的范围完整映射到 [0, 255],而对称量化则只能映射到 [-128, 127],导致一半的整数范围被浪费。

实操建议:在 Vela 编译器(Ethos-U 的官方编译器)中,默认配置会自动为权重选择对称量化,为激活选择非对称量化。但在某些特殊层(如 Sigmoid 输出范围 [0,1]),手动调整量化参数可能带来额外的精度提升。

3.4 量化参数 Scale 与 Zero-Point 的计算方法

量化参数的计算依赖于校准数据集(Calibration Dataset)。校准过程通常使用一小部分具有代表性的训练数据(如 100-500 张图片),统计每一层激活值的动态范围。具体计算步骤如下:

  1. 收集统计值:在校准数据集上运行 FP32 模型,记录每一层输出的最小值和最大值(或使用百分位法,如 99.99% 分位数,以排除异常值)。
  2. 计算 Scale:根据目标整数位宽(如 INT8,范围 [-128, 127])计算 Scale。
    # 对称量化
    scale = max(abs(min_val), abs(max_val)) / 127.0
    
    # 非对称量化
    scale = (max_val - min_val) / 255.0
  3. 计算 Zero-Point:
    # 对称量化
    zero_point = 0
    
    # 非对称量化
    zero_point = round(-min_val / scale)  # 然后裁剪到 [0, 255]
  4. 量化与反量化:将浮点值转换为整数,或反向转换。
    # 浮点 -> 整数
    q = round(r / scale) + zero_point
    
    # 整数 -> 浮点
    r = scale * (q - zero_point)
风险提示:如果校准数据集与真实推理数据分布差异较大,会导致 Scale 和 Zero-Point 计算不准确,进而造成严重的精度下降。建议校准数据集应覆盖真实场景中的典型输入,并包含一定的多样性。

3.5 案例拆解:一个 Conv2D 层的量化全过程

假设我们有一个简单的卷积层,输入激活值范围为 [0.0, 6.0],权重范围为 [-1.0, 1.0]。我们使用 INT8 量化(范围 [-128, 127])。

步骤 1:计算量化参数

# 激活(非对称)
act_scale = (6.0 - 0.0) / 255.0 = 0.023529
act_zero_point = round(-0.0 / 0.023529) = 0

# 权重(对称)
w_scale = max(|-1.0|, |1.0|) / 127.0 = 1.0 / 127.0 = 0.007874
w_zero_point = 0

步骤 2:量化具体数值

假设输入激活值 r_act = 3.5,权重 r_w = 0.5。

q_act = round(3.5 / 0.023529) + 0 = round(148.75) = 149
q_w = round(0.5 / 0.007874) + 0 = round(63.5) = 64

步骤 3:整数域计算

乘积 = q_act × q_w = 149 × 64 = 9536

步骤 4:反量化回浮点(用于验证)

乘积_浮点 = act_scale × w_scale × (乘积 - act_zero_point × w_zero_point)
= 0.023529 × 0.007874 × (9536 - 0)
= 0.0001853 × 9536
= 1.767

而原始浮点乘积为 3.5 × 0.5 = 1.75,量化误差约为 0.017,相对误差约 1%。这个误差在可接受范围内。

复盘经验:在实际 Ethos-U 部署中,Vela 编译器会自动处理上述步骤,并生成优化的 C 代码。但理解这个过程有助于我们诊断精度问题。例如,如果发现某层精度异常,可以检查该层的 Scale 是否过大(说明动态范围利用不充分),或者 Zero-Point 是否偏移严重。

3.6 常见误区与总结复盘

  • 误区一:所有层都使用相同的量化参数。实际上,每一层都有独立的 Scale 和 Zero-Point,因为它们的数据分布不同。
  • 误区二:对称量化总是比非对称量化差。对于权重而言,对称量化通常足够且更高效;对于激活,非对称量化更优。选择取决于数据分布。
  • 误区三:校准数据集越大越好。过大的校准集可能导致过拟合于校准数据的分布,而忽略了真实场景的多样性。通常 100-500 个样本足够。
  • 误区四:忽略偏置的量化。偏置通常不量化到 INT8,而是保留 INT32,否则累加误差会迅速累积。