该方法的简称为:IAO
该论文提出了一种允许网络在推测时只使用整数计算的方法,即 float32 --> int8.
该文在MobileNets等已经压缩过的网络进行量化,测试数据集为ImageNet分类数据集。不同于其他的方法,在高度冗余的模型,如Alexnet等网络上进行的,且提出的硬件加速方法需要专门的特殊硬件(即他们并没有在真正的硬件上加速,只是提出一种理论),该方法在普通的CPU上即可运行。
Introduction
以前的方法在两方面减少modle size和推测时间:
- 网络结构上,如MobileNet、SqueezeNet、ShuffleNet和DenseNet
- 量化权重和**函数,从32 bit的floating point到更低的 bit-depth表示
但是之前的方法有两个方面的缺陷:
- 之前的方法没有在一个合理的基准结构上评估,他们大部分的基准结构普遍在AlexNet,VGGnet,GoogleNet上,这些网络在设计时,为了达到高准确率,有很大的冗余,所以在压缩这些网络时有不小的效果
- **很多量化放大没有真正在硬件上进行有效性证明。**① 有的方法只在weight上量化,仅仅在乎在设备的存储,而不在乎计算效率;② 有的方法,比如二元/三元权重网络和bit-shift网络,他们的方法把权重限制为0或者2n,他们想把乘法计算用bit-shift实现。但是,在现有的硬件上,bit-shift实现并不比<乘法-加法>好。而且,只有当bit较大时,乘法才显得“昂贵”,所以,我们需要将乘法的输入—weight和activation都给量化成较小的bit-width。
Quantized Inference
Quantized scheme
作者的量化方案为:在测试时只使用int计算,在训练时使用浮点计算。
量化方案的基本要求就是:允许只用量化值的整数运算来完成所有的算术运算。
量化方案是一个仿射映射,在整数和实值: 其中是常数(是量化参数)【对每一层array用一对S/Z参数,即每一个activation、每一个weight的Tensor都有一个对应S/Z】。
对于8-bit的量化,q就是8-bit的整数。对于B-bit的量化,q就是B-bit的实数。
而对于bias,就固定量化为32-bit的实数。
常数是step_size,代表一个“scale”,是一个实数。常数是偏移shift,代表“zero-point”,就是为了让实数的和量化数的对应,和q是一个类型的数。设定:
则
从公式可以推出:
template<typename QType> // e.q. QType=uint8
struch QuantizedBuffer{
vector<QType> q; // the quantized values
float S; // the scale
QType Z; // the zero-point
}
量化卷积计算过程
1. 输入 量化的特征图 lhs_quantized_val, uint8类型, 偏移量 lhs_zero_point, int32类型;
2. 输入 量化的卷积核 rhs_quantized_val, uint8类型, 偏移量 rhs_zero_point, int32类型;
3. 转换 unit8 到 int32类型;
4. 每一块卷积求和(int32乘法求和有溢出风险,可换成固定点小数树乘法);
int32_accumulator += (lhs_quantized_val(i, j) - lhs_zero_point) * (rhs_quantized_val(j, k) - rhs_zero_point);
5. 输入 量化的乘子 quantized_multiplier, int32类型 和 右移次数记录 right_shift, int类型;
6. 计算乘法,得到int32类型的结果 (int32乘法有溢出风险,可换成固定点小数树乘法);
quantized_multiplier * int32_accumulator
7. 再左移动 right_shift 位还原,得到 int32的结果;
8. 最后再加上 结果的偏移量 result_zero_point;
(7和8的顺序和 官方说的先后顺序颠倒);
9. 将int32类型结果 限幅到[0, 255], 再强制转换到 uint8类型;
10. 之后再 反量化到浮点数,更新统计输出值分布信息 max, min;
11. 再量化回 uint8;
11. 之后 经过 量化**层;
12. 最后 反量化到 浮点数,本层网络输出;
13. 进入下一层
循环执行 1~12 步骤
若有连续的层需要量化操作时,就没必要进行反量化了。。比如上面步骤的 ,实际上是可以省略的【但相应的。。可能会带来乘法加法累积造成的溢出】
Integer-arithmetic-only matrix multiplication
由公式可以知道,每个array中的实数 都能表示带有一对参数的实数。则对实数矩阵的乘法,其结果矩阵的每个实数可以表示为:其中,是公式中唯一不是实数的值。经验发现,总是在中,所以将表达为: 其中,为非负整数,是一个整数。这样,实数运算就变成了整数运算。同时,用移位运算。因为图片输入的每一个数字都在,而映射的区域也是
注意,在预测时,权重矩阵的量化step_size,可以通过已有参数统计出来,而activation的量化step_size是大量训练数据的指数移动均值统计出来的。所以,才会有没出来,但应用了的公式出现。【下面会有S的计算公式,是通过映射前的range的最小值和最大值出来的】
Implementation of a typical fused layer
定义bias-vector的量化:其中,用int32表示。
矩阵乘法,weights和activations的矩阵乘法后的加法:
使用32位加法器得结构后,还有3件事情需要做:① 将这个output activations的int32 scale down到int8的scale指标;② 将 int32 的output activations 仿射到 uint8;③ 对这个uint8的结果应用**函数。
这个乘法的down-scaling就是公式.
Training with simulated quantization
Quantized scheme
作者分析原有的量化方法:用floating point训练,然后量化训练的weight.(有时候会进行量化后的微调),发现这种方法对于大模型来说结果不错,对小模型来说精确度下降不小。作者对这种量化后的微调方法分析了存在的两点问题:
- 同一layers不同channels权重分布尺度差很多(100x)
- 量化会带来一些“参数丢失”,即量化了就丢失了精度(废话。。)
作者提出了一种在前向传播阶段模拟量化的方法,反向传播和平常一样,所有的权重和biases都用floating point保存以微调小变化。前向传播的浮点数计算方法,模拟量化的方式,就如公式所示。
对每一层,数值都用参数(量化层次,和clamping range)量化:其中,是待量化的实数;是量化的范围;是量化的等级数,对所有layer都是固定的,比如8-bit量化,;就是取整到最近的整数。
公式表示x所处的范围,即映射前的range,之所以有这个看起来没用的公式,是因为activation的range是移动均值平均的出来的;公式表示range映射到n-1段,每段的大小;公式表示一个实数r就近到能完整量化的实数,且是能我们的B-bit表示的量化结果;
bias没有被量化,因为在推测阶段,它被32-bit表示。【这句没懂,因为前面不是有量化bias的参数吗?】
Learning quantization ranges
weight 和 activation的量化range不同:
- 对于weight:,
- 对于activation:在训练时,用指数移动平均来收集activation的range [a,b],平滑参数接近1.【若范围快速变化时,指数移动平均会延迟反映出来,所以在训练初期(5万步到200万步)时,不量化activation是有用的】