量化(Quantization)是将深度学习模型中的浮点数参数(如权重、偏置、激活值)转换为低精度定点数表示的过程。在训练阶段,模型通常使用32位浮点数(FP32)来表示参数,以获得最高的数值精度。然而,当模型需要部署到资源受限的微控制器(MCU)上时,FP32的存储和计算开销往往难以承受。
量化的本质是一种数值映射:将连续的浮点值域离散化为有限个整数值。以INT8量化为例,FP32的数值范围被映射到[-128, 127]共256个离散级别上。虽然精度有所损失,但存储需求降低为原来的1/4,计算速度在支持整数运算的硬件上可提升2~4倍。
其中 scale 是缩放因子,表示每个整数级别对应的浮点数值跨度;zero_point 是零点,表示浮点数值0所对应的整数值。通过这两个参数,可以精确地描述浮点值与整数值之间的映射关系。
量化过程可以理解为对浮点数轴的"采样"。假设一组浮点权重值为 [-1.2, -0.5, 0.0, 0.3, 1.8],在INT8对称量化下(zero_point=0),scale = max(|value|) / 127 = 1.8 / 127 ≈ 0.01417。那么 0.3 量化后为 round(0.3 / 0.01417) = 21,反量化后为 21 × 0.01417 = 0.2976,存在约0.0024的误差。
MCU的资源限制是量化的根本驱动力。以下表格对比了典型MCU与GPU/服务器的资源差异:
| 资源维度 | STM32H7 (Cortex-M7) | 典型GPU服务器 | 差距倍数 |
|---|---|---|---|
| Flash存储 | 2 MB | 1 TB+ | 500,000x |
| SRAM | 1 MB | 40 GB+ | 40,000x |
| 计算频率 | 480 MHz | 1.5 GHz × 10000+ cores | >30,000x |
| 功耗 | < 1W | 300W+ | 300x |
| 浮点单元 | 单/双精度FPU | 专用Tensor Core | 架构差异巨大 |
一个典型的MobileNetV1模型在FP32下约16MB,远超STM32H7的2MB Flash。通过INT8量化,模型体积可压缩到约4MB,再配合内存优化技术,才能成功部署到MCU上。
对称量化(Symmetric Quantization)将浮点零值映射到整数零值,即 zero_point = 0。量化公式简化为:
对称量化的优点是计算简单,不需要额外的零点偏移运算,在矩阵乘法中效率更高。缺点是当数据分布不对称时(例如ReLU激活后的值全为正),会浪费一部分量化范围。
非对称量化(Asymmetric Quantization)允许 zero_point ≠ 0,可以更精确地覆盖数据的实际分布范围:
非对称量化在数据分布偏移较大时效果更好,例如经过ReLU激活后的非负值域。但计算时需要额外减去零点,增加了少量计算开销。
| 特性 | 对称量化 | 非对称量化 |
|---|---|---|
| zero_point | 0 | 可为任意整数 |
| 计算复杂度 | 低(无需偏移) | 略高(需减零点) |
| 数据适配性 | 对称分布最优 | 任意分布均可 |
| 典型应用 | 权重量化 | 激活值量化 |
| STM32Cube.AI支持 | 支持 | 支持 |
逐层量化(Per-Tensor Quantization)对整个张量使用一组 scale 和 zero_point。实现简单,但当不同通道的数值范围差异较大时,量化误差会增大。
逐通道量化(Per-Channel Quantization)为每个输出通道维护独立的 scale 和 zero_point。例如,一个卷积核有64个输出通道,则需要64组量化参数。这显著提高了量化精度,因为每个通道的数值范围被独立适配。
拖动下方滑块调整 scale 和 zero_point 参数,观察浮点数如何映射到INT8整数值。上方数轴显示浮点值,下方数轴显示量化后的INT8值,连线展示映射关系。
拖动滑块调整参数,观察量化映射变化
训练后量化(Post-Training Quantization, PTQ)是最简单的量化方法:模型训练完成后,直接对已训练好的浮点参数进行量化转换,无需重新训练。
PTQ的工作流程:
适用场景:模型结构较简单、精度裕度较大(如当前精度98%,目标精度95%即可)、无法获取训练数据或对量化流程不熟悉的场景。在STM32Cube.AI中,默认的量化方式就是PTQ。
量化感知训练(Quantization-Aware Training, QAT)在训练过程中模拟量化的效果,让模型在训练阶段就"适应"量化带来的精度损失。
QAT的核心思想:在前向传播时插入"伪量化"(Fake Quantization)节点,模拟INT8的量化效果;反向传播时使用直通估计器(Straight-Through Estimator, STE)将梯度直接传递通过伪量化节点,使网络参数能够学习如何补偿量化误差。
QAT的工作流程:
动态量化(Dynamic Quantization):权重在部署前预先量化为低精度,但激活值在运行时动态量化。每次推理时,先观察激活值的实际范围,再计算量化参数。优点是简单、无需校准数据;缺点是运行时额外开销较大。
静态量化(Static Quantization):权重和激活值都在部署前量化。激活值的量化参数通过校准数据集预先确定,运行时直接使用固定的量化参数。优点是推理速度快(无运行时量化开销);缺点是需要代表性的校准数据。
| 特性 | 动态量化 | 静态量化 |
|---|---|---|
| 权重量化 | 离线完成 | 离线完成 |
| 激活量化 | 运行时动态 | 离线校准确定 |
| 推理速度 | 较慢(额外开销) | 较快 |
| 需要校准数据 | 不需要 | 需要 |
| 精度稳定性 | 随输入波动 | 稳定可预测 |
| MCU适用性 | 不太适合 | 推荐 |
混合精度量化(Mixed-Precision Quantization)允许模型的不同层使用不同的量化精度。核心思想是:并非所有层对量化都同样敏感。例如,第一层卷积和最后一层全连接层通常对量化更敏感,可以保持较高精度(如INT16或FP16),而中间层可以使用INT8甚至INT4。
混合精度的确定方法:
STM32Cube.AI支持混合精度配置,用户可以在转换时为不同层指定不同的目标精度。工具会自动处理精度转换和数据格式适配。
决策流程:
选择不同模型,查看PTQ、QAT、混合精度三种策略在模型大小、推理速度、精度保持、实现难度四个维度的对比。
点击上方按钮切换不同模型的对比数据
| 指标 | FP32 | FP16 | INT8 |
|---|---|---|---|
| 数值精度 | 7位有效数字 | 3~4位有效数字 | 整数,无小数 |
| 动态范围 | ±3.4×1038 | ±65504 | -128 ~ 127(需scale还原) |
| 单参数存储 | 4 字节 | 2 字节 | 1 字节 |
| 模型体积(以16MB模型为例) | 16 MB | 8 MB | 4 MB |
| MAC运算速度 | 基准 1x | 1.5~2x(有FPU时) | 2~4x(DSP/加速器) |
| 典型精度损失 | 无 | < 0.1% | 0.5% ~ 3% |
| MCU支持 | 广泛支持 | 部分Cortex-M7支持 | DSP指令/软件模拟 |
量化对推理速度的提升主要来自三个方面:
实际加速比取决于模型结构和硬件平台。对于内存密集型模型(如深层网络),加速比更明显;对于计算密集型模型,加速比可能受限于计算单元本身。
量化引起的精度损失主要来自两个来源:
影响精度损失的因素:
| 因素 | 精度损失小 | 精度损失大 |
|---|---|---|
| 模型大小 | 大模型(参数冗余多) | 小模型(每个参数都重要) |
| 任务难度 | 简单任务(精度裕度大) | 困难任务(精度裕度小) |
| 网络深度 | 浅层网络 | 深层网络(误差累积) |
| 数值分布 | 分布集中、均匀 | 分布分散、有离群值 |
| 量化位数 | INT16/INT12 | INT4/INT3 |
量化校准(Calibration)是静态量化中的关键步骤,其目的是使用一组代表性数据来确定各层激活值的量化参数。
校准过程:
校准算法的选择:
当量化导致精度损失过大时,可以采用以下精度恢复技术:
权重共享(也称为权重聚类,Weight Clustering)是将模型中相近的权重值合并为相同的值,从而减少唯一权重值的数量。合并后的权重可以使用更少的位数进行编码,同时通过查找表(Codebook)还原实际值。
工作原理:
权重共享可以与量化结合使用。例如,一个FP32权重(4字节)经过256簇的权重共享后,只需1字节的索引 + 查找表(256 × 4字节 = 1KB)。对于大层,查找表的开销可以忽略不计。
网络剪枝是移除模型中"不重要"的连接或结构,以减小模型体积和计算量。
剪枝的层次:
在MCU上,RAM是极其宝贵的资源。内存优化的核心目标是最小化峰值RAM使用量。
缓冲区复用(Buffer Reuse):神经网络推理时,并非所有层的激活值都需要同时保存。当某一层的输出被下一层消费后,该层的输入缓冲区就可以被释放并复用。通过分析层的依赖关系(即"生命周期分析"),可以让不同层的激活值共享同一块内存区域。
内存池管理(Memory Pool):STM32Cube.AI采用静态内存分配策略,在编译时确定所有缓冲区的大小和位置。运行时不需要动态内存分配(malloc/free),避免了内存碎片和不确定性。所有激活值缓冲区被组织在一个连续的内存池中。
内存优化的关键策略:
STM32Cube.AI在模型转换过程中自动执行以下内存优化:
在STM32Cube.AI的转换报告中,会详细列出优化前后的内存使用情况,包括:
以下是一个基于MobileNetV1(输入224x224,1000类分类)在STM32H743上的部署优化案例:
| 指标 | 优化前(FP32) | 量化后(INT8) | 优化后(INT8+优化) |
|---|---|---|---|
| Flash占用 | 16.8 MB | 4.2 MB | 3.8 MB |
| RAM占用(峰值) | 2.1 MB | 1.1 MB | 0.68 MB |
| 推理延迟 | 1200 ms | 380 ms | 290 ms |
| Top-1精度 | 71.3% | 70.8% | 70.8% |
| 能耗/次推理 | ~360 mJ | ~114 mJ | ~87 mJ |
优化过程分析:
最终模型成功部署到STM32H743(2MB Flash, 1MB RAM)上,还有充足的余量用于其他功能。
点击"开始优化"按钮,观察Flash和RAM的内存布局从优化前(FP32)到优化后(INT8+剪枝+复用)的变化过程。
点击"开始优化"查看内存布局的动态变化