1. AI模型量化基础:从浮点到整数的思维转变

各位同学,咱们今天聊聊模型量化。说实话,我第一次接触这个概念时,也觉得不就是把32位浮点数砍成8位整数嘛,能有多复杂?直到我在一个电池供电的穿戴设备项目上栽了跟头——模型跑在STM32上,推理一次要3秒,功耗根本压不住。后来用了量化,推理时间降到200毫秒,功耗直接砍掉70%。嗯,从那以后,我再也不敢小看量化了。

1.1 什么是模型量化

模型量化,说白了就是给神经网络模型“减肥”。

一个典型的深度学习模型,参数都是32位浮点数(FP32)存储的。比如权重是0.12345678,偏置是-0.98765432。这些数字在PC上跑没问题,但到了STM32这种资源受限的MCU上,就尴尬了——Flash不够、RAM不够、算力也不够。

量化的核心思路:用更少的比特数来表示模型的参数和激活值。最常见的是从FP32降到INT8,也就是8位整数。这样一来:

  • 模型体积缩小4倍:32位→8位,立竿见影
  • 内存带宽需求降低4倍:每次搬运的数据量少了
  • 推理速度提升2-4倍:整数运算比浮点运算快得多
  • 功耗显著下降:少搬数据、少做计算,电池自然更耐用

关键认知:量化不是“压缩”,而是“重新编码”。它保留了模型的结构和连接关系,只是改变了数值的表示方式。就像你用中文和英文描述同一件事,意思不变,但表达方式不同。

1.2 量化的数学原理

量化的数学基础其实不复杂。我习惯把它拆成两个问题:

  1. 怎么把浮点数映射到整数范围?
  2. 做完整数运算后,怎么还原回浮点数?

这里有两个核心概念:缩放因子(Scale)和零点(Zero Point)。

1.2.1 非对称量化

非对称量化是最通用的方案。它的映射公式长这样:

量化值 = round(浮点值 / 缩放因子) + 零点

反量化:浮点值 = (量化值 - 零点) × 缩放因子

其中:

  • 缩放因子 = (浮点最大值 - 浮点最小值) / (整数最大值 - 整数最小值)
  • 零点 = 整数最小值 - round(浮点最小值 / 缩放因子)

举个例子。假设我们有一组权重:[-1.5, 0.0, 3.2, 7.8],要量化到INT8范围[-128, 127]:

浮点范围 = 7.8 - (-1.5) = 9.3
整数范围 = 127 - (-128) = 255
缩放因子 = 9.3 / 255 ≈ 0.03647

零点 = -128 - round(-1.5 / 0.03647)
     = -128 - round(-41.13)
     = -128 - (-41)
     = -87

量化 -1.5:round(-1.5/0.03647) + (-87) = -41 - 87 = -128
量化 0.0:round(0.0/0.03647) + (-87) = 0 - 87 = -87
量化 3.2:round(3.2/0.03647) + (-87) = 88 - 87 = 1
量化 7.8:round(7.8/0.03647) + (-87) = 214 - 87 = 127

你看,-1.5映射到了-128,7.8映射到了127,整个整数范围被充分利用了。

我的经验:非对称量化适合ReLU这类激活函数输出全为正数的情况。因为零点可以偏移,不会浪费整数范围。我在做图像分类模型时,90%的情况都用非对称量化。

1.2.2 对称量化

对称量化就简单多了。它假设浮点范围关于0对称,所以零点固定为0:

量化值 = round(浮点值 / 缩放因子)

反量化:浮点值 = 量化值 × 缩放因子

缩放因子 = max(|浮点最小值|, |浮点最大值|) / 整数最大值

还是上面那组数据:[-1.5, 0.0, 3.2, 7.8]:

最大绝对值 = max(|-1.5|, |3.2|, |7.8|) = 7.8
缩放因子 = 7.8 / 127 ≈ 0.06142

量化 -1.5:round(-1.5/0.06142) = round(-24.42) = -24
量化 0.0:round(0.0/0.06142) = 0
量化 3.2:round(3.2/0.06142) = round(52.10) = 52
量化 7.8:round(7.8/0.06142) = round(127.0) = 127

注意看,-1.5只映射到了-24,而整数范围的下限-128根本没用到。这就是对称量化的缺点——如果数据分布不对称,会浪费一部分整数表示能力。

避坑指南:我曾经在一个语音识别模型上用了对称量化,结果精度掉了5%。后来发现是因为激活值全是正数,对称量化浪费了一半的整数范围。换成非对称量化后,精度损失降到了0.3%。所以,选哪种量化方式,先看看你的数据分布。

1.2.3 两种量化方式的对比

对比维度 非对称量化 对称量化
零点 非零,需要额外存储 固定为0,无需存储
整数范围利用率 高,适合任意分布 低,数据偏置时浪费严重
计算复杂度 稍高(需处理零点偏移) 低(乘法后直接累加)
硬件友好度 一般 高,很多硬件原生支持
典型应用场景 激活值量化、权重分布不对称 权重量化、硬件加速器

1.3 量化精度与性能的权衡

量化不是免费的午餐。你省了存储和计算,但代价是精度损失。为什么会这样?

原因很简单:量化是一个有损过程。把32位浮点数映射到8位整数,相当于把4.3亿种可能的取值压缩到256种。这中间必然有信息丢失。

我习惯用一个指标来衡量量化损失——量化误差:

量化误差 = |原始浮点值 - 反量化后的浮点值|

回到刚才的例子,看看-1.5的量化误差:

非对称量化:
  反量化值 = (-128 - (-87)) × 0.03647 = -41 × 0.03647 ≈ -1.495
  误差 = |-1.5 - (-1.495)| = 0.005

对称量化:
  反量化值 = -24 × 0.06142 ≈ -1.474
  误差 = |-1.5 - (-1.474)| = 0.026

你看,对称量化的误差是非对称的5倍多。这就是为什么数据分布很重要。

核心权衡关系:

  • 位宽越高,精度越好,但压缩比越低:INT4比INT8压缩比高,但精度损失也大
  • 量化粒度越细,精度越好,但计算开销越大:逐层量化比逐通道量化精度高,但需要更多缩放因子
  • 校准数据集越大,量化效果越好,但耗时越长:1000张图片比100张图片更能反映真实分布

在实际项目中,我一般这样权衡:

  • 对精度极其敏感的任务(如医疗诊断):用INT8逐通道量化,配合校准数据集微调
  • 对性能要求高的任务(如实时控制):用INT4对称量化,接受1-2%的精度损失
  • 存储极度受限的场景(如BLE设备):用INT4甚至二值化,牺牲精度换体积

我的建议:别一上来就追求极致压缩。先做INT8量化,看看精度损失。如果损失在1%以内,就够用了。如果损失太大,再考虑逐通道量化或量化感知训练。我在一个手势识别项目上,INT8量化只掉了0.3%的精度,完全够用,根本没必要上更复杂的方案。

1.4 量化知识体系总览

下面这张图把本章的核心知识点串起来了。你可以把它当作量化的“思维导图”:

模型量化知识体系 模型量化 什么是量化 量化数学原理 精度与性能权衡 FP32→INT8 模型体积缩小4倍 推理加速2-4倍 功耗降低70% 非对称量化 对称量化 缩放因子 + 零点 位宽选择 量化粒度 校准数据集 量化误差 核心原则:在精度损失可接受的前提下,追求极致的存储和计算效率 量化不是目的,部署到嵌入式设备上跑起来才是目的

这张图把量化拆成了三个维度:是什么、怎么算、怎么权衡。后面几章我们会逐一深入每个子节点,但今天先把骨架搭好。

本章小结:

  • 量化是用更少的比特数表示模型参数,核心是FP32→INT8
  • 非对称量化适合任意数据分布,对称量化计算更简单
  • 量化必然有精度损失,关键是把损失控制在可接受范围内
  • 选择量化方案前,先分析你的数据分布和硬件能力