获取神经网络的计算量和参数量
作者:DengBoCong 文仅交流,侵删
Github:本文代码放在该项目中:https://github.com/DengBoCong/nlp-paper
说明:讲解时会对相关文章资料进行思想、结构、优缺点,内容进行提炼和记录,相关引用会标明出处,引用之处如有侵权,烦请告知删除。
目录:
全连接层的计算量和参数量估计
激活函数的计算量估计
LSTM的计算量和参数量估计
卷积层的计算量和参数量估计
深度可分离卷积的计算量和参数量估计
Batch Normalization的计算量和参数量估计
其他层的计算量和参数量估计
对于深度学习模型来说,拥有一个非常好的设计思路和体系架构非常重要,对模型性能的影响非常之大,所以对于模型的研究倾向于在模型性能上的表现。但是对于商业应用来说,算法模型落地的另一个重要考量就是在满足业务场景内存占用、计算量等需要的同时,保证算法的性能,这个研究对于移动端的模型部署更加明显,这有利于压缩应用的体积。最近这段时间正好在研究关于移动端模型部署(TensorFlow Lite用的不是很顺心呀),所以要仔细研究一下模型的参数量等,这不仅可以让我们对模型的大小进行了解,还能更好的调整结构使得模型响应的更快。
可能有时候觉得,模型的大小需要计算嘛,直接保存大小直接看不就完事儿了?运行速度就更直接了,多运行几次取平均速度不就行了嘛?so easy?这个想法也没啥错,但是大前提是你得有个整型的模型呀(训练成本多高心里没数嘛),因此很多时候我们想要在模型设计之初就估计一下模型的大小以及可能的运行速度(通过一些指标侧面反应速度),这个时候我们就需要更深入的理解模型的内部结构和原理,从而通过估算模型内部的参数量和计算量来对模型的大小和速度进行一个初步评估。
一个朴素的评估模型速度的想法是评估它的计算量。一般我们用FLOPS,即每秒浮点操作次数FLoating point OPerations per Second这个指标来衡量GPU的运算能力。这里我们用MACC,即乘加数Multiply-ACCumulate operation,或者叫MADD,来衡量模型的计算量。不过这里要说明一下,用MACC来估算模型的计算量只能大致地估算一下模型的速度。模型最终的的速度,不仅仅是和计算量多少有关系,还和诸如内存带宽、优化程度、CPU流水线、Cache之类的因素也有很大关系。
下面我们对计算量来进行介绍和定义,方便我们后续展开层的讲解:
神经网络中的许多计算都是点积,例如:
y = w[0]*x[0] + w[1]*x[1] + w[2]*x[2] + ... + w[n-1]*x[n-1]
此处, 和 是两个向量,结果 是标量(单个数字)。对于卷积层或完全连接的层(现代神经网络中两种主要类型的层), 是该层的学习权重, 是该层的输入。我们将 计数为一个乘法累加或1个MACC,这里的“累加”运算是加法运算,因为我们将所有乘法的结果相加,所以上式具有 个这样的MACC(从技术上讲,上式中只有 个加法,比乘法数少一个,所以这里知识认为MACC的数量是一个近似值)。就FLOPS而言,因为有 个乘法和 个加法,所以点积执行 FLOPS,因此,MACC大约是两个FLOPS。现在,我们来看几种不同的层类型,以了解如何计算这些层的MACC数量。
注意了:下面的阐述如果没有特别说明,默认都是batch为1。
01
在完全连接的层中,所有输入都连接到所有输出。对于具有 输入值和 输出值的图层,其权重 可以存储在 矩阵中。全连接层执行的计算为:
在这里, 是 输入值的向量, 是包含图层权重的 矩阵, 是 偏差值的向量,这些值也被相加。结果 包含由图层计算的输出值,并且也是大小 的向量。对于完全连接层来说,矩阵乘法为 ,其中具有 个MACC(和权重矩阵 大小一样),对于偏置 ,正好补齐了前面我们所说的点积中正好少一个加法操作。因此,比如一个具有300个输入神经元和100个输出神经元的全连接层执行 个MACC。特别提示:上面我们讨论的批次大小 需要具体计算需要乘上Batch。
也就是说,通常,将长度为 的向量与 矩阵相乘以获得长度为 的向量,则需要 MACC或 FLOPS。
上面我们讨论了全连接层的计算量,那么它的参数量是多少呢?这个应该很容易就算出来,对于全连接层而言,它的参数分别是权重 和 偏置 ,所以对于上面的例子中具有300个输入神经元和100个输出神经元的全连接层的参数量是: ,这个很容易进行验证,下图是使用TensorFlow进行验证参数量:
02
通常,一个层后面紧接着就是非线性激活函数,例如ReLU或sigmoid,理所当然的计算这些激活函数需要时间,但在这里我们不用MACC进行度量,而是使用FLOPS进行度量,原因是它们不做点积,一些激活函数比其他激活函数更难计算,例如一个ReLU只是:
这是在GPU上的一项操作,激活函数仅应用于层的输出,例如在具有 个输出神经元的完全连接层上,ReLU计算 次,因此我们将其判定为 FLOPS。而对于Sigmoid激活函数来说,有不一样了,它涉及到了一个指数,所以成本更高:
在计算FLOPS时,我们通常将加,减,乘,除,求幂,平方根等作为单个FLOP进行计数,由于在Sigmoid激活函数中有四个不同的运算,因此将其判定为每个函数输出4 FLOPS或总层输出 FLOPS。所以实际上,通常不计这些操作,因为它们只占总时间的一小部分,更多时候我们主要对(大)矩阵乘法和点积感兴趣,所以其实我们通常都是忽略激活函数的计算量。
对于参数量?注意了它压根没有参数,请看它们的公式,用TensorFlow验证如下:
03
关于LSTM的原理可以参考这一篇文章
http://colah.github.io/posts/2015-08-Understanding-LSTMs/
(embedding_size + hidden_size) * hidden_size * 4
(embedding_size + hidden_size) * hidden_size * 4 个MACC
embedding_size * hidden_size * 8 + hidden_size * (hidden_size + 20) 个FLOPS
((embedding_size + hidden_size) * hidden_size + hidden_size) * 4
对于特征维128的输入,LSTM单元数为64的网络来说,LSTM的参数量为:((128 + 64) * 64 + 64) * 4 = 49408,通过TensorFlow验证如下:
04
输出特征图中有Hout × Wout × Cout个像素; 每个像素对应一个立体卷积核K x K x Cin在输入特征图上做立体卷积卷积出来的; 而这个立体卷积操作,卷积核上每个点都对应一次MACC操作
05
3×3 depthwise : 7,225,344
1×1 pointwise : 102,760,448
深度可分离卷积 : 109,985,792 MACCs
常规 3×3 卷积 : 924,844,032 MACCs
一个 卷积,为特征图添加更多通道(称为expansion layer) 深度卷积,用于过滤数据(depthwise convolution) 卷积,再次减少通道数(projection layer,bottleneck convolution)
,(参照上面传统卷积,把卷积核设置为1x1即得) (参照MoblieNet V1分析) (参照MoblieNet V1分析,或者传统卷积把卷积核设置为1x1即得)
06
07
08
减少参数 降低精度 融合计算单元步骤
https://www.jianshu.com/p/b8d48c99a47c
http://machinethink.net/blog/how-fast-is-my-model/
http://colah.github.io/posts/2015-08-Understanding-LSTMs/
https://datascience.stackexchange.com/questions/10615/number-of-parameters-in-an-lstm-model
https://zhuanlan.zhihu.com/p/77471991
https://arxiv.org/abs/1506.02626
猜您喜欢:
附下载 |《TensorFlow 2.0 深度学习算法实战》