0%

模型量化中的激活函数

模型量化中的激活函数

文章参考学习

在之前学习的模型量化过程中,对于激活函数的处理只是简单说了一下ReLU函数的量化,这里更加具体的学习一下!

量化回顾

之前说的量化过程: \[ r=S(q-Z) \tag{1} \]

\[ q=round(\frac{r}{S}+Z) \tag{2} \]

但是,这里还存在一点小问题,就是对于式\((2)\)而言,仅使用\(round\)是不够的,还需要使用一个\(clip\)操作,来将结果固定到指定范围内,防止溢出,例如对于uint8的量化,则量化的结果q必须要量化到[0,255],所以进一步公式为: \[ q=clip(round(\frac{r}{S}+Z), 0, 255) \tag{3} \] 现在,假设激活函数为\(f(x)\),存在浮点实数\(r_1\),则其对应的激活值为 \[ r_2=f(r_1) \tag{4} \] 把式\((1)\)代入式\((4)\)得: \[ S_2(q_2-Z_2) = f(S_1(q_1-Z_1)) \tag{5} \]

ReLU量化

具体的对于ReLU激活函数进行量化,ReLU原函数是: \[ ReLU(x) = \begin{cases} 0 &,x<0 \\ x &, x\ge0 \end{cases} \tag{6} \] 使用\(r_1,r_2\)替换得: \[ r_2 = \begin{cases}0 &, r_1<0 \\r_1 &,r_1\ge0 \end{cases} \tag{7} \] 再将式\((1)\)代入得: \[ S_2(q_2-Z_2) = \begin{cases}0&, q_1<Z_1 \\S_1(q_1-Z_1)&,q_1\ge Z_1 \end{cases} \tag{8} \] 换算得: \[ q_2 = \begin{cases}Z_2 &, q_1 < Z_1 \\ \frac{S_1}{S_2}(q_1-Z_1)+Z_2 &, q_1\ge Z_1 \end{cases} \tag{9} \] 这里的\(\frac{S_1}{S_2}\)是浮点数,所以在实际运算是也需要和之前的\(M\)一样通过定点数移位的方式实现。需要注意的是,这里的\(Z_2\)表示的是\(ReLU\)输出的zero point,而根据式\((6)\)可知,\(ReLU\)输出的结果是\([0, ReLU(input_{max})]\),而\(Z_2\)需要与其中的0对齐,同时\(Z_2\)的取值范围又是\([0, 255]\)(如果其是uint8类型的话),这样一来,\(Z_2\)就一定为0了

而在具体工程实践过程中,通常并不是完全按照式\((9)\)进行的,因为\(ReLU\)的物理意义就是将小于零点的数值截断,其余不变。因此,工程上,通常将\(ReLU\)前后的scale和zero point保持一致,然后使用如下公式来实现理化: \[ q_2 = \begin{cases}Z_1 &, q_1 < Z_1 \\ q_1 &, q_1 \ge Z_1 \end{cases} \tag{10} \]

ReLU整合Convolution

假设一个卷积操作为\(r_3 = \sum_i^N r_1^ir_2^i\),则其量化后的公式为: \[ S_3(q_3-Z_3) = S_1S_2\sum_i^N(q_1-Z_1)(q_2-Z_2)\tag{11} \]\(q_3\)代入式\((8)\)得: \[ S_4(q_4-Z_4) = \begin{cases}0&, q_3<Z_3 \\S_3(q_3-Z_3)&,q_3\ge Z_3 \end{cases} \tag{12} \] 将式\((11)\)代入得: \[ S_4(q_4-Z_4) = \begin{cases}0&, q_3<Z_3 \\S_1S_2\sum_i^N(q_1-Z_1)(q_2-Z_2) &,q_3\ge Z_3 \end{cases} \tag{13} \] 整合得: \[ q_4 = \begin{cases}Z_4&, q_3<Z_3 \\\frac{S_1S_2}{S_4}\sum_i^N(q_1-Z_1)(q_2-Z_2)+Z_4 &,q_3\ge Z_3 \end{cases} \tag{14} \] 上述操作clip后则是: \[ q_4 = \begin{cases}Z_4&, q_3<Z_3 \\ clip(\frac{S_1S_2}{S_4}\sum_i^N(q_1-Z_1)(q_2-Z_2)+Z_4,0,255) &,q_3\ge Z_3 \end{cases} \tag{15} \] 这里由于\(ReLU\)的物理原理,\(Z_4\)是为0的,而当\(q_3<Z_3\)时,代入到式\((11)\)可以发现,\(\sum_i^N(q_1-Z_1)(q_2-Z_2)<0\),如果代入到\((15)\)中的\(q_3 \ge Z_3\)分支中时,可以得到\(q_4 = clip(\frac{S_1S_2}{S_4}\sum_i^N(q_1-Z_1)(q_2-Z_2)+Z_4,0,255)=0\),其中的\(\frac{S_1S_2}{S_4}\sum_i^N(q_1-Z_1)(q_2-Z_2)+Z_4=\frac{S_1S_2}{S_4}\times负数+0\),clip后就是0了

综上,就可以使用如下式子表示卷积和\(ReLU\)整合的结果: \[ q_4 = clip(\frac{S_1S_2}{S_4}\sum_i^N(q_1-Z_1)(q_2-Z_2)+Z_4,0,255) \tag{16} \] 这个公式的意义相当于:计算出\(ReLU\)\(S\)\(Z\),然后将这个\(S\)\(Z\)对应到卷积层的输出,这样一来,\(ReLU\)运算就合并到了卷积层了。

LeakyReLU

首先,\(LeakyReLU\)的公式为: \[ LeakyReLU(x) = \begin{cases} \alpha x &,x<0 \\ x &, x\ge0 \end{cases} \tag{17} \] \(\alpha\)为超参数,通常取值范围为\([0,1]\)

类比式\((6),(7),(8),(9)\),可以得到: \[ r_2 = \begin{cases}\alpha r_1 &,r_1<0 \\ r_1 &, r_1 \ge 0 \end{cases} \tag{18} \]

\[ S_2(q_2-Z_2) = \begin{cases}\alpha S_1(q_1-Z_1) &,q_1<Z_1 \\ S_1(q_1-Z_1) &, q_1 \ge Z_1 \end{cases} \tag{19} \]

\[ q_2 = \begin{cases}\frac{\alpha S_1}{S_2}(q_1-Z_1)+Z_2 &,q_1<Z_1 \\ \frac{S_1}{S_2}(q_1-Z_1)+Z_2 &, q_1 \ge Z_1 \end{cases} \tag{20} \]

这里,由于\(\alpha\)的存在,\(q_2\)是无法用一个式子进行表示的,也就无法整合到卷积操作里了。

非线性函数

对于类\(ReLU\)函数来说,其实还都是分段线性的,而遇到非线性的函数如\(sigmoid\)\(tanh\)等,又应该如何量化呢?

这些函数其实是用定点运算来近似浮点的效果,以I-BERT: Integer-only BERT Quantization float为例,它是采用多项式拟合的方式用线性计算来实现其中的非线性计算。