4、权重量化与激活量化:权重量化的策略、激活量化的挑战、动态范围与静态范围

好,咱们进入第四章。这一章聊的是量化里最核心的两个对象——权重和激活值。

很多人刚开始学量化,觉得不就是把32位浮点数砍成8位整数嘛,有什么难的?

嗯,我当年也是这么想的。直到我在一个边缘设备上跑模型,发现精度直接掉了5个点,才意识到这里面的门道有多深。

今天咱们就把权重量化和激活量化掰开揉碎了讲清楚。

4.1 权重量化的策略

权重是什么?是模型训练好的参数,是固定的。你训练完了,权重就定在那了,不会因为输入图片不同而改变。

这就带来一个好处——我们可以离线分析权重的分布,然后选择最合适的量化策略。

我个人习惯把权重量化策略分成三类:

  • 对称量化:量化范围关于0对称。比如权重范围是[-1.0, 1.0],量化到[-127, 127]。
  • 非对称量化:量化范围不关于0对称。比如权重范围是[-0.8, 1.2],那就用零点偏移来映射。
  • 逐通道量化:每个卷积核单独算自己的缩放因子,而不是整个层共用一套。

你可能会问,这三种策略到底怎么选?

我直接说结论:对于大多数卷积网络,逐通道对称量化是性价比最高的选择

为什么?

因为权重分布通常是对称的,而且不同通道的分布差异很大。我在项目中遇到过,一个卷积层有64个通道,有的通道权重范围是[-0.1, 0.1],有的却是[-0.5, 0.5]。如果整个层共用一套量化参数,小范围的通道几乎要被噪声淹没了。

来看一段伪代码,展示逐通道量化的核心逻辑:

# 逐通道对称量化
for channel in range(num_channels):
    w_ch = weights[channel, :, :, :]
    scale = max(abs(w_ch)) / 127.0
    q_ch = round(w_ch / scale)
    q_ch = clamp(q_ch, -127, 127)
    quantized_weights[channel, :, :, :] = q_ch
    scales[channel] = scale

这里要注意,scale是每个通道独立计算的。推理时,反量化也要按通道来。

我的小技巧:如果模型对精度特别敏感,可以试试混合精度量化——敏感层用8位,不敏感层用4位。我在一个语音模型上试过,模型大小压缩了60%,精度只掉了0.3%。

4.2 激活量化的挑战

激活量化比权重量化难得多。

为什么?因为激活值是动态的。你输入一张猫的图片和一张狗的图片,中间层的激活值分布可能完全不同。

我刚开始做激活量化时,犯过一个低级错误——直接用训练集的激活值分布来定量化范围。结果验证集上跑得好好的,一到测试集就崩了。

后来我才明白,激活量化的核心挑战有三个:

  1. 分布不稳定:不同输入产生的激活值范围差异很大。
  2. 异常值问题:偶尔会出现几个特别大的激活值,把量化范围撑得很大。
  3. 逐层累积误差:前一层的量化误差会传递到下一层,越往后误差越大。

举个例子,假设某层激活值99%都在[-3.0, 3.0]之间,但偶尔有个值跑到10.0。如果你按[-10.0, 10.0]来量化,那大部分值的精度就浪费了。如果你按[-3.0, 3.0]来量化,那个10.0就会被截断,产生巨大误差。

怎么解决?

我建议用校准数据集来统计激活值的分布。具体做法是:

  • 拿几百张有代表性的图片跑一遍模型
  • 记录每一层激活值的最大值、最小值、百分位数
  • 根据这些统计量来设定量化范围
注意:校准数据集一定要覆盖边缘情况。我曾经只用标准测试集做校准,结果模型在低光照图片上直接失效了。后来我专门加了一批暗光图片,问题才解决。

4.3 动态范围与静态范围

这两个概念很多人搞混,我简单说清楚。

静态范围:量化参数在推理前就定好了,推理过程中不变。

动态范围:量化参数在推理时根据实际输入动态调整。

说白了,静态范围是「一刀切」,动态范围是「看人下菜碟」。

来看一个对比表格:

特性 静态范围 动态范围
计算开销 低(参数固定) 高(每次推理都要算)
精度 一般 较高
硬件友好度
适用场景 边缘设备、实时推理 服务器端、精度优先

我个人在边缘设备上几乎只用静态范围。为什么?因为动态范围需要在推理时计算最大值和最小值,这个操作在CPU上很慢,在NPU上甚至不支持。

但静态范围也有坑。你想想看,如果校准集和实际部署场景的数据分布不一致,那静态范围就选不准了。

我遇到过最典型的情况:一个目标检测模型,校准集用的是白天的街景,部署时却遇到了大量夜间场景。结果激活值分布完全变了,量化后的模型几乎没法用。

怎么避免?

  • 校准数据集要尽可能覆盖部署场景
  • 如果场景变化太大,考虑用运行时统计来动态调整量化范围
  • 实在不行,就回退到FP16推理,虽然慢一点但至少不会崩
核心总结
权重是静态的,适合离线分析和逐通道量化。
激活值是动态的,需要校准数据集来统计分布。
静态范围省计算,动态范围保精度。
在边缘设备上,优先用静态范围,但一定要做好校准数据集的覆盖。

嗯,这一章的内容就到这里。下一章咱们会讲量化感知训练,也就是怎么让模型在训练时就「学会」量化带来的误差。到时候我会分享一个我在项目里踩过的坑——训练时精度很高,量化后直接崩了,后来发现是伪量化操作没加对位置。

到时候细聊。