神经网络量化入门--Folding BN ReLU
上一篇文章介绍了量化训练的基本流程,本文介绍量化中如何把 BatchNorm 和 ReLU 合并到 Conv 中。
Folding BatchNorm
BatchNorm 是 Google 提出的一种加速神经网络训练的技术,在很多网络中基本是标配。
回忆一下,BatchNorm 其实就是在每一层输出的时候做了一遍归一化操作:
其中 是网络中间某一层的激活值,、 分别是其均值和方差, 则是过了 BN 后的输出。
一般卷积层与BN合并
Folding BatchNorm 不是量化才有的操作,在一般的网络中,为了加速网络推理,我们也可以把 BN 合并到 Conv 中。
合并的过程是这样的。假设有一个已经训练好的 Conv 和 BN:
假设 Conv 的 weight 和 bias 分别是 和 。那么卷积层的输出为:
图中 BN 层的均值和标准差可以表示为
量化 BatchNorm Folding
量化网络时可以用同样的方法把 BN 合并到 Conv 中。
如果量化时不想更新 BN 的参数 (比如后训练量化),那我们就先把 BN 合并到 Conv 中,直接量化新的 Conv 即可。
如果量化时需要更新 BN 的参数 (比如量化感知训练),那也很好处理。Google 把这个流程的心法写在一张图上了:
由于实际 inference 的时候,BN 是 folding 到 Conv 中的,因此在量化训练的时候也需要模拟这个操作,得到新的 weight 和 bias,并用新的 Conv 估计量化误差来回传梯度。
Conv与ReLU合并
在量化中,Conv + ReLU 这样的结构一般也是合并成一个 Conv 进行运算的,而这一点在全精度模型中则办不到。
在之前的文章中说过,ReLU 前后应该使用同一个 scale 和 zeropoint。这是因为 ReLU 本身没有做任何的数学运算,只是一个截断函数,如果使用不同的 scale 和 zeropoint,会导致无法量化回 float 域。
看下图这个例子。假设 ReLU 前的数值范围是
但是保证前后的 scale 和 zp 一致,没规定一定得用
想要理解这一点,需要回顾一下量化的基本公式:
注意,这里的 round 除了把 float 型四舍五入转成 int 型外,还需要保证
再举个例子。
假设有一个上图所示的 Conv+ReLU 的结构,其中,Conv 后的数值范围是
但现在,我们想在 ReLU 之后统计 minmax,并用 ReLU 后的 scale 和 zp 作为 ReLU 前的 scale 和 zp「即 Conv 后面的 scale 和 zp」,结果会怎样呢?
看图中下半部分,假设 Conv 后的数值是
因此,通过在 Conv 后直接使用 ReLU 后的 scale 和 zp,我们实现了将 ReLU 合并到 Conv 里面的过程。
那对于 ReLU 外的其他激活函数,是否可以同样合并到 Conv 里面呢?这取决于其他函数是否也只是在做 clip 操作,例如 ReLU6 也有同样的性质。但对于其他绝大部分函数来说,由于它们本身包含其他数学运算,因此就不具备类似性质。
总结
这篇文章主要介绍了如何把 BatchNorm 和 ReLU 合并成一个 Conv,从而加速量化推理。按照计划,应该和之前的文章一样,给出代码实现。但我在测试代码的时候发现有一些 bug 需要解决,正好也控制一下篇幅,下篇文章会给出相关的代码实现。