CNN模型计算量估计

在我们训练的深度学习模型在资源受限的嵌入式设备上落地时,精度不是我们唯一的考量因素,我们还需要考虑

  1. 安装包的大小,如果你的模型文件打包进app一起让客户下载安装,那么动辄数百MB的模型会伤害用户的积极性;

  2. 模型速度,或者说计算量的大小。现在手机设备上的图片和视频的分辨率越来越大,数据量越来越多;对于视频或者游戏,FPS也越来越高,这都要求我们的模型在计算时,速度越快越好,计算量越小越好;

  3. 运行时内存占用大小,内存一直都是嵌入式设备上的珍贵资源,占用内存小的模型对硬件的要求低,可以部署在更广泛的设备上,降低我们算法落地的成本;况且,一些手机操作系统也不会分配过多的内存给单一一个app,当app占用内存过多,系统会kill掉它;

  4. 耗电量大小,智能手机发展到今天,最大的痛点一直是电池续航能力和发热量,如果模型计算量小,内存耗用小的话,自然会降低电量的消耗速度。

以上四点因素,在学术界刷paper的时候或者刷比赛时不会考虑到的(要不然Kaggle上也就不会有那么多ensemble的trick了),学者们可以在PC平台上,甚至在GPU集群上来跑他们的模型;但是当我们评估一个模型,是不是适合在嵌入式设备、移动平台上落地使用时,我们最好针对以上四点预先估算一下它。

最准确的估算方式,当然是训练好模型后,把模型集成进目标硬件上,运行一下(也可以是多次,以避免系统状态波动),测量它的速度和内存占用;但是这样还是要先有一个可以运行在目标硬件上的模型!

本文介绍怎么在模型训练之前,从理论上分析模型的计算量和内存占用大小,毕竟,训练模型的代价也是挺昂贵的。

实验平台

N/A

计算量评价指标

一个朴素的评估模型速度的想法是评估它的计算量。一般我们用FLOPS,即每秒浮点操作次数FLoating point OPerations per Second这个指标来衡量GPU的运算能力。这里我们用MACC,即乘加数Multiply-ACCumulate operation,或者叫MADD,来衡量模型的计算量。

不过这里要说明一下,用MACC来估算模型的计算量只能大致地估算一下模型的速度。模型最终的的速度,不仅仅是和计算量多少有关系,还和诸如内存带宽、优化程度、CPU流水线、Cache之类的因素也有很大关系。

为什么要用乘加数来评估计算量呢?因为CNN中很多的计算都是类似于y = w[0]*x[0] + w[1]*x[1] + w[2]*x[2] + … + w[n-1]*x[n-1]这样的点乘然后累加的形式,其中w和x是向量,结果y是标量。

在CNN中最常见的卷积层和全连接层中,w是学习到的权重值,而x是该层的输入特征图,y是该层的输出特征图。一般来说,每层输出不止一张特征图,所以我们上面的乘加计算也要做多次。这里我们约定w[0]*x[0] + …算一次乘加运算。这样来算,像上面两个长度为n的向量w和x相乘,就有n次乘法操作和n-1次加法操作,大约可等于n次乘加操作。

CNN常用层计算量分析

下面我们逐个分析常见的CNN层的计算量:

全连接层

在全连接层,所有的出都是所有的输入的加权求和而来。对于一个有I和输入和J和输出的全连接层来说,它的权重W可以存储在一个IxJ的矩阵里面,这个全连接层执行的计算就是y = matmul(x, W) + b,这里x是I个输入值的向量,W是包含层权重的IxJ矩阵,b是包含J个元素的偏置值向量。结果y包含由层计算的输出值,也是大小为J的向量。

为了计算MACC的数量,我们看点乘发生的位置matmul(x, W)。矩阵乘法matmul只包含一大堆的点积运算。每个点积都在输入x和矩阵W的一列间发生。两者都有个I元素,因此这算作I个MACC。我们必须计算J个这样的点积,因此MACC的总数IxJ与权重矩阵的大小相同。

加偏置b并不会太影响MACC的数量,毕竟加偏置的操作次数远少于矩阵乘法里面的乘加次数。

示例:具有300个输入神经元和100个输出神经元的全连接层执行300 × 100 = 30,000个MACC。

注意:有时,全连接层的公式是在没有明确偏置值的情况下编写的。在这种情况下,偏置向量作为一行添加到权重矩阵中,所以是(I + 1)× J,但这实际上更像是一种数学简化。在任何情况下,它只会增加J个额外的乘法,所以无论如何MACC的数量都不会受到太大影响。

记住这是一个近似值。

总之,一个长度为I的向量与一个I x J维度的矩阵相乘(这就是全连接呀)得到一个长度为J的输出向量,需要I x J次MACC或者(2xI - 1) x J和FLOPS

如果全连接层直接跟随卷积层,则其输入大小可能不会被指定为单个矢量长度I,但是可能被指定为具有诸如形状(512, 7, 7)的特征图。例如Keras要求你先将这个输入“压扁flatten”成一个向量,这样就可以得到I = 512×7×7个输入。

注意:在所有这些计算中,我假设批量大小为1.如果您想知道批量大小为B的MACC,那么只需将结果乘以B。

激活函数

通常深度学习模型层的后面会串联一个非线性激活函数,例如ReLU或者Sigmoid函数。这些激活函数自然也会消耗时间。但是我们不用MACC来计算它们的计算量,而是使用FLOPS,因为它们不完全是乘加运算。

有些激活函数的计算比其他激活函数更难,例如,ReLU:y = max(x, 0),这只是GPU上的一次单次操作。对于一个有J个输出神经元的全连接层来说,ReLU只做J次这样的运算,所以算J次FLOPS。对于Sigmoid函数y = 1 / (1 + exp(-x))来说,因为它涉及到指数运算和倒数,所以它有更多的计算量。当我们计算FLOPS时,我们通常把加、减、乘、除、取幂、求根等看做一次FLOPS。因为Sigmoid函数有四种(减、取幂、加、除),所以它每个输出对应四个FLOPS,对于J个输出单元的全连接层后的Sigmoid激活层,有J x 4次FLPOS

通常我们不计算激活函数的计算量,因为他们只占整个网络计算量中的很小一部分,我们主要关心大矩阵乘法和点乘运算,直接认为激活函数的运算是免费的。

总结:不需要担忧激活函数

卷积层

卷积层的输入和输出不是矢量,而是三维特征图H × W × C,其中H是特征图的高度,W宽度和C是通道数。

今天使用的大多数卷积层都是方形核。对于具有核大小K的卷积层,MACC的数量为:K × K × Cin × Hout × Wout × Cout。这个公式可以这么理解:

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

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

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

同样,我们在这里为了方便忽略了偏置和激活。

我们不应该忽略的是层的stride,以及任何dilation因子,padding等。这就是为什么我们需要参看层的输出特征图的尺寸Hout × Wout,因它考虑到了stride等因素。

示例:对于3×3,128个filter的卷积,在112×112带有64个通道的输入特征图上,我们执行MACC的次数是:

3 × 3 × 64 × 112 × 112 × 128 = 924,844,032

这几乎是10亿次累积运算!GPU将忙于计算…

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

深度可分离卷积层

这里对于MobileNet V1中的深度可分离卷积只列个结论,更详细的讨论可见本黑板报我前面写的depthwise separable convolutions in mobilenet一文。MobileNet V1深度可分层的总MACC是:MACC_v1 = (K × K × Cin × Hout × Wout) + (Cin × Hout × Wout × Cout),其中K是卷积核大小,Cin是输入特征图通道数,Hout, Wout是DW卷积核输出尺寸(PW卷积只改变输出通道数,不改变输入输出尺寸)。深度可分离卷积的计算量和传统卷积计算量的比为(K × K + Cout) / K × K × Cout,约等于 1 / (K x K)。

下面我们详细讨论下MobileNet V2中的MACC。

MobileNet V2相比与V1,主要是由DW+PW两层变成了下面的三层PW+DW+PW:

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

  2. 3×3深度卷积,用于过滤数据(depthwise convolution)

  3. 1×1卷积,再次减少通道数(projection layer,bottleneck convolution)

这种扩展块中MACC数量的公式:

Cexp = (Cin × expansion_factor),(expansion_factor用于创建深度层要处理的额外通道,使得Cexp在此块内使用的通道数量)

MACC_expansion_layer = Cin × Hin × Win × Cexp,(参照上面传统卷积,把卷积核设置为1x1即得)

MACC_depthwise_layer = K × K × Cexp × Hout × Wout(参照MoblieNet V1分析)

MACC_projection_layer = Cexp × Hout × Wout × Cout(参照MoblieNet V1分析,或者传统卷积把卷积核设置为1x1即得)

把所有这些放在一起:

MACC_v2 = Cin × Hin × Win × Cexp + (K × K + Cout) × Cexp × Hout × Wout

如果stride = 1,则简化为:

(K × K + Cout + Cin) × Cexp × Hout × Wout

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

(3 × 3 + 128 + 64) × (64 × 6) × 112 × 112 = 968,196,096

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

BN层

前面提到了,对于激活函数,我们认为他们是免费的。但是对于BN层呢?在近年的网络结构中在卷积层后面串一个BN层已是常规操作。

BN层获取上层的输出,并将以下公式应用于每个输出值:z = gamma * (y - mean) / sqrt(variance + epsilon) + beta。这y是前一层输出特征图中的元素。我们首先通过减去输出通道的mean并除以标准偏差来标准化该值(epsilon用于确保我们不除以0,它通常是这样的0.001)。然后我们按比例缩放gamma并添加偏差或偏移量beta。每个通道有自己的gamma,beta,mean,和variance的值,因此,如果在卷积层有C个输出通道,则该批量标准化层学习到C×4个参数。看起来有相当多的FLOPS,因为上面的公式应用于输出特征图中的每个元素。然而…通常批量标准化应用于卷积层的输出但非线性(ReLU)之前。在这种情况下,我们可以做一些数学运算来使批量标准化层消失(详见本黑板报我前面写的Batch-Normalization层原理与分析)!

简而言之:我们可以完全忽略批量标准化层的影响,因为我们在进行推理时实际上将其从模型中融合进前面的卷积层。

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

其它层

池化层

到此我们研究了卷积层和全连接层,这两个是现代神经网络中最重要的组成部分。但是也有其他类型的层,例如池化层。

这些其他层类型肯定需要时间,但它们不使用点积,因此不能用MACC测量。如果你对计算FLOPS感兴趣,只需获取特征图大小并将其乘以表示处理单个输入元素的难度的常量。

示例:在112×112具有128通道的特征图上具有过滤器大小2和步幅2的最大池化层需要112 × 112 × 128 = 1,605,632 FLOPS或1.6兆FLOPS。当然,如果步幅与滤波器尺寸不同(例如3×3窗口,2×2步幅),则这些数字会稍微改变。

但是,在确定网络的复杂性时,通常会忽略这些附加层。毕竟,与具有100个MFLOPS的卷积/全连接层相比,1.6 MFLOPS非常小。因此,它成为网络总计算复杂度的舍入误差。

Concate层

某些类型的操作,例如结果的连接,通常甚至可以免费完成。不是将两个层分别写入自己的输出张量中,然后有一个将这两个张量复制到一个大张量的连接层。相反,第一层可以直接写入大张量的前半部分,第二层可以直接写入后半部分。不需要单独的复制步骤。

总结

计算量相对比值备注
全连接层(2 x I - 1) x J FLOPS或者I x J MACC耗时大户
激活函数(Sigmoid)J x 4 FLOPS比例很小,通常不关心
卷积层K × K × Cin × Hout × Wout × Cout MACC1耗时很多
MobileNet V1(K × K × Cin × Hout × Wout) + (Cin × Hout × Wout × Cout) MACC约等于 1 / (K x K)传统卷积的(K × K + Cout) / K × K × Cout,约等于 1 / (K x K)
MobileNet V2Cin × Hin × Win × Cexp + (K × K + Cout) × Cexp × Hout × Wout MACC计算量没有变小,但是表达能力变大了
BN层N/ABN融合,通常不关心
池化层Cin × Hin × Win FLOPS很小,通常不关心
Concate层N/A通常不需要拷贝,成本为零

如上表,本文讨论了在CNN网络中常见的层的计算量MACC,没有涉及到的层也可以参考本文的分析方法来算MACC或者FLOPS。后面在工作中遇到新的模型的时候,不需要实际实现它就可以按照本文的讨论粗略地估计模型在计算量上的可行性;更重要的是,以上分析在自己设计、改造网络的时候也有很强的指导性作用。

参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值