Quantization

[1] 进击的程序猿-模型压缩-神经网络量化基础.

[2] Przewlocka-Rus D., Sarwar S. S., Sumbul H. E., Li Y. and De Salvo B. Power-of-two quantization for low bitwidth and hardware compliant neural networks. tinyML Research Symposium, 2022.

[3] Li Y., Dong X. and Wang W. Additive powers-of-two quantization: an efficient non-uniform discretization for neural networks. ICLR, 2020.

[4] Xia L., Anthonissen M., Hochstenbach M. and Koren B. Improved stochastic rounding. 2020.

[5] Oh S., Sim H., Lee S. and Lee J. Automated log-scale quantization for low-cost deep neural networks. CVPR, 2021.

整理了一下量化中的基础概念和方法. 其实, 在计算机中, 我们所见之浮点数也只不过是真正数字的一个高精度量化 (e.g, FP32), 但是随着模型的逐步增加, 我们需要将模型进一步'精简'. 当然了, '精简'的法子有很多: 裁剪 (pruning), 蒸馏 (distillation), 包括这里讲到的量化 (quantization). 个人感觉, 相较于裁剪和蒸馏, 量化是一种即插即用的方法 (虽然会有一些追求极限精度的量化方法需要一些校准). 本文讨论如下的例子:

[3.1,0.03,0.1,1.2]xfQ[...][128,127]Int8/[0,255]UInt8.

线性量化 (Linear Quantization)

对称量化

  • xq=Q(xf) 的对称量化过程如下:

    1. 确定 xf 的(绝对值)范围: Δf=maxi(|xf[i]|);
    2. 确定 xq 的范围: Δq=2N11, N 表示量化后的精度, 比如 Int8 时 Δq=127.
    3. 量化:

      xq=Q(xf):=round(xfΔfΔq).

  • 如上图所示, Δf 首先将 xf 压缩到 [1,1] 之中, 然后再映射回 [128,127] 的量化后的精度中.


def quant(f: torch.Tensor, N: int = 8):
    delta_f = f.abs().max()
    delta_q = 2 ** (N - 1) - 1
    return (f * delta_q / delta_f).round().to(torch.int), delta_f

  • 利用上述代码可得:

[127,1,4,49].

  • 反解的过程:

    x^f=Q1(xq):=xqΔqΔf.


def dequant(q: torch.Tensor, delta_f: torch.Tensor, N: int = 8):
    delta_q = 2 ** (N - 1) - 1
    return (q * delta_f / detal_q).float()

  • 得到:

    [3.1000,0.0244,0.0976,1.1961].

非对称量化

  • xq=Q(xf) 的非对称量化过程如下:

    1. 确定 xf 的(绝对值)范围: Δf=xfmaxxfmin;
    2. 确定 xq 的范围: Δq=2N1, N 表示量化后的精度, 比如 UInt8 时 Δq=255.
    3. 确定零点偏移量: xoffset=xfmin
    4. 量化:

      xq=Q(xf):=round(xf+xoffsetΔfΔq).

  • 注意到:

    xf+xoffset=xfxfmin[0,Δf].


def quant(f: torch.Tensor, N: int = 8):
    offset = -f.min()
    delta_f = f.max() + offset
    delta_q = 2 ** N - 1
    return ((f + offset) * delta_q / delta_f).round().to(torch.int), delta_f, offset


  • 通过如上代码可得量化结果:

    [0,182,190,255]

  • 通过如下方式进行反解:

    x^f=Q1(xq):=xqΔqΔfxoffset.


def dequant(q: torch.Tensor, delta_f: torch.Tensor, offset: torch.Tensor, N: int = 8):
    delta_q = 2 ** N - 1
    return (q * delta_f / delta_q).add(-offset).float()

  • 得到:

    [3.1000,0.0310,0.1039,1.2000]

非线性量化

  • 其实, 一般的量化都可以用如下的过程统一表示:

    1. xf normalize 到 ϕ(x)[0/1,1] 区间内;
    2. 在该区间内设置 2N (或者 2N1) 个点, 记为:

      Q={qi}iI.

    3. 寻找最近邻的作为量化结果:

      Q(x)=argminiI|ϕ(x)qi|.

  • 之前的线性量化实际上就是:

    Q={i/(2N11)}iI,I={(2N11),,0,1,,2N11},

    Q={i/(2N1)}iI,I={0,1,,2N1}.

  • 而 round 就是一种自动的 nearest 的搜索方式.

  • 当然了, Q 的分布不必像线性量化一样那样的均匀, 实际上这种分布往往不是最优的. 容易感觉到, 最优的分布应当在 xf 中比较稠密的范围分布较多的量化点, 否则会造成大量的浪费. 当然了, 这种非线性量化的方式相较于线性量化有它的不足之处, 就是得根据数据'找'一个合适的分布, 这个'找'的过程往往是比较耗时的.

Logarithmic Quantization

  • 对数量化的过程如下:
    1. 确定 xf 的(绝对值)范围: Δf (不一定是最大值);
    2. 确定 xq 的范围: Δq=2N1;
    3. 量化:

      xq=Q(xf):={clip(round(log2|xf||Δf|),1,Δq1),xf>00,xf=0clip(round(log2|xf||Δf|),1,Δq),xf<0

    4. 反解的过程为:

      x^f=sign(xq)α|xq|1Δf.

Power-of-X

注: Power-of-X 根据 [3] 的确是这么定义的, 但是, 在有些里论文里, power-x 表示的是幂函数. 我说实话, 有那么点晕了.

  • Power-of-X 的特点就是 Q 的分布是服从指数分布的:

    Q={αi1}iI{Q0=0},I={1,,2N1}.

    其中 α(0,1).

  • 其量化过程为:

    1. 确定 xf 的(绝对值)范围: Δf=maxi(|xf[i]|);
    2. 确定 xq 的范围: Δq=2N11, N 表示量化后的精度, 比如 Int8 时 Δq=127.
    3. 量化:

      xq=Q(xf):=sign(xf)clip(round(logα(|xf|Δf)+1),0,Δq).

    4. 反解的过程为:

      x^f=sign(xq)α|xq|1Δf.

注: 这里 +1,1 是为了将 0 保留给真正的 0 值.


def quant(f: torch.Tensor, alpha: float, N: int = 8):
    sign, f = f.sign(), f.abs()
    delta_f = f.max()
    delta_q = 2 ** (N - 1) - 1
    logalpha = math.log2(alpha)
    return (f / delta_f).log2().div(logalpha).add(1).round().clip(0, delta_q).mul(sign).to(torch.int), delta_f

def dequant(q: torch.Tensor, alpha: float, delta_f: torch.Tensor, N: int = 8):
    sign, q = q.sign(), q.abs()
    return (alpha ** q.add(-1)).mul(delta_f).mul(sign)

  • 如上图所示, α0, 不均匀性大大增加. 这个性质在有些时候会很有用, 因为很多数据的分布是形容高斯分布的, 此时采用不均匀的会更加高效.

  • 需要声明的一点是, α1 的时候, 整体会显得更加均匀一点, 但是并不能等价线性量化, 注意到:

    α2Nα11.

    这意味着, 除了 0 之外, Q 所能表示的最小值会随着 α 增加逐步增大. 这其实是另一种极为严重的 '不均匀' 性质.

  • 此外 α=0.5 是比较特殊的一种情况, 可以通过位操作加速.

Rounding

有些时候 Rounding 的方式也很重要, 毕竟它是误差的来源.

Deterministic rounding

Stochastic rounding

  • 随机 rounding 形式如下:

    round(x)=x+I[xxξ],ξU([0,1]).

    其中 x 表示 round down 操作.

  • 举个例子, 对于 0.4, 它有 0.4 的概率为 10.6 的概率为 0. 对于 1.6, 它有 0.6 的概率为 2, 有 0.4 的概率为 1.

  • 一个比较好的性质是:

    E[round(x)]=x+E[I[xxξ]]=x+1(xx)=x.

posted @   馒头and花卷  阅读(122)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示