概要总结
HWGQ-net主要是针对激活值进行量化,其从理论上分析如何去选择一个激活函数,以及使用近似方法来拟合量化的损失(使得量化的损失和梯度匹配)。
在前向传播时使用近似于ReLU函数的量化器,在反向传播使用适合的分段线性函数,来解决前向传播和反向传播的不匹配问题。(以前的前向传播多了个量化过程,而反向传播不作处理)。
该方法,对于重新训练模型会比较好(该文提出的量化器,可以作为激活函数的替代品,所以可能实现上网络没有激活函数层了??)。
简介
对于量化的影响而言,激活值的量化比权重的量化要大很多(因为量化损失大很多)。作者认为这是因为激活值量化之后,还要经过激活函数的作用(作者此时把激活函数看做sigmoid、tanh、阶跃这样的,因为后面提出ReLU会好一些,从而推出类ReLU),这样就会产生不可微分算子,产生很小的梯度(梯度饱和)。
ReLU是一个半波过滤器,half-wave rectifier。
因为以前的方法,forward model和反向计算梯度的方法不匹配,所以不能保证得到很好的性能,很可能得到一个次优解。(因为forward时,要经过一个量化操作,而backward时按原模型处理,所以会出现forward和backward模型不匹配现象)
相关工作
让模型在硬件加速的方向有几个:
- 低秩矩阵分解(多对于全连接层)
- 模型裁剪(connection pruning)
- 压缩模型(使用avg pooling代替全连接层,NIN,Squeezenet等)
- 网络蒸馏(network distillation)
- 模型量化(quantization)
二元网络
模型计算可以简单看做如下点积形式: (1) z = g ( w T x ) z=g(w^Tx)\tag{1} z=g(wTx)(1) 我们的权重量化和激活值量化最后都表现为 z z z;
在原始的浮点网络有两个问题: 1) 权重存储需要大量的memory;2) 点积计算需要大量的浮点值;
权值量化
如果权值量化到二元,则原有的计算 I ∗ W ≈ α ( I ⊕ B ) I*W \approx \alpha(I\oplus B) I∗W≈α(I⊕B) 其中, ⊕ \oplus ⊕表示 multiplication-free 卷积, B = s i g n ( W ) B = sign(W) B=sign(W), B ∈ R c ∗ w ∗ h B\in R^{c*w*h} B∈Rc∗w∗h, α = ∥ W ∥ 1 c ∗ w ∗ h \alpha = \frac{\|W\|_1}{c*w*h} α=c∗w∗h∥W∥1, α ∈ R + \alpha \in R^+ α∈R+。
量化权重,解决了w的存储问题,但并未解决浮点计算的点积计算问题。
二值激活量化
激活值二元量化的方式和权值量化一样 (2) z = s i g n ( x ) = { + 1 , i f x ≥ 0 − 1 , o t h e r w i s e z=sign(x)=\begin{cases}+1, &if\ x\ge0 \\ -1, &otherwise\end{cases}\tag{2} z=sign(x)={+1,−1,if x≥0otherwise(2) 一般来说,还要乘以一个因子 β \beta β,但实际效果显示并没啥用。
按照公式 ( 1 ) (1) (1)进行反向求导, (3) ∂ C ∂ w = ∂ C ∂ z g ′ ( w T x ) x \frac{\partial C}{\partial w} = \frac{\partial C}{\partial z}g'(w^Tx)x\tag{3} ∂w∂C=∂z∂Cg′(wTx)x(3)
当使用公式 ( 2 ) (2) (2)作为 g ( x ) g(x) g(x)时,基本就没有梯度了。此时,其他作者就想出了反向传播用激活函数近似的方法,来使得反向传播过程和前向传播近似(因为forward比全浮点模型还要多一个量化过程)。此时有: (4) s i g n ^ ′ ( x ) = { 1 , i f ∣ x ∣ ≤ 1 0 , o t h e r w i s e \widehat{sign}'(x)=\begin{cases}1, &if \ |x| \leq 1 \\ 0, &otherwise\end{cases}\tag{4} sign ′(x)={1,0,if ∣x∣≤1otherwise(4)
在反向传播阶段使用这个近似的函数,可以得到一些梯度,用于更新。但也因此产生两个问题:
- 仍有饱和现象(梯度消失)
- 前向传播和反向传播模型的不一致(这里表现为 s i g n sign sign和 s i g n ^ \widehat{sign} sign 的区别),这种现象称为 " gradient mismatch "
Half-wave Gaussian Quantization
ReLU
(5) g ( x ) = m a x ( 0 , x ) g(x)=max(0,x)\tag{5} g(x)=max(0,x)(5)
本文在前向传播使用量化器 Q ( x ) Q(x) Q(x)去近似公式 ( 5 ) (5) (5),在反向传播使用合适的分段线性近似 Q ^ ( x ) \hat{Q}(x) Q^(x)。
Forward Approximation
Q ( x ) = q i , i f x ∈ ( t i , t i + 1 ] Q(x)=q_i, \ \ if \ \ x\in(t_i, t_{i+1}] Q(x)=qi, if x∈(ti,ti+1]
其中, t i , t i + 1 t_i,t_{i+1} ti,ti+1是两个量化的值。我们所需要存储的是下标,通过存储下标得到对应的值。
因为每层的激活输出都接近于高斯分布(经过BN层之后,就是高斯分布。而该方法是作用于点积操作后的BN层之后的),又因为ReLU是一个 half-wave rectifier,所以方法叫做 half-wave Gaussian quantized (HWGQ)。
Backward Approximation
有三种方法来进行反向传播的近似:
- Vanilla ReLU Q ^ ′ ( x ) = { 1 , i f x > 0 0 , o t h e r w i s e \hat{Q}'(x)=\begin{cases}1, & if \ \ x>0 \\ 0, & otherwise \end{cases} Q^′(x)={1,0,if x>0otherwise 该方法和HWGQ存在 gradient mismatch , 因为Q(x) 限定了量化的最大数 t m t_m tm。
- Clipped ReLU Q ^ c ( x ) = { q m , x > q m x , x ∈ ( 0 , q m ] 0 , o t h e r w i s e \hat{Q}_c(x)=\begin{cases}q_m, &x>q_m \\ x, & x \in (0, q_m] \\ 0, &otherwise\end{cases} Q^c(x)=⎩⎪⎨⎪⎧qm,x,0,x>qmx∈(0,qm]otherwise 使用截断ReLU,则不会在大于 q m q_m qm的数值上产生 dismatch 现象。
- Log-tail ReLU Q ^ l ( x ) = { q m + l o g ( x − τ ) , x > q m x , x ∈ ( 0 , q m ] 0 , o t h e r w i s e \hat{Q}_l(x)=\begin{cases}q_m+log(x-\tau), &x>q_m \\ x, & x \in (0, q_m] \\ 0, &otherwise\end{cases} Q^l(x)=⎩⎪⎨⎪⎧qm+log(x−τ),x,0,x>qmx∈(0,qm]otherwise
结果证明,截断式ReLU比较好用。
实验细节
如果要使用max-pooling操作,则在batch-normalization之前;
第一层和最后一层保持全浮点精度;
lr衰减手段为多项式衰减。