4. Fully Connected Layer数学基础:矩阵乘法、权重与激活的int8表示、累加器精度要求、输出反量化流程
Fully Connected(FC)层在神经网络中承担特征空间变换与分类决策的职责,其数学本质是矩阵乘法与偏置加法的组合。在CMSIS-NN的int8推理路径中,FC层并非简单地将浮点权重替换为整数,而是涉及一整套量化数学体系的重新构建:权重与激活如何映射到int8域、累加器需要多少位宽才能避免溢出、输出如何从int32累加结果反量化回浮点或直接映射到下一层所需的int8范围。本章从数学基础出发,逐步拆解FC层在int8量化推理中的完整计算链路,为后续kernel调优提供理论支撑。
上图展示了FC层int8推理的完整数学链路。输入激活与权重分别以int8格式存储,各自携带scale和zero point参数;矩阵乘法在int32累加器中进行,累加结果与偏置相加后,通过反量化步骤映射回目标输出范围。整个过程涉及三个关键数学问题:量化表示的正确性、累加器的精度保障、反量化流程的数值稳定性。下面逐一展开。
4.1 矩阵乘法的量化表示
核心原理:FC层的数学运算为 y = W·x + b,其中W为[Cout, Cin]权重矩阵,x为[1, Cin]输入向量,b为[Cout]偏置。在int8量化推理中,浮点值被映射到整数域:x_f = s_x·(x_q - z_x),w_f = s_w·(w_q - z_w),其中s为scale(缩放因子),z为zero point(零点偏移)。将浮点表达式代入矩阵乘法,得到整数域运算公式:
y_f = Σ s_w·(w_q - z_w) · s_x·(x_q - z_x) + b_f
= (s_x · s_w) · Σ (w_q - z_w)·(x_q - z_x) + b_f
实际kernel实现中,通常将zero point预先减掉,即预先计算 w_eff = w_q - z_w,x_eff = x_q - z_x,然后执行纯整数矩阵乘法。偏置b在量化时直接以int32格式存储,其量化scale为s_x·s_w,因此累加结果加上偏置后仍保持int32精度。
判断方法:在CMSIS-NN的arm_fully_connected_s8函数中,输入激活的zero point通常为-128(对称量化)或0(非对称量化),权重的zero point通常为0(对称量化)。判断一个FC层是否适合int8推理,需要检查:
- 输入输出通道数是否在int8可表示范围内(激活值域[-128, 127])
- 权重分布是否均匀,是否存在极端离群值导致量化误差过大
- 累加器位宽是否足够(见4.3节)
4.2 权重与激活的int8表示策略
核心原理:int8表示将浮点数值映射到[-128, 127]的整数区间。对于权重矩阵W,量化参数s_w和z_w在训练后校准阶段确定。常见策略包括:
| 策略 | 公式 | 适用场景 | CMSIS-NN支持 |
|---|---|---|---|
| 对称量化 | s = max(|W|)/127, z = 0 | 权重分布近似对称 | 原生支持 |
| 非对称量化 | s = (max-min)/255, z = round(-min/s) | 激活分布偏斜 | 需额外处理 |
| per-tensor | 整个张量共享一组scale/zero | 小模型、通道间差异小 | 默认模式 |
| per-channel | 每个输出通道独立scale | 权重通道差异大 | CMSIS-NN v1.4+ |
操作流程:在CMSIS-NN中,权重通常以int8数组存储,布局为[Cout, Cin]行主序。对于per-channel量化,每个输出通道的scale单独存储,kernel在累加时需按通道应用不同scale。激活的int8表示则依赖前一层输出的量化参数,在FC层输入前已完成量化。
案例拆解:假设一个FC层,Cin=256,Cout=128。权重浮点范围为[-0.5, 0.5],采用对称量化:s_w = 0.5/127 ≈ 0.00394,z_w = 0。激活浮点范围为[-1.0, 2.0],采用非对称量化:s_x = 3.0/255 ≈ 0.01176,z_x = round(1.0/0.01176) ≈ 85。则整数域计算中,x_eff = x_q - 85,w_eff = w_q。累加结果acc = Σ w_eff·x_eff,最终输出scale为s_x·s_w ≈ 4.63e-5。
4.3 累加器精度要求
核心原理:FC层的累加操作在int32累加器中进行。int8×int8乘法结果最大为127×127=16129,累加Cin个乘积后,理论最大绝对值为16129×Cin。int32累加器范围为[-2^31, 2^31-1] ≈ ±2.147e9。因此安全条件为:
|acc_max| = 16129 × Cin ≤ 2^31 - 1
Cin ≤ 2^31 / 16129 ≈ 133,120
实际中,由于权重和激活的分布并非极端值,Cin通常远小于该上限。但CMSIS-NN的kernel实现中,累加器使用int32_t类型,且部分优化(如SIMD)可能使用int16中间结果,需额外注意。
判断方法:在调优前,应检查FC层的Cin是否超过安全阈值。对于Cin > 4096的层,建议使用以下公式估算最大累加值:
- 统计权重的绝对值最大值|w_max|和激活的绝对值最大值|x_max|
- 计算理论最大累加值:acc_max = |w_max| × |x_max| × Cin
- 若acc_max > 2^31 - 1,则存在溢出风险,需考虑per-channel量化或int16累加
实战场景:在语音唤醒词模型中,最后一层FC通常将特征维度从512映射到分类数(如10)。Cin=512,即使权重和激活均为极端值127,acc_max = 127×127×512 ≈ 8.25e6,远小于int32上限,安全。但在视觉模型中,某些FC层Cin可达4096或更高,需仔细校验。
4.4 输出反量化流程
核心原理:FC层输出y_f = acc × (s_x × s_w) + b_f。在int8推理中,输出需要量化到下一层所需的int8范围:y_q = y_f / s_y + z_y。将两者合并,得到融合公式:
y_q = acc × (s_x × s_w / s_y) + z_y
= acc × M + B
其中M = (s_x × s_w) / s_y,B = z_y。M为浮点数,在CMSIS-NN中通过定点近似实现:M ≈ M0 × 2^(-n),其中M0为int32定点数,n为移位位数。反量化流程包含三个步骤:
- 定点乘法:acc × M0,结果为int64中间值
- 右移:结果右移n位,恢复M的实际大小
- 加偏置与裁剪:加上B,并裁剪到[-128, 127]范围
操作流程:CMSIS-NN中,反量化参数M0和n在模型转换时预先计算并存储在权重结构体中。kernel执行时,对每个输出元素执行:
int32_t acc = ...; // 累加结果
int32_t tmp = (int32_t)((int64_t)acc * M0 >> n);
int8_t out = (int8_t)CLAMP(tmp + B, -128, 127);
案例拆解:假设s_x=0.05, s_w=0.02, s_y=0.1,则M = 0.05×0.02/0.1 = 0.01。选择n=8,则M0 = round(0.01 × 2^8) = round(2.56) = 3。实际M_approx = 3/256 ≈ 0.01172,相对误差约17%。若n=16,M0 = round(0.01×65536) = 655,M_approx = 655/65536 ≈ 0.009995,误差小于0.05%。因此n的选择直接影响输出精度。
4.5 常见误区与总结复盘
常见误区:
- 误区一:认为int8量化后精度必然下降。实际上,通过合理的scale选择与校准,FC层在分类任务中精度损失可控制在0.5%以内。
- 误区二:忽略zero point的影响。非对称量化中,zero point不为0时,矩阵乘法需先减去zero point,否则会产生固定偏移误差。
- 误区三:累加器溢出只考虑理论最大值。实际中,权重和激活的分布通常远小于极端值,但若存在离群值(outlier),可能导致局部溢出。
- 误区四:反量化M值直接用浮点计算。CMSIS-NN要求M为定点数,浮点乘法在Cortex-M上性能极差,必须使用定点近似。
总结复盘:FC层的int8数学基础可归纳为三个核心公式:
1. 整数矩阵乘法: acc = Σ (w_q - z_w)·(x_q - z_x)
2. 累加器约束: |acc| ≤ 2^31 - 1, 即 Cin ≤ 133120(理论极限)
3. 反量化: y_q = round(acc × M0 / 2^n) + z_y, 裁剪到int8范围
在CMSIS-NN调优中,应优先检查:权重是否对称量化(简化计算)、Cin是否超过安全阈值、M0的定点精度是否足够(n≥16)、输出裁剪是否与激活函数匹配。这些数学基础决定了kernel实现的正确性与性能上限。
--post_training_quantize并检查FC层的量化参数。若发现某层精度异常,优先检查该层的scale是否过小(导致M0舍入误差大),或zero point是否偏离0(导致计算复杂度增加)。在CMSIS-NN中,可通过arm_fully_connected_s8的返回值检查累加器是否溢出(函数内部有饱和处理,但溢出会降低精度)。