4、特征向量与模型输入:什么是特征向量、模型输入格式要求、常见数据类型(float32、q7、q15、q31)
在嵌入式机器学习与数字信号处理(DSP)系统中,模型推理的起点并非算法本身,而是数据如何被组织、量化并送入模型。CMSIS-DSP 作为 ARM Cortex-M 系列处理器上的官方 DSP 库,其核心任务之一就是高效地完成特征向量的预处理与格式转换。理解特征向量的本质、模型输入的内存布局要求,以及 q7、q15、q31 等定点数据类型的数学含义,是确保模型在资源受限设备上正确、高效运行的前提。本章将系统拆解这三个关键环节,并给出可落地的工程实践指南。
4.1 特征向量的本质与构建
特征向量是原始信号经过变换、降维或统计提炼后形成的数值序列,它是模型推理的直接输入。在 CMSIS-DSP 语境下,特征向量通常以数组形式存储于内存中,每个元素代表一个维度的特征值。例如,一个 256 点的 FFT 频谱幅值序列、一组 MFCC 倒谱系数、或由加速度计三轴数据计算出的均值、方差、峰值等统计量,都可以构成特征向量。
构建特征向量时,必须遵循以下原则:
- 维度固定:模型输入维度是编译期常量,特征向量长度必须严格匹配。若使用 CMSIS-DSP 的 arm_mat_* 矩阵函数,还需注意行/列主序。
- 数值范围可控:浮点特征值应归一化到 [-1, 1] 或 [0, 1] 区间,以便后续定点量化时充分利用动态范围。
- 物理意义明确:每个维度应具有可解释性,避免冗余或高度相关的特征导致模型训练不稳定。
4.2 模型输入的格式要求
不同推理框架(如 TensorFlow Lite Micro、CMSIS-NN、自研 C 代码)对输入张量的内存布局有严格约定。常见要求包括:
| 格式项 | 要求说明 | CMSIS-DSP 对应操作 |
|---|---|---|
| 数据连续性 | 特征数据必须存储在连续内存块中,不能有间隔 | arm_copy_f32 / arm_fill_q15 |
| 字节对齐 | 通常要求 4 字节对齐(q31/float32)或 2 字节对齐(q15) | 使用 __ALIGNED(4) 或 CMSIS 提供的 ALIGN_STRUCT |
| 通道布局 | 多通道数据需按 CHW(通道-高-宽)或 HWC 排列 | arm_transpose_q15 进行矩阵转置 |
| 量化参数 | 定点模型需提供 scale 和 zero_point | arm_scale_q31 / arm_offset_q7 |
在 Cortex-M 处理器上,非对齐访问会导致 HardFault 或性能骤降。因此,定义特征向量缓冲区时,应使用 __ALIGNED(4) 或 alignas(4) 属性。CMSIS-DSP 的许多函数(如 arm_cfft_f32)要求输入输出缓冲区 4 字节对齐,否则结果不可预测。
4.3 常见数据类型深入解析
CMSIS-DSP 支持三种定点格式和一种浮点格式,每种格式在精度、内存占用和运算速度上各有取舍。
4.3.1 float32(单精度浮点)
float32 是 Cortex-M4/M7/M33 等带有 FPU(浮点运算单元)器件的首选类型。其动态范围极大,无需担心溢出,但内存占用为 4 字节/样本,且在没有 FPU 的 Cortex-M0/M0+ 上,软件浮点模拟会非常缓慢。使用场景包括:音频处理中的中间计算、模型训练的离线仿真、以及精度要求极高的控制环路。
4.3.2 q31(1.31 定点格式)
q31 将 32 位有符号整数解释为 [-1, 1) 区间的小数,最低位(LSB)代表 2^-31。它保留了 float32 的内存占用,但运算完全基于整数指令,在无 FPU 的芯片上速度远快于软件浮点。q31 常用于需要高精度的 DSP 算法,如 PID 控制器、IIR 滤波器。CMSIS-DSP 提供 arm_q31_to_float 和 arm_float_to_q31 进行互转,转换时需指定缩放因子(通常为 2^31)。
4.3.3 q15(1.15 定点格式)
q15 使用 16 位存储,LSB 代表 2^-15,精度约为 3.05e-5。它是音频处理和通信基带的经典格式,因为 16 位 ADC/DAC 的原始数据天然就是 q15 格式。CMSIS-DSP 的 FIR、IIR、FFT 等函数均有 q15 版本,且支持饱和运算(arm_sat_q15),防止溢出。内存占用仅为 float32 的一半,适合存储大量采样数据。
4.3.4 q7(1.7 定点格式)
q7 是 8 位定点格式,LSB 代表 2^-7,精度约 7.81e-3。它主要用于神经网络推理(CMSIS-NN 库)和传感器数据预处理。由于内存占用极小(1 字节/样本),可以在 RAM 有限的 MCU 上容纳更大的特征图。但精度较低,使用时需确保输入数据已归一化到 [-1, 1] 且分布均匀,否则量化误差会显著影响模型精度。
__SSAT 指令或 CMSIS 提供的饱和宏,否则会产生不可预测的环绕行为。
4.4 实战场景:从 float32 特征到 q7 模型输入的转换
假设我们有一个基于 Cortex-M4 的振动监测设备,采集 3 轴加速度数据,每轴提取 8 个频域特征(共 24 维特征向量)。模型输入要求为 q7 格式,且每个特征需归一化到 [-1, 1]。
初始现象:直接使用 float32 特征送入 CMSIS-NN 模型,推理时间 12ms,但 RAM 占用 96 字节(24×4),且模型精度仅 89%。
目标:将特征转换为 q7,RAM 降至 24 字节,推理时间缩短至 5ms,精度损失不超过 1%。
操作步骤:
- 离线统计:在 PC 端对 10000 组训练样本计算每个维度的最大值和最小值,得到 scale[i] = max(abs(min), abs(max)),用于归一化。
- 浮点归一化:在 MCU 上,对每个特征 f[i] 执行
f_norm[i] = f[i] / scale[i],确保结果在 [-1, 1] 内。 - 转换为 q7:调用
arm_float_to_q7(f_norm, q7_buffer, 24, 1),其中第 4 个参数为缩放因子(此处为 1,因为已归一化)。 - 验证:将 q7 数据反变换回 float,计算最大误差。若误差超过 0.01,则需检查是否有特征值超出归一化范围。
结果对比:
| 指标 | float32 | q7 | 变化 |
|---|---|---|---|
| RAM 占用 | 96 B | 24 B | -75% |
| 推理时间 | 12 ms | 5 ms | -58% |
| 模型精度 | 89% | 88.2% | -0.8% |
复盘经验:q7 量化误差主要来源于归一化不充分。若某个特征在训练集中最大值为 0.8,但实际部署时出现 0.9 的异常值,则会被饱和截断为 0.992(q7 最大值),导致信息丢失。解决方案是保留 10% 的头部裕量,即 scale[i] 乘以 1.1 的安全系数。
4.5 常见误区与总结
- 误区一:所有数据都适合 q7。若特征值分布极不均匀(如大部分接近 0,少数接近 ±1),q7 的均匀量化会浪费大量动态范围。此时应使用非均匀量化或考虑 q15。
- 误区二:忽略字节对齐。CMSIS-DSP 的 FFT 函数要求缓冲区 4 字节对齐,若使用
uint8_t数组存储 q7 数据,再强制转换为q7_t*,可能导致对齐错误。应使用__ALIGNED(4) static q7_t buffer[24]。 - 误区三:转换时忘记缩放因子。
arm_float_to_q31的第 4 个参数是缩放因子,若设为 1,则浮点 0.5 会转换为整数 0(因为 0.5×1=0.5,取整为 0),造成严重失真。正确做法是传入 2^31 或 2^15。 - 误区四:混合使用不同定点格式。在同一个计算图中,q15 和 q31 不能直接相加,必须先统一格式。CMSIS-DSP 提供
arm_q15_to_q31等转换函数,但会引入额外开销。