3. 量化方法

好,咱们今天聊聊量化的具体玩法。说白了,量化就是把模型里那些浮点数(FP32)硬塞进INT8的小盒子里。怎么塞?这里头就有讲究了。

我个人习惯把量化方法分成两个维度来理解:一个是缩放方式(对称 vs 非对称),另一个是粒度(逐层 vs 逐通道)。这两个维度组合起来,基本就覆盖了90%以上的INT8落地场景。

3.1 对称量化 vs 非对称量化

先看缩放方式。你想想看,一个FP32的数值范围是[-∞, +∞],但INT8只能表示[-128, 127]或者[0, 255]。怎么映射?

对称量化,就是让零点(zero point)固定在0。也就是说,FP32的0对应INT8的0。这样做的好处是计算简单,没有零点偏移,卷积、矩阵乘这些操作可以直接用INT8算,不用额外处理零点。

但问题来了——如果模型权重分布不对称怎么办?比如某个卷积核的权重全在正数区间,对称量化就会浪费掉INT8的负数部分。我在项目中遇到过这种情况,一个层的权重范围是[0.01, 0.5],对称量化后有效精度直接砍半。

非对称量化就灵活多了。它允许零点偏移,FP32的0可以映射到INT8的任意值。这样就能充分利用INT8的整个表示范围。代价呢?计算时多一步零点减法,硬件实现稍微复杂一点。

核心区别一句话:

  • 对称量化:零点固定为0,计算快,适合权重分布对称的场景
  • 非对称量化:零点可偏移,精度高,适合激活值分布不对称的场景

嗯,这里要注意:激活值(activation)通常是非对称的(比如ReLU后全是正数),所以激活量化我建议用非对称。权重呢?大部分预训练模型的权重分布接近对称,用对称量化就够了。

3.2 逐层量化 vs 逐通道量化

接下来是粒度问题。说白了就是:一个层里,我用一个缩放因子管所有通道,还是每个通道各管各的?

逐层量化,就是整个层共享一个scale和zero point。实现简单,硬件友好,内存占用小。但问题也很明显——如果某个通道的数值范围特别大,其他通道就得跟着吃亏。

举个例子:一个卷积层有64个输出通道,其中63个通道的权重范围是[-0.1, 0.1],但第64个通道范围是[-1.0, 1.0]。逐层量化时,scale会被第64个通道拉大10倍,其他63个通道的精度就白白损失了。

逐通道量化,就是每个通道独立计算scale和zero point。精度提升很明显,尤其对深度可分离卷积、分组卷积这类结构。代价呢?需要存储更多的scale参数,硬件设计也更复杂。

我的经验:

我曾经在一个MobileNetV3的量化项目里,逐层量化掉点2.3%,换成逐通道量化后只掉点0.4%。所以对于轻量级模型,逐通道量化几乎是必选项。

3.3 四种组合怎么选?

把上面两个维度组合起来,就是四种方案:

组合 权重量化 激活量化 典型场景
对称+逐层 ✅ 常用 ❌ 不推荐 大模型、硬件受限场景
对称+逐通道 ✅ 推荐 ❌ 不推荐 通用场景,精度敏感
非对称+逐层 ❌ 不推荐 ✅ 可用 激活值分布极不对称
非对称+逐通道 ✅ 可用 ✅ 推荐 高精度要求,硬件支持

避坑指南:

我曾经在一个项目里对权重用了非对称+逐通道量化,结果硬件不支持零点偏移的权重计算,推理速度反而慢了30%。所以选方案前,一定先确认你的推理芯片支持什么。

3.4 知识体系总览

下面这张图帮你理清思路:

INT8量化方法体系 量化方法 缩放方式 量化粒度 对称量化 非对称量化 逐层量化 逐通道量化 对称+逐层 大模型、硬件受限 对称+逐通道 通用场景,精度敏感 非对称+逐层 激活值极不对称 非对称+逐通道 高精度,硬件支持 选择原则:权重用对称+逐通道,激活用非对称+逐通道(硬件支持时)

3.5 实战建议

说了这么多,到底怎么选?我给出一个通用策略:

  1. 权重量化:优先对称+逐通道。精度损失小,硬件实现也简单。
  2. 激活量化:优先非对称+逐层。如果精度不够,再升级到逐通道。
  3. 特殊层处理:第一层和最后一层建议保留FP32,或者用更高精度量化。

一句话总结:

对称量化省计算,非对称量化保精度。逐层量化省资源,逐通道量化保精度。具体选哪个,看你的硬件和精度要求。