Google CNN Quantization: Theory and Implementation

量化方案综述

这篇文章提出了一种量化神经网络到INT8的通用解决方案,包括量化后精度损失,通过training scheme来弥补精度等。

主要包含三点:

  • 提出一种通用的量化方案,同时量化weight和activation
  • 提出弥补量化后精度损失的训练方案
  • 在MobileNet上实验以证明其有效性

IAO算法实现过程

1.过程综述

  1. 对量化的实现是通过把常见操作转换为等价的八位版本达到的。
  2. 涉及到的操作包括卷积,矩阵乘法,激活函数,池化操作,拼接等。
  3. 转换脚本:把每个已知的操作替换为等价的量化版本
  4. 然后在操作的前后加上含有转换函数的子图,将input从浮点数转换为 8 bit
  5. 再把output 从8 bit 转回浮点数。

我们以ReLU操作为例介绍整个过程。

2.Quantization Inference

  • basics about Quantization Inference

量化方案中量化就是把float型的数值映射到int8或者uint8来进行卷积运算。

论文中使用的 quantization scheme 定义如下:

where:

r: 需要量化的float型数值

q: 量化后的uint8类型的数值

Z: 零点值,偏移量,即量化前 r = 0时,量化后 q 的数值

S: 为了能把量化后的 q 还原回 r,引入一个缩放系数

  • 基本数值转化

比如,如果我们的输入最大值为30.0, 最小值为 -10.0, 则对应量化值为:

Float Quantized
-10.0 0
10 128
30.0 255
  • float 矩阵乘法转换为 int8乘法

paper中公式写得很明白, 根据矩阵乘法定义

我们得到

其中:

上面的操作,具体可以通过如下数学计算表示。

float matrix multiply to int

# 输入:

    r1 = S1 * (q1 - Z1)

    r2 = S2 * (q2 - Z2)

# 乘法:

    out = r1 * r2 =  S1 * (q1 - Z1) * S2 * (q2 - Z2)

    q_out = out / S3 + Z3

          = S1 * S2 / S3 * (q1 - Z1) * (q2 - Z2)

          = M * (q1 - Z1) * (q2 - Z2)

在上面的式子中,M是唯一一个float类型的数据,这里论文中通过以下方式将M转化为int8.

根据经验值,M 的取值范围为 (0, 1), 令 M0 取 [0.5, 1)

首先,对令 M0 = M0 * 2**31, 又因为M0 >= 0.5, 所以,M0 >= 2**30。所以对于M0的这个操作可以看作是定点操作,一个符号位,31个小数位。

举个例子,令M0 = 0.6,然后我们把M0量化位整型,具体是16位还是32位根据机器决定,以32位为例,M0 = M0 * 2**31, 取整后,M0是一个32位的整型。令n = 32, 可以获得M的定点表达。

3.steps of Quantization

  • S = (max - min) / (255 - 0), where max min 分别为矩阵中的最大值和最小值

  • Z = (-min) / S

  • q = r / S + Z, where r 为需要量化的float型数值

4.Training

下面补充一下,我在计算和训练过程中对论文的理解。

  • weight 和 input 的max,min,,S,Z都能容易计算,然而S3,Z3这些参数在inference的时候是未知的。作者通过假设从开始就设定r3是int8的,所以在整型矩阵相乘后通过 bit shift等操作,结果仍然是 int8类型的。然后,直接进入下一次卷积操作,而不进行dequantize操作,保证结果一直保持是int8型
  • S3,Z3如上所述,是在计算过程中计算出来的。
  • 激活值中 max,min是在训练过程中使用EMA计算出来的
  • 作者提到在训练刚开始不稳定的时候不要对网络进行量化,待稳定后再量化,可以尽快使整个网络收敛。

5.Implementation

代码实现过程如下:

quantization

import numpy as np
# 记录各层 激活输入、卷积核参数、激活输出的参数范围 max min, 量化范围我们使用 uint_8 所以量化范围为 0 ~ 255
# 计算量化参数,缩放尺度 S 和 零点(偏移量) Z
S = np.float()
Z = np.uint8()
 
 
S = (max - min) / (255 - 0)
Z = round(0 - min / S)
 
 
# 量化输入 in_ 和 卷积参数 w_
in_quan = in_ / S_in + Z_in
w_quan = w_ / S_w + Z_w
 
 
# 浮点矩阵乘法 变成 量化卷积乘法
out_ = sum(in_[i] * w_[i]) //浮点矩阵乘法
out_ = (S_in * S_w) * sum((in_quan - Z_in) * (w_quan - Z_w))
out_quan = out_ / S_out + Z_out
out_quan = (S_in * S_w / S_out) * sum((in_quan - Z_in) * (w_quan - Z_w)) + Z_out
real_multiplier = S_in * S_w / S_out
quantized_multiplier = round(real_multiplier * 2**31)
 
 
# 之后再将整数结果转换成 浮点结果 用于后续计算
out_ = (out_quan - Z_out) * S_out

References

[1]Jacob B, Kligys S, Chen B, et al. Quantization and Training of Neural Networks for Efficient Integer-Arithmetic-Only Inference

[2]gemmlowp

[3]tensorflow

©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值