3、量化基础回顾:对称量化与非对称量化、量化粒度(per-tensor vs per-channel)

好,咱们进入第三章。说实话,量化这个主题,很多同学一听就觉得头大。我当年刚接触的时候也一样,觉得不就是把 FP32 变成 INT8 嘛,有什么难的?结果第一次在低功耗芯片上跑模型,精度直接崩了……嗯,从那以后,我再也不敢小看量化了。

这一节,咱们把量化最核心的两个概念讲透:对称 vs 非对称,以及量化粒度。这两个东西,说白了就是决定你量化后模型精度和性能的“命门”。

3.1 量化到底在做什么?

先问个问题:为什么我们要量化?

因为低功耗场景下,芯片的算力和带宽都有限。FP32 的模型跑起来,功耗高、速度慢。量化成 INT8,计算量能降 4 倍,模型体积能缩 4 倍,功耗更是直线下降。代价呢?精度损失。我们的任务就是让这个损失尽可能小。

量化的数学本质很简单:

Q = round( (R - zero_point) / scale )

其中 R 是原始浮点数,Q 是量化后的整数,scale 是缩放因子,zero_point 是零点偏移。就这么一个公式,但不同的选择,结果天差地别。

3.2 对称量化 vs 非对称量化

对称量化

对称量化,顾名思义,就是量化后的整数范围关于 0 对称。比如 INT8 的范围是 [-128, 127],对称量化会让浮点数的 0 对应整数的 0。

公式简化成:

Q = round( R / scale )

这里 zero_point = 0。好处是什么?计算简单,硬件实现快。我在项目中遇到过,很多 NPU 和 DSP 对对称量化的支持特别好,几乎零开销。

但有个坑:如果你的数据分布不是对称的,比如全是正数,那对称量化会浪费一半的表示范围。举个例子,ReLU 的输出全是非负的,你用对称量化,负半轴的 [-128, -1] 全浪费了,精度自然受影响。

我曾经踩过的坑: 在量化一个轻量级分类网络时,我图省事直接用了对称量化。结果精度掉了 2 个点。后来发现,模型中间层的激活值分布严重偏正,对称量化根本不适合。换成非对称后,精度只掉了 0.3 个点。

非对称量化

非对称量化允许 zero_point 不为 0。这样,浮点数的 0 可以映射到整数范围内的任意位置。公式就是最前面那个:

Q = round( (R - zero_point) / scale )

好处很明显:能充分利用整个整数表示范围。对于 ReLU 这种输出全为正的激活函数,非对称量化可以把 [0, max] 映射到 [0, 255],一个比特都不浪费。

代价呢?计算稍微复杂一点,硬件上需要多一个减法操作。不过现在大部分芯片都支持,性能影响不大。

对比项 对称量化 非对称量化
zero_point 固定为 0 可调节
计算复杂度
硬件友好度
数据分布适配 仅适合对称分布 适合任意分布
典型应用 权重、LayerNorm 激活值、偏置

我个人习惯是:权重用对称量化,激活用非对称量化。为什么?权重分布通常比较对称,而且对称量化在硬件上更快。激活值分布千奇百怪,非对称量化更灵活。

3.3 量化粒度:per-tensor vs per-channel

量化粒度,说白了就是“多少个参数共享同一个 scale 和 zero_point”。

Per-tensor 量化

整个张量(比如一个卷积层的权重)只用一个 scale 和一个 zero_point。实现最简单,计算量最小。但问题也很明显:如果张量内部不同通道的数值范围差异很大,那精度损失会很大。

举个例子,一个卷积层有 64 个输出通道,其中 63 个通道的权重范围是 [-1, 1],但第 64 个通道的范围是 [-10, 10]。per-tensor 量化会取全局最大值 10,导致前 63 个通道的量化精度严重不足。

核心观点: per-tensor 量化适合数值分布均匀的张量。如果分布不均匀,精度会打折扣。

Per-channel 量化

每个通道独立计算 scale 和 zero_point。比如一个卷积层有 64 个输出通道,那就需要 64 组量化参数。精度更高,但计算量和存储量也更大。

我在项目中遇到过,per-channel 量化通常能让精度提升 0.5~1 个点,尤其是在深度可分离卷积中。MobileNet 系列模型,如果不做 per-channel 量化,精度掉得惨不忍睹。

对比项 Per-tensor Per-channel
量化参数数量 1 组 通道数 组
计算开销
存储开销
精度 一般
适用场景 小模型、资源极度受限 大模型、精度敏感场景

你想想看,低功耗场景下,我们通常选哪个?我个人建议:权重用 per-channel,激活用 per-tensor。因为激活值的分布通常比较稳定,per-tensor 就够了。而权重的分布差异大,per-channel 能保住精度。

3.4 知识体系总览

为了让你更直观地理解,我画了一张图。这张图把量化最核心的两个维度——量化方法和量化粒度——组合起来,形成了四种常见策略。你在实际项目中,可以根据芯片能力和精度要求,在这四个象限里选一个。

量化策略四象限 量化方法 对称 非对称 量化粒度 Per-tensor Per-channel 对称 + Per-tensor 计算最快 硬件最友好 精度最低 适合:权重分布均匀的小模型 对称 + Per-channel 计算较快 精度较高 存储略增 适合:权重分布不均的中型模型 非对称 + Per-tensor 精度适中 实现简单 适合:激活值分布偏正的小模型 非对称 + Per-channel 精度最高 计算最复杂 适合:精度敏感的大模型 ← 精度递增 ← 精度递增 计算复杂度递增 → 计算复杂度递增 →

这张图你看懂了吗?横轴是量化粒度,纵轴是量化方法。左下角(对称+per-tensor)计算最快但精度最低,右上角(非对称+per-channel)精度最高但计算最复杂。低功耗场景下,我们通常选左下或左上,具体看芯片能力。

3.5 实战建议

好了,理论讲完了,说点实际的。如果你现在要量化一个 SwiGLU 激活的模型,我的建议是:

  1. 权重用对称 + per-channel。SwiGLU 的权重分布通常比较对称,per-channel 能保住精度。
  2. 激活用非对称 + per-tensor。SwiGLU 的输出是门控机制的结果,分布偏正,非对称更合适。per-tensor 够用,别浪费资源。
  3. 先跑一遍校准集。看看每层的数值范围,如果某层分布特别异常,再单独调整。
小技巧: 如果你用的芯片支持混合粒度量化,可以试试权重 per-channel、激活 per-tensor 的组合。这是我在多个低功耗项目里验证过的“黄金搭配”。

嗯,量化基础就讲到这里。记住,没有银弹。不同的模型、不同的芯片,最佳策略都不一样。多试、多调,才能找到最适合你的方案。


公众号:蓝海资料掘金营,微信deep3321