神经网络的计算量和参数量估计

本文详细探讨了神经网络的计算量和参数量估计,包括全连接层、激活函数(ReLU和Sigmoid)、LSTM、卷积层和深度可分离卷积层的计算量和参数量计算方法。计算量主要用MACC(Multiply-ACCumulate operation)衡量,参数量则涉及权重和偏置。例如,全连接层的计算量与输入和输出神经元数量有关,而LSTM的计算量除了非线性变换外,还包括激活函数的FLOPS。深度可分离卷积层通过深度卷积和逐点卷积降低计算量,提高效率。
摘要由CSDN通过智能技术生成

目录

计算量定义

全连接层计算量和参数量估计

计算量

参数量

 激活函数计算量

ReLU激活函数

Sigmoid激活函数

LSTM计算量和参数量估计

计算量

参数量

 卷积层计算量和参数量估计

计算量

参数量

深度可分离卷积层

Batch normalization


一个朴素的评估模型速度的想法是评估它的计算量。一般我们用FLOPS,即每秒浮点操作次数FLoating point OPerations per Second这个指标来衡量GPU的运算能力。这里我们用MACC,即乘加数Multiply-ACCumulate operation,或者叫MADD,来衡量模型的计算量。不过这里要说明一下,用MACC来估算模型的计算量只能大致地估算一下模型的速度。模型最终的的速度,不仅仅是和计算量多少有关系,还和诸如内存带宽、优化程度、CPU流水线、Cache之类的因素也有很大关系。

计算量定义

神经网络中的许多计算都是点积,例如:

 

此处,w  和x  是两个向量,结果 y 是标量(单个数字)。对于卷积层或完全连接的层(现代神经网络中两种主要类型的层), w 是该层的学习权重,x  是该层的输入。我们将 w[0] * x[0]+\ldots 计数为一个乘法累加或1个MACC,这里的“累加”运算是加法运算,因为我们将所有乘法的结果相加,所以上式具有n  个这样的MACC(从技术上讲,上式中只有 n-1 个加法,比乘法数少一个,所以这里知识认为MACC的数量是一个近似值)。就FLOPS而言,因为有n个乘法和  n-1 个加法,所以点积执行2 n-1 FLOPS,因此,MACC大约是两个FLOPS。

现在,我们来看几种不同的层类型,以了解如何计算这些层的MACC数量。

全连接层计算量和参数量估计

计算量

在完全连接的层中,所有输入都连接到所有输出。对于具有I  输入值和 J 输出值的图层,其权重 W 可以存储在 I \times J 矩阵中。全连接层执行的计算为:

y=\operatorname{matmul}(x, W)+b

在这里,x  是 I 输入值的向量, W 是包含图层权重的 I \times J 矩阵,b  是 J 偏差值的向量,这些值也被相加。结果y 包含由图层计算的输出值,并且也是大小J 的向量。对于完全连接层来说,矩阵乘法为 \operatorname{matmul}(x, W) ,其中具有 I \times J 个MACC(和权重矩阵W大小一样),对于偏置b,正好补齐了前面我们所说的点积中正好少一个加法操作。因此,比如一个具有300个输入神经元和100个输出神经元的全连接层执行  个MACC。特别提示:上面我们讨论的批次大小  需要具体计算需要乘上Batch。

注意:

 以上计算基于Batch=1,如果Batch不是1,需乘上Batch。

 也就是说,通常,将长度为I的向量与I \times J矩阵相乘以获得长度为J的向量,则需要I \times J  MACC或(2 I-1) \times J FLOPS。

参数量

对于全连接层而言,它的参数分别是权重W和 偏置b,所以对于上面的例子中具有300个输入神经元和100个输出神经元的全连接层的参数量是:300 \times 100+100=30100  ,这个很容易进行验证,下图是使用TensorFlow进行验证参数量: 

 激活函数计算量

通常,一个层后面紧接着就是非线性激活函数,因为它们不做点积,所以使用FLOPS进行度量而非MACC。

在计算FLOPS时,我们通常将加,减,乘,除,求幂,平方根等作为单个FLOP进行计数。

ReLU激活函数

ReLU激活函数表达式为:y=\max (x, 0)

 在具有J个输出神经元的完全连接层上,ReLU计算J次,因此我们将其判定为JFLOPS。

Sigmoid激活函数

Sigmoid激活函数表达式为:y=1 /(1+\exp (-x))

由于在Sigmoid激活函数中有四个不同的运算,因此将其判定为每个函数输出4 FLOPS或总层输出J \times 4  FLOPS。

可以看出,激活函数的耗时较短,因而主要考虑矩阵乘法和点积的计算量,忽略激活函数的计算量。

此外,激活函数没有参数量。

LSTM计算量和参数量估计

计算量

LSTM里面有 4 个非线性变换(3 个 门 + 1 个 tanh),每一个非线性变换就是一个全连接网络,形如:W\left[h_{t-1}, x_{t}\right]+b  。其中,第一层是x_{i}h_{i}的结合,维度就是embedding_size + hidden_size,第二层就是输出层,维度为 hidden_size,则它的计算量按照上文我们对全连接层的阐述,易得MACC为:

(embedding_size + hidden_size) * hidden_size * 4

四个非线性变换中,还会对全连接层的输出进行激活函数计算(三个sigmoid和一个tanh),由上面讨论的sigmoid我们知道,对于sigmoid的计算量为:(embedding_size + hidden_size) * hidden_size * 3 *4个FLOPS,而tanh的计算公式为:\frac{\exp (x)-\exp (-x)}{\exp (x)+\exp (-x)}  ,其中共有八个加,减,乘,除,求幂,平方根等计算,所以计算量为:(embedding_size + hidden_size) * hidden_size * 8个FLOPS。除此之外,LSTM除了在四个非线性变换中的计算,还有三个矩阵乘法(不是点积)、一个加法、一个tanh计算,其中三个矩阵乘法都是shape为(batch, hidden_size),则这四个运算的计算量为:batch * hidden_size + batch * hidden_size + batch * hidden_size + batch * hidden_size + batch * hidden_size * 8,综上所述,LSTM的计算量为:

(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验证如下:

 卷积层计算量和参数量估计

计算量

卷积层的输入和输出不是矢量,而是shape为H \times W \times C 的三维特征图,其中H是特征图的高度,W  是宽度,C 是每个位置的通道数,正如我们所见今天使用的大多数卷积层都是二维正方内核,对于内核大小为K 的转换层,MACC的数量为:

K \times K \times \text { Cin } \times \text { Hout } \times \text { Wout } \times \text { Cout }

  • 输出特征图中有Hout × Wout × Cout个像素;

  • 每个像素对应一个立体卷积核K x K x Cin在输入特征图上做立体卷积卷积出来的;

  • 而这个立体卷积操作,卷积核上每个点都对应一次MACC操作

同样,我们在这里为了方便忽略了偏置和激活。我们不应该忽略的是层的stride,以及任何dilation因子,padding等。这就是为什么我们需要参看层的输出特征图的尺寸Hout × Wout,因它考虑到了stride等因素。比如,对于3 \times 3 ,128个filter的卷积,在112 \times 112 带有64个通道的输入特征图上,我们执行MACC的次数是:

3 \times 3 \times 64 \times 112 \times 112 \times 128=924,844,032

这几乎是10亿次累积运算!

注意:在此示例中,我们使用“same”填充和\text { stride }=1,以便输出特征图与输入特征图具有相同的大小。通常看到卷积层使用\text { stride }=2,这会将输出特征图大小减少一半,在上面的计算中,我们将使用56 \times 56而不是112 \times 112

参数量

根据卷积的原理,对于上面的例子中,3 \times 3  ,128个filter的卷积,在 112 \times 112 带有64个通道的输入特征图上的参数量为:3 \times 3 \times 64 \times 128+128=73856  ,用TensorFlow验证结果如下图:

深度可分离卷积层

深度可分离卷积是将常规卷积因式分解为两个较小的运算,它们在一起占用的内存更少(权重更少),并且速度更快,这些层在移动设备上可以很好地工作,既是MobileNet的基础,也是Xception等大型模型的基础。深度可分离卷积中,第一个操作是深度卷积,它在很多方面与常规卷积相似,不同之处在于我们不合并输入通道,也就是说输出通道数始终与输入通道数相同,深度卷积的MACC总数为:K \times K \times \text { Cin } \times \text { Hout } \times \text { Wout }

这减少了\text { Cin }的工作量,比常规的卷积层效率更高。当然,仅深度卷积是不够的,我们还需要增加“可分离”,第二个操作是常规卷积,但始终使用内核大小 1 \times 1,即 K=1 ,也称为“逐点”卷积,MACC的数量为:\text { Cin } \times \text { Hout } \times \text { Wout } \times \text { Cout }

深度可分离卷积分为两个操作,深度卷积和可分离,所以现在我们对两种操作分别就上面的例子计算,和并和常规3 \times 3卷积进行比较:

 所以深度可分离卷积的计算量简化为:

\text { Cin } \times \text { Hout } \times \text { Wout } \times(K \times K+\text { Cout })

 我们来看看MobileNet V2中的对深度可分离卷积的拓展,MobileNet V2相比与V1,主要是由DW+PW两层变成了下面的三层PW+DW+PW:

  • 一个 1 \times 1 卷积,为特征图添加更多通道(称为expansion layer)

  •  3 \times 3深度卷积,用于过滤数据(depthwise convolution)

  •  1 \times 1卷积,再次减少通道数(projection layer,bottleneck convolution)

这种扩展块中MACC数量的公式:Cexp = (Cin × expansion_factor),(expansion_factor用于创建深度层要处理的额外通道,使得Cexp在此块内使用的通道数量)

  • M A C C \text { expansion layer }=\text { Cin } \times \text { Hin } \times \text { Win } \times \text { Cexp } ,(参照上面传统卷积,把卷积核设置为1x1即得)

  •  \text { MACC depthwise layer }=K \times K \times \text { Cexp } \times \text { Hout } \times \text { Wout }(参照MoblieNet V1分析)

  • M A C C \text { projection layer }=\text { Cexp } \times \text { Hout } \times \text { Wout } \times \text { Cout } (参照MoblieNet V1分析,或者传统卷积把卷积核设置为1x1即得)

把所有这些放在一起:

M A C C_{v} 2=\text { Cin } \times \text { Hin } \times \text { Win } \times \text { Cexp }+(K \times K+\text { Cout }) \times \text { Cexp } \times \text { Hout } \times \text {Wout}

这与MobileNet V1使用的深度可分层相比如何?如果我们使用输入特征图 112 \times 112 \times 64扩展因子6,以及\text { stride }=1的  3 \times 3深度卷积和128输出通道,那么MACC的总数是:

(1 \times 1+128 +64) \times (64 \times 6) \times 112 \times 112=969196096

这不是比以前更多吗?是的,它甚至超过了最初的3 \times 3卷积。但是......请注意,由于扩展层,在这个块内,我们实际上使用了64 \times 6=384通道。因此,这组层比原始的3 \times 3 卷积做得更多(从64到128个通道),而计算成本大致相同。

Batch normalization

在现代网络中,通常在每个卷积层之后都包含一个batch norm层。相关资料见[2].

Batch normalization在层的输出上进行计算,针对每个输出值,计算公式如下:

 此处,y是上一层的输出图中的元素。我们首先通过减去该输出通道的平均值并除以标准偏差来对该值进行归一化(epsilon 用于确保不除以0,通常为0.001),然后,我们将系数gamma缩放,然后添加一个偏差或偏移beta。每个通道都有自己的gamma,beta,均值和方差值,因此,如果卷积层的输出中有 C 个通道,则Batch normalization层将学习C \times 4参数,如下图所示:

通常将Batch normalization应用于卷积层的输出,而在ReLU之前,在这种情况下,我们可以做一些数学运算以使Batch normalization层消失!由于在全连接层中进行的卷积或矩阵乘法只是一堆点积,它们是线性变换,而上面给出的Batch normalization公式也是线性变换,因此我们可以将这两个公式组合为一个变换。我们只需要将Batch normalization参数合并到前面各层的权重中,其数学运算非常简单。具体可以参见上面的那篇关于Batch Normalization的文章,也就是说我们可以完全忽略Batch Normalization层的影响,因为我们在进行推理时实际上将其从模型中删除了。

注意:此trick仅在层的顺序为:卷积->BN->ReLU时才有效;不适用于:卷积->ReLU->BN。ReLU是一个非线性操作,它会把数据弄乱。(但如果批量标准化后面紧跟一个新的卷积层,你可以反过来折叠参数)


【可参考资料】

[1] G-kdom:CNN基础知识——卷积(Convolution)、填充(Padding)、步长(Stride)

https://zhuanlan.zhihu.com/p/77471866

[2] DengBoCong:论文阅读笔记:看完也许能进一步了解Batch Normalization

https://zhuanlan.zhihu.com/p/340219662

[3] CNN卷积层、全连接层的参数量、计算量(https://zhuanlan.zhihu.com/p/77471991)

Learning both Weights and Connections for Efficient Neural Networks(https://arxiv.org/abs/1506.02626)

[4] 卷积神经网络中参数量的计算与模型占用显存的计算(https://www.jianshu.com/p/b8d48c99a47c)

How fast is my model?(http://machinethink.net/blog/how-fast-is-my-model/)

[5] Understanding LSTM Networks(http://colah.github.io/posts/2015-08-Understanding-LSTMs/)

Number of parameters in an LSTM model(https://datascience.stackexchange.com/questions/10615/number-of-parameters-in-an-lstm-model)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值