原文链接:https://www.yuque.com/yahei/hey-yahei/binary_quantization
最近号称达到MobileNet水平的二值网络MeliusNet面世,趁这个机会顺便梳理一下二值量化的发展历程吧。
参考:
- 《MeliusNet: Can Binary Neural Networks Achieve MobileNet-level Accuracy? (2020.01)》的Related Work
- https://github.com/memoiry/Awesome-model-compression-and-acceleration
- https://github.com/Ewenwan/MVision/tree/master/CNN/Deep_Compression/quantization
BNN
算是开山之作,同时二值化了权重和激活,但精度挺低,只在MNIST跟CIFAR10上做了些实验。
论文:《Binarized Neural Networks(NIPS2016)》
参考:《二值神经网络(Binary Neural Network,BNN) | CSDN, 张雨石》
实现:https://github.com/itayhubara/BinaryNet.pytorch
二值化形式
BNN提出了两种二值化形式,一种是决策形式,一种是随机形式。
- 决策形式:直接根据连续值的符号,准确地二值化为+1或-1
- 随机形式:引入随机因素,概率性地二值化为+1或-1
![]
其中σ(.)为hard sigmoid函数,即
随机形式要求软硬件生成随机数,实现上比较复杂,所以BNN更倾向于决策形式的二值化
移位实现的BN层
为参数找到最接近的!近似值,把乘法运算简化为位移运算
训练细节
权重和激活在前传和后传都二值化,梯度则继续使用浮点数
- 训练过程中梯度往往比较小而且需要累积,别说二值化了,即使普通的int8量化甚至是用半精度浮点数都会带来训练效果的损失;所幸在梯度上使用浮点数只是增加了训练的时间,预测阶段的速度不受影响
- 权重和激活值的量化引入了噪声,相当于引入正则化,反而还有利于模型的训练
- 二值化函数的梯度处处为0,显然没法直接用反向传播算法来进行训练
为了解决这一问题,作者使用了梯度直通评估器(straight-through estimator, STE),相当于用一个可导的hard tanh函数去近似sign函数
优点
- 速度快,减小内存占用和访存
- 简化计算结构,通常来说32bit乘法需要占用200倍于位运算的计算资源
- 由于权重只有+1和-1,那么卷积核存在的可能组合是相当有限的,相同/相反的输出通道都可以直接剪裁,相似的通道也有一定的裁剪空间
XNOR-Net
与BNN相似,加入了额外的缩放因子,问题讨论也比BNN更加详尽。
论文:《XNOR-Net: ImageNet Classification Using Binary Convolutional Neural Networks (ECCV2016)》
参考:《XNOR-Net算法详解 | CSDN, AI之路》
实现:https://github.com/jiecaoyu/XNOR-Net-PyTorch
(据说~58x的加速比有问题)
(XNOR-Net卷积过程图示,源自BiRealNet论文)
二值化权重
将权重二值化为+1和-1,同时和常规的线性量化一样保留一个缩放因子,即
其中,W是浮点数权重,α是一个浮点数,B是二值权重。
卷积操作可以近似为
其中,I是输入特征图,代表只包含加减法的卷积运算。
取,整层权重共享一个α
二值化权重和激活
由于在卷积和激活阶段进行二值化,传统CNN上的BN层和池化层会出现一些问题,所以需要稍微调整一下顺序:
注意图中只有 BinActiv->BinConv
中间的数据是二值的,其他数据都是浮点数
暂不展开介绍
WRPN 和 Shen et al. 通过提升卷积层通道数的方式来提升 BNN 的精度,即让 BNN 变得更宽。但是这样的方法很大程度上增加了运算复杂度,欠缺模型效果和计算复杂度上的平衡,实用性比较差。ABC-Net 和 GroupNet 是另一种提升 BNN 准确率的代表性方法。它们认为单个权重与激活值信息量不够,如果多学习几组,并取线性加权来逼近全精度输出,那么效果应该是足够的。这类方法计算复杂度太高,准确率是上去了,但速度优势也没了。
Bi-RealNet
XNOR-Net的改进版。
论文:《Bi-Real Net: Enhancing the Performance of 1-bit CNNs with Improved Representational Capability and Advanced Training Algorithm (ECCV2018)》
参考:《Bi-Real Net——XNOR-net的增强与演进(Binary Neural Network) | CSDN, Law-Yao》
实现_(这pytorch代码有点丑啊)_:https://github.com/liuzechun/Bi-Real-net
主要贡献:
- 借鉴ResNet的shortcut,为每个卷积层引入shortcut加强信息的流动,提高特征表达能力
- 改造STE,用更平滑的曲线近似sign函数来估计梯度
- 改造参数更新规则,使得梯度与参数大小相关,加速训练过程
- 优化预训练步骤,在预训练期间用clip(-1,1)替代ReLU
卷积层shortcut
二值化近似函数
为了估计梯度,BNN和XNOR-Net采用的二值化近似函数比较简单,导数也只有0和1,信息较为贫乏;BiRealNet采用二次函数来更好的近似二值化sign函数,进一步减小偏差。
幅度感知的参数更新
训练时,关于二值权重的梯度通常比较小,存在参数更新缓慢的问题。为了解决这个问题,BiRealNet引入了幅度感知的参数更新规则加速训练过程。
在实际预测时,依旧应用sign函数进行二值化,而这个因子可以融合到后续BN层的参数中去
预训练时用clip替代ReLU激活
考虑到权重是二值化为+1和-1,而不是0和1,用ReLU来激活就显得不那么合理,作者用clip(-1,1)替代了ReLU来做激活函数,用clip激活来预训练也得到明显的提升。
BinaryDenseNet
借鉴ResNetE、DenseNet进一步改进Bi-RealNet。
论文:《BinaryDenseNet: Developing an Architecture for Binary Neural Networks (ICCV2019)》
(ResNet vs. ResNetE)
(DenseNet vs. BinaryDenseNet)
- 短连接通过拼接的形式融合特征(ResNet则是相加)
- bottleneck会限制信息的流通,作者建议不要用bottleneck,直接用一层比较窄的3x3卷积
作者发现下采样路径二值化也会带来比较大的负面影响,所以建议
(DenseNet里将如上图d、e下采样部分称为过渡层transition layer)- 过渡层不二值化,通道收缩依旧一半
- 过渡层二值化,但减缓通道收缩的速度,第一个过渡层不收缩,第二、三个过渡层分别收缩1.4倍
- 除了下采样的卷积,第一层卷积和最后一层全连接也不进行二值化
- 将DenseNet的
ReLU->1x1Conv->2x2AvgPool
过渡层改造为计算量更小的2x2MaxPool->ReLU->1x1Conv
MeliusNet
进一步改进BinaryDenseNet。
论文:《MeliusNet: Can Binary Neural Networks Achieve MobileNet-level Accuracy? (2020.01)》
参考:《第一次胜过MobileNet的二值神经网络,-1与+1的三年艰苦跋涉 | 机器之心》
(MeliusNet的基本block)
基本block由DenseBlock和ImprovementBlock组成,
- DenseBlock与BinaryDenseNet里的一致,可以增大提取的特征容量
ImprovementBlock是一个新的模块,用于提高提取的特征质量
- 用拼接后的完整特征进一步产生一个修正特征(类似残差)
- 这个修正被加到DenseBlock产生的新特征上,进一步提高新特征的质量
(完整模型,naive版本)
其他改进和细节:
- 第一层卷积不二值化。用三个3x3卷积替代initial layers的7x7卷积,第一个卷积下采样,第二和第三个卷积分别用
g=4
和g=8
的分组卷积,由此将计算量从118MFLOPS下降为69MFLOPS - 过渡层的1x1卷积不二值化。但都改用分组卷积,取
g=2
或g=4
- 最后一层全连接层也不二值化
- BiRealNet的二值化近似函数似乎没有提升,所以作者依旧采用了原来的hard tanh来近似
- XNOR-Net和BiRealNet在二值化时都有一个缩放因子,但这个因子是可以被BN层取代的,所以没啥必要,所以作者也没有用这个缩放因子,而是跟最初的BNN一样直接进行二值化处理
实验结果:
(MeliusNet的准确率达到了MobileNetv1的水平)
BiRealNet、BinaryDenseNet、MeliusNet都只提供理论的加速效果(比较operations数量)而没有实测数据。
推荐阅读