本文首发于我的知乎:https://zhuanlan.zhihu.com/p/104753473
GaintPandaCV导语 传统的卷积神经网络基本都是乘法密集型运算堆叠起来的,而无论哪种硬件实现这些乘法运算都需要消耗大量的能量和计算资源,同时使得运行的延时无法显著降低,如何用更廉价的操作来代替乘法运算也成为模型加速比较火的方向。前段时间有两篇华为联合出品的神经网络高效计算的论文AdderNet和DeepShift很有意思,主要想法都是研究如何用更廉价的运算来代替神经网络中昂贵密集的乘法运算,如加法或者移位+符号位翻转,鉴于我们课题组也是主要做的AI加速方面的工作,所以仔细阅读了论文,想看看其中端倪,并尝试获得一些启发。
论文链接:
https://arxiv.org/pdf/1912.13200.pdf
)。https://arxiv.org/abs/1905.13298
)。代码链接:
https://github.com/huawei-noah/AdderNet
)。https://github.com/mostafaelhoushi/DeepShift
)。目前深度神经网络中广泛使用的卷积是互相关的计算,用来测量输入特征和卷积滤波器之间的相似性,虽然有效,但涉及大量的浮点乘法运算:
卷积是互相关的计算
其中S()是相似性度量函数,输入
,权重
,输出
本文针对这点提出了一个新的基于加法的相似度计算方法,即将输入特征和卷积滤波器之间的L1范数距离作为相似性的度量:
基于加法的相似度计算方法
考虑到正常卷积的运算输出值是有正有负的,而本文的L1范数是取两个值之差的绝对值的负数,只能输出非正值,因此为了考虑激活函数的使用以及与传统输出范围的统一,这里使用Batch Normalization来进行规范化的操作,将输出调整至合适范围,那么这里大家就比较疑惑了?说好的没有乘法呢?Batch Normalization是不可能避免乘除法的,论文的解释是传统卷积神经网络中,卷积部分的计算复杂度是
,而BN的计算复杂度是
,两者差距比较大,BN的乘法运算相比于卷积而言几乎可以忽略,这个意思就是说本文我只取代调卷积部分的乘法,其他部分的乘法我还是需要继续使用的,但这么回头看看题目,感觉过于扎眼。
然后为了保证这种度量方式能够有效地学习到数据的特征,作者又特地改进了BP的计算方式:
改进的BP方式
其中HT()是HardTanh函数:
HardTanh函数
并且考虑到不同层的学习情况不同,设计了自适应学习率的方法,第l层的学习率:
第l层的学习率计算公式
其中γ是全局的学习率,
是第l层局部的学习率,第三项是第l层的梯度。
AdderNet训练流程
最后一句"with almost no multiplication"这句话的说法感觉还需要商榷,BN的运算量是固定的,相比于正常的卷积运算来说确实很小,但是将卷积中的乘法替换成L1范数计算后,BN的ops在整个AdderNet网络中是否还是占少数,如果还是占少数的话那么说"with almost no multiplication"还挺可信,但是据我了解,加法相对于乘法占用的计算资源是小很多的,所以作者应该在这块再给个证明。
最后作者还基于MNIST数据集(10分类)对传统卷积神经网络和本文的AdderNet的特征进行了可视化,结果表明CNNs这张计算输入与滤波器之间互相关的方式,卷积操作相当于在求两者的余弦距离(输入和滤波器都进行归一化的情况下),所以分类结果是以角度进行划分的,而AdderNet这张基于L1范数的相似度计算方式表现为聚类的效果。
对AdderNet的特征进行了可视化
实验结果没有统计乘法
这篇文章也是针对传统CNNs中大量密集的乘法运算带来的高计算消耗和能量消耗的问题,考虑用逐点移位和标志位翻转来代替乘法操作,移位操作代替绝对值乘法运算,标志位翻转代替正负符号运算,并且提出了两种不同的训练方式DeepShift-Q和DeepShift-PS。在硬件电路中移位和标志位01翻转是相对于加法更简单的操作,所以对于模型加速也是很有意义的。
权值的表示方式
其中:
s和2^p的具体计算方法
图2.1
图2.2
图2.3 原始卷积核权值都用移位来表示
训练方法和训练常规的CNN相同,只是权重矩阵被round到最近的2的次幂上
权值的更新
然后梯度更新方式也同时进行一些修改,并且设定round函数的梯度为1
反向传播参数更新
这里的训练参数仍然是原始的W和b,只是在实际运行的时候会round到附近的2的次幂值上,所以和之前的网络比差异不是特别大,很容易理解,我在做8bit量化的时候也经常这么干。
DeepShift-Q 示意图
区别于DeepShift-Q的方法,DeepShift-PS直接使用p和s用于训练参数更新
训练参数更新
其中
和HardTanh有点类似
且设置
对
的梯度为1。
梯度更新的计算公式为:
梯度更新计算公式
同样其中遇到sign()函数和round函数的梯度都设为1。
DeepShift-PS计算公式
DeepShift-Q和DeepShift-PS的训练流程和正常的CNNs的训练方式相同,只是参数和梯度更新计算公式需要根据设定的来,实验中同样将权重加入loss作为L2正则化项,对于DeepShift-PS,
,而非
,本文实验比较充分,既在CPU上实验,也特定设计了一个GPU的计算核,并且对比实验做的很充分。
在s较大时误差较大,在s较小时误差相对小,但是当属于[-1,1]时,-1,0和1的区间大小又不一样,偏向于0的区间显然更大。所以这种梯度近似的方法是不是有些粗糙。
乘法是目前通用的深度神经网络设计中不可或缺的一部分,但同样也是由于大量密集的乘法运算,使得算法模型在嵌入式/移动端设备上很难部署,而加法在硬件中几乎是最廉价的计算之一了,如何利用加法,移位,标志位翻转、与或非位运算等廉价操作来代替神经网络中的乘法操作还是可以进一步进行探究的。并且这些廉价操作的替换同时也会带来训练上的复杂性——梯度、优化器、学习率需要重新设计,毕竟牵一发而动全身,各个环节都需要小心翼翼。同时考虑到模型落地应用的话,参数量的压缩是一个很重要的方面,模型落地有两个大的角度:轻量化网络设计(KD暂时纳入其中)和模型压缩/量化。轻量化网络的设计需要网络本身有强大的表征能力,基于乘法运算的CNNs已经被证明是有这样的能力的,如SqueezeNet,ShuffleNet和MobileNet,这两篇论文实验都是VGG和ResNet这中本身冗余性比较大的网络,那么能否推广到更轻量级的网络,使得保持学习能力的同时还能减少模型参数量,或者能否在训练好的基础上进一步进行参数的压缩或量化。如果像AdderNet和DeepShift这种基于廉价操作的方法既可以减少了参数量又降低了运算所需的ops,我想NVIDIA应该会第一时间去更新他的cudnn吧,因为这是非常具有革命性的,说明基于加法或移位+标志位翻转的模型具有强大的学习能力,可以完全取代传统的CNNs。
所以我认为此类方法的进一步研究是:
以上就是我对这两篇论文的解读和拙见,希望有兴趣的读者读完原论文的可以私下继续交流一下。可以在下面的想法中和我们交流哦。