CNN卷积神经网络模型的参数量、计算量计算方法(概念版)

一、参考资料

神经网络参数量、计算量(FLOPS)、内存访问量(MAC)计算详解

5种方法获取Torch网络模型参数量计算量等信息

卷积神经网络的参数计算

浅谈深度学习:如何计算模型以及中间变量的显存占用大小

卷积的三种模式:full, same, valid

卷积中参数量和计算量

卷积神经网络中的参数计算

理解分组卷积和深度可分离卷积如何降低参数量

抽丝剥茧,带你理解转置卷积(反卷积)

深度学习中不同类型卷积的综合介绍:2D卷积、3D卷积、转置卷积、扩张卷积、可分离卷积、扁平卷积、分组卷积、随机分组卷积、逐点分组卷积等pytorch代码实现和解析。

二、相关介绍

1. 引言

1.1 为什么要计算模型参数量和计算量?

  • 好的网络模型不仅要求精度准,还要要求模型的参数量计算量不大,才能有利于部署
  • 统计模型的参数量和计算量可以用于不同网络模型之间的对比分析
  • 有的模型虽然参数量相同,但是可能因为连接方式和结构等不同而导致计算量不同

1.2 计算量与参数量对比?

  • 计算量是指网络模型需要计算的运算次数,参数量是指网络模型自带的参数数量多少。
  • 计算量对应时间复杂度,参数量对应于空间复杂度
  • 计算量决定了网络执行时间的长短,参数量决定了占用显存的大小

2. 参数量(Parameters, Weights)

参数量是模型中的参数的总和,跟模型在磁盘中所需的空间大小直接相关。对于 CNN 来说参数主要由 Conv/FC 层的 Weight 构成,当然其他的一些算子也有参数,不过一般忽略不计了。

参数量往往是被算作访存量(MAC)的一部分,因此参数量不直接影响模型推理性能。但是参数量一方面会影响内存占用,另一方面也会影响程序初始化的时间。

参数量会直接影响软件包的大小。当软件包大小是很重要的指标时,参数量至关重要,例如手机 APP 场景,往往对 APK 包的大小有比较严格的限制;此外有些嵌入式设备的 Flash 空间很小,如果模型磁盘所需空间很大的话,可能会放不下,因此也会对参数量有所要求。

除了在设计模型时减少参数量外,还可以通过压缩模型的方式降低软件包大小。例如 Caffe 和 ONNX 采用的 Protobuf 就会对模型进行高效的编码压缩。不过压缩模型会带来解压缩开销,会一定程度增加程序初始化的时间。

3. 计算量(FLOPs)

计算量是模型所需的计算次数,反映了模型对硬件计算单元的需求。计算量一般用 OPs (Operations) ,即计算次数来表示。由于最常用的数据格式为 float32,因此也常常被写作 FLOPs (Floating Point Operations),即浮点计算次数。

模型的整体计算量等于模型中每个算子的计算量之和。而每个算子的计算量计算方法各不一致。例如对于 Elementwise Sum 来讲,两个大小均为 (N, C, H, W) 的 Tensor 相加,计算量为 N ∗ C ∗ H ∗ W N * C * H * W NCHW

对于计算量主要有 MAddsMFlops 两个概念。shufflenet的论文用的是MFlops,Mobilenet用的是MAddsMAddsMFlops的两倍。

3.1 乘加累积操作(MACs, MAdds)

MACs=MAdds=2*FLOPs

乘加累积操作(Multiply-Accumulate Operations, MACs),MACs和MAdds是同一个概念MACs常常与FLOPs概念混淆,实际上 1MACs 包含一个乘法操作和一个加法操作, 1MACs等于2倍FLOPs。

3.2 FLOPsFLOPS

FLOPS:注意全大写,是 floating point operations per second 的缩写,意指每秒浮点运算次数,理解为计算速度。是一个衡量硬件性能的指标

FLOPs:注意s小写,是 floating point operations 的缩写(s表复数),意指浮点运算数,理解为计算量。可以用来衡量算法/模型的复杂度。

4. 访存量(MAC)

访存量(memory access cost, MAC),又称为内存访问量,是指模型运行时所需访问存储单元的字节大小,反映了模型对存储单元带宽的需求。访存量一般用 Bytes(或者 KB/MB/GB)来表示,即模型计算到底需要存/取多少 Bytes 的数据。

和计算量一样,模型整体MAC等于模型各个算子的访存量之和。对于 Elementwise Sum 来讲,两个大小均为 (N, C, H, W) 的 Tensor 相加,MAC为 ( 2 + 1 ) ∗ N ∗ C ∗ H ∗ W ∗ s i z e o f ( d a t a _ t y p e ) (2 + 1) * N * C * H * W * sizeof(data\_type) (2+1)NCHWsizeof(data_type),其中 2 代表读两个 Tensor,1 代表写一个 Tensor。

5. 内存占用

内存占用是指模型 运行时 所占用的内存/显存大小。一般有工程意义的是最大内存占用,当然有的场景下会使用平均内存占用。这里要注意的是,内存占用 ≠ 访存量。 内存占用在论文里不常用,主要原因是其大小除了受模型本身影响外,还受软件实现的影响。例如有的框架为了保证推理速度,会将模型中每一个 Tensor 所需的内存都提前分配好,因此内存占用为网络所有 Tensor 大小的总和;但更多的框架会提供 lite 内存模式,即动态为 Tensor 分配内存,以最大程度节省内存占用(当然可能会牺牲一部分性能)。

和参数量一样,内存占用不会直接影响推理速度,往往算作访存量的一部分。但在同一平台上有多个任务并发的环境下,如推理服务器、车载平台、手机 APP,往往要求内存占用可控。可控一方面是指内存/显存占用量,如果占用太多,其他任务就无法在平台上运行;另一方面是指内存/显存的占用量不会大幅波动,影响其他任务的可用性。

三、通俗理解参数量的计算

下图中,输入特征图尺寸为 32x32x3 ,用一个 5x5x3 的卷积核对其中某个位置的计算,这里计算的是一个点积,所以输出是一个单独的标量值

在这里插入图片描述

因为卷积的操作是通过一个滑动窗口实现的,通过卷积操作,输出特征图尺寸为 28x28x1

在这里插入图片描述

如果有6个filter,输出特征图尺寸为 28x28x6

在这里插入图片描述

这就是一个最基础的卷积操作,那么这里用到的参数量是多少呢?我们只需要把每个filter的参数累加起来,当然,不要忘了加上bias偏置:5x5x3x6 + 6 = 456。

另外,计算卷积以后的输出的大小,如下图所示,N是输入图像的size,F是filter的size,stride是滑动的步长。

在这里插入图片描述

然而,从上图中最后一个例子可以看到,stride大于1的时候不一定能整除,此时,需要在原图像上加上一层padding填充,然后再用前面的公式计算即可。

在这里插入图片描述

另外,还有一个 maxpooling 操作,该操作会改变输入输出,但不会有参数。所以使用和计算卷积一样的公式计算即可。

在这里插入图片描述

四、参数量、计算量的数学表达

1. 卷积层

在这里插入图片描述

1.1 参数量

Conv2d(C_in, C_out, (K_h, K_w)):参数量为 C_in × C_out × K_h × K_w

对于卷积层来说,参数量就是卷积核里所有参数的数量。

假设,每个卷积核的尺寸是 D K ∗ D K ∗ M D_K * D_K*M DKDKM,一共有N个卷积核。

如果考虑bias偏置项,则标准卷积的参数量为: D K ∗ D K ∗ M ∗ N + N D_K * D_K * M * N + N DKDKMN+N

如果不考虑bias偏置项,则标准卷积的参数量为: D K ∗ D K ∗ M ∗ N D_K * D_K * M * N DKDKMN

从计算公式可以看出,参数量仅与卷积核有关,与输入尺寸无关

1.2 计算量

原始论文:[1]

对于卷积层来说,输出的特征图都是进行一系列的乘加运算得到的。

假设,每个卷积核的尺寸是 D K ∗ D K ∗ M D_K * D_K * M DKDKM,一共有N个卷积核,输出的特征图尺寸是 D F ∗ D F D_F * D_F DFDF

一次卷积乘法运算次数为: D K ∗ D K ∗ M D_K * D_K * M DKDKM

一次卷积加法运算次数为: D K ∗ D K ∗ M − 1 ( 27 个数相加,做 26 次加法运算 ) D_K * D_K * M-1 \quad \textcolor{red}{(27个数相加,做26次加法运算)} DKDKM1(27个数相加,做26次加法运算)

一共进行 D F ∗ D F ∗ N  次卷积运算 ( 输出 f e a t u r e   m a p 大小为 D F ∗ D F ∗ N ) D_F * D_F*N \ 次卷积运算 \quad \textcolor{red}{(输出feature \ map大小为D_F * D_F*N)} DFDFN 次卷积运算(输出feature map大小为DFDFN)

乘加运算总次数: ( 2 ∗ D K ∗ D K ∗ M − 1 ) ∗ ( D F ∗ D F ∗ N ) (2*D_K * D_K * M-1)*(D_F * D_F*N) (2DKDKM1)(DFDFN)

乘加运算总次数的近似表示: 2 ∗ ( D K ∗ D K ∗ M ) ∗ ( D F ∗ D F ∗ N ) 2*(D_K * D_K * M)*(D_F * D_F*N) 2(DKDKM)(DFDFN)

通常,标准卷积的计算量只考虑乘法运算 ( D K ∗ D K ∗ M ) ∗ ( D F ∗ D F ∗ N ) (D_K * D_K * M) * (D_F * D_F * N) (DKDKM)(DFDFN)

从计算公式可以看出,计算量与输出特征图的尺寸有关。

1.3 访存量(MAC)

原始论文:[1]

对于标准卷积,MAC的计算公式为:

M A C ( C o n v ) = M A C ( I n p u t ) + M A C ( W e i g h t ) + M A C ( O u t p u t ) = ( C i n ∗ H i n ∗ W i n + C i n ∗ D K ∗ D K ∗ C o u t + C o u t ∗ H o u t ∗ W o u t ) ∗ s i z e o f ( d a t a _ t y p e ) \begin{aligned} MAC(Conv)& =MAC(Input) + MAC(Weight) + MAC(Output) \\ & =(C_{in} * H_{in} * W_{in} + C_{in} * D_K * D_K * C_{out} + C_{out} * H_{out} * W_{out} ) * sizeof(data\_{type}) \end{aligned} MAC(Conv)=MAC(Input)+MAC(Weight)+MAC(Output)=(CinHinWin+CinDKDKCout+CoutHoutWout)sizeof(data_type)

MAC对模型的推理速度至关重要,设计模型时需要予以关注

1.4 注意

  1. 参数量只与定义的网络结构有关,和forward的任何操作无关。即定义好了网络结构,参数就已经确定了。FLOPs和不同的层运算结构有关。但是如果forward时在同一层(同一名字命名的层)多次运算,FLOPs不会增加。
  2. Model_size = 4*params 模型大小约为参数量的4倍,4表示按照32位存储,即4字节。

2. 全连接层

在这里插入图片描述

2.1 参数量

Linear(M->N):参数量为M×N+N

假设,输入 C i C_i Ci 个神经元,输出 C o C_o Co 个神经元。

如果考虑bias偏置项,则参数量为: C i ∗ C o + C o C_i * C_o + C_o CiCo+Co

如果不考虑bias偏置项,则参数量为: C i ∗ C o C_i * C_o CiCo

2.2 计算量

假设,输入 C i C_i Ci 个神经元,输出 C o C_o Co 个神经元。

一个神经元乘法运算次数为: C i C_i Ci

一个神经元加法运算次数为: C o C_o Co

乘加运算总次数为: ( 2 ∗ C i − 1 ) ∗ C o (2*C_i - 1)*C_o (2Ci1)Co

2.3 访存量MAC

输入: C i C_i Ci

输出: C o C_o Co

权重: C i ∗ C o C_i*C_o CiCo

那么,上述三项之和为MAC: C i + C o + C i ∗ C o C_i+C_o+C_i*C_o Ci+Co+CiCo

3. BN层

BatchNorm(N):参数量为 2N

参数量: 2 ∗ C i ( b n . w e i g h t + b n . b i a s ) 2*C_i \quad \textcolor{red}{(bn.weight + bn.bias)} 2Ci(bn.weight+bn.bias)

4. Embedding层

Embedding(N,W):参数量为 N × W

5. 代码示例

import torch
import torch.nn as nn
from torchvision import models
 
class MyModel(nn.Module):
    def __init__(self, ):  # input the dim of output fea-map of Resnet:
        super(MyModel, self).__init__()
 
        self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, bias=False)
        self.bn1 = nn.BatchNorm2d(64)
        self.relu = nn.ReLU(inplace=True)
        self.gap = nn.AdaptiveAvgPool1d(1)
 
        self.fc = nn.Linear(2048, 512)
 
    def forward(self, input):  # input is 2048!
 
        x = self.conv1(input)
        x = self.bn1(x)
        x = self.relu(x)
        x = self.gap(x)
        x = self.fc(x)
 
        return x
 
##############################
 
# 模型准备
model = MyModel()
 
blank = ' '
print('-----------------------------------------------')
print('|   weight name   |        weight shape       |')
print('-----------------------------------------------')
 
for index, (key, w_variable) in enumerate(model.named_parameters()):
    if len(key)<=15: key = key + (15-len(key))*blank
    w_variable_blank = ''
    if len(w_variable.shape) == 1:
        if w_variable.shape[0] >= 100: w_variable_blank = 8*blank
        else: w_variable_blank = 9*blank
    elif len(w_variable.shape) == 2:
        if w_variable.shape[0] >= 100: w_variable_blank = 2*blank
        else: w_variable_blank = 3*blank
 
    print('| {} | {}{} |'.format(key, w_variable.shape, w_variable_blank))
    key = 0
print('-----------------------------------------------')
 

输出:

-----------------------------------------------
|   weight name   |        weight shape       |
-----------------------------------------------
| conv1.weight    | torch.Size([64, 3, 7, 7]) |
| bn1.weight      | torch.Size([64])          |
| bn1.bias        | torch.Size([64])          |
| fc.weight       | torch.Size([512, 2048])   |
| fc.bias         | torch.Size([512])         |
-----------------------------------------------

解释说明

  • CNN卷积层参数量 D K ∗ D K ∗ M ∗ N = 7 ∗ 7 ∗ 3 ∗ 64 D_K * D_K * M * N=7*7*3*64 DKDKMN=77364
  • BN层参数量参数量 2 ∗ C i = b n . w e i g h t + b n . b i a s = 64 + 64 2*C_i=bn.weight+bn.bias=64+64 2Ci=bn.weight+bn.bias=64+64
  • FC全连接层参数量 C i ∗ C o + C o = 2048 ∗ 512 + 512 C_i * C_o + C_o = 2048*512 + 512 CiCo+Co=2048512+512

五、常见网络模型的参数量

LeNet-5

LeNet-5, convolutional neural networks

Gradient-Based Learning Applied to DocumentRecognition

网络解析(一):LeNet-5详解

LeNet-5网络结构如下:
在这里插入图片描述

LeNet-5网络参数量如下:

网络层(操作)输入filterstridepadding输出计算公式参数量
Input32x32x132x32x10
Conv132x32x15x5x1x61028x28x65x5x1x6+6156
MaxPool128x28x62x22014x14x60
Conv214x14x65x5x6x161010x10x165x5x6x16+162416
MaxPool210x10x162x2205x5x160
FC15x5x161205x5x16x120+12048120
FC212084120x84+8410164
FC3841084x10+10850

参数总量: 61706

AlexNet

ImageNet Classification with Deep Convolutional Neural Networks

图像识别-AlexNet网络结构详解

AlexNet网络结构如下:
在这里插入图片描述

AlexNet的结构图有些奇怪。但其实是因为要把网络拆分到两个GPU上,才画成了两层,两层的结构是一样的,下面计算的时候的结构相当于合并以后的网络。

AlexNet网络参数量如下:

网络层(操作)输入filterstridepadding输出计算公式参数量
Input224x224x3224x224x30
Conv1224x224x311x11x3x964055x55x9611x11x3x96+9634,944
MaxPool155x55x963x32027x27x960
Norm127x27x9627x27x960
Conv227x27x965x5x96x2561227x27x2565x5x96x256+256614,656
MaxPool227x27x2563x32013x13x2560
Norml213x13x25613x13x2560
Conv313x13x2563x3x256x3841113x13x3843x3x256x384+384885,120
Conv413x13x3843x3x384x3841113x13x3843x3x384x384+3841,327,488
Conv513x13x3843x3x384x2561113x13x2563x3x384x256+256884,992
MaxPool313x13x2563x3206x6x2560
FC66x6x25640966x6x256x4096+409637,752,832
FC7409640964096x4096+409616,781,312
FC8409610004096x1000+10004,097,000

参数总量: 62,378,344

VGG-16

Very Deep Convolutional Networks for Large-Scale Image Recognition

VGG-16网络结构如下:
在这里插入图片描述

VGG-16网络参数量如下:

网络层(操作)输入filterstridepadding输出计算公式参数量
Input224x224x3224x224x30
Conv3-64224x224x33x3x3x6411224x224x643x3x3x64 + 641,792
Conv3-64224x224x643x3x64x6411224x224x643x3x64x64 + 6436,928
MaxPool2224x224x642x220112x112x640
Conv3-128112x112x643x3x64x12811112x112x1283x3x64x128 + 12873,856
Conv3-128112x112x1283x3x128x12811112x112x1283x3x128x128 + 128147,584
MaxPool2112x112x1282x22056x56x1280
Conv3-25656x56x1283x3x128x2561156x56x2563x3x128x256 + 256295,168
Conv3-25656x56x2563x3x256x2561156x56x2563x3x256x256 + 256590,080
Conv3-25656x56x2563x3x256x2561156x56x2563x3x256x256 + 256590,080
MaxPool256x56x2562x22028x28x2560
Conv3-51228x28x2563x3x256x5121128x28x5123x3x256x512 + 5121,180,160
Conv3-51228x28x5123x3x512x5121128x28x5123x3x512x512 + 5122,359,808
Conv3-51228x28x5123x3x512x5121128x28x5123x3x512x512 + 5122,359,808
MaxPool228x28x5122x22014x14x5120
Conv3-51214x14x5123x3x512x5121114x14x5123x3x512x512 + 5122,359,808
Conv3-51214x14x5123x3x512x5121114x14x5123x3x512x512 + 5122,359,808
Conv3-51214x14x5123x3x512x5121114x14x5123x3x512x512 + 5122,359,808
MaxPool214x14x5122x2207x7x5120
FC17x7x51240967x7x512x4096 + 4096102,764,544
FC2409640964096*4096 + 409616,781,312
FC3409610004096*1000 + 10004,097,000

参数总量: 138,357,544

六、FAQ

Q:计算量越小,模型推理就越快吗?

答案是否定的。

当年头一次实习做算法的时候,主管给的第一个任务就是“把一个大的分割模型砍成一个小的”。当时并不理解模型“大”、“小”的真正含义,就简单的选取计算量作为评价指标,疯狂砍计算量(backbone 换 MobileNet/ShuffleNet、Conv 换成 DepthWise Conv、以及一些奇奇怪怪的融合结构等等),把模型计算量砍了将近 10 倍,结果一部署发现速度并没有快多少,反而是把最初的 ResNet 简单砍掉几个 block 效果更好。

实际上计算量和实际的推理速度之间没有直接的因果关系。计算量仅能作为模型推理速度的一个参考依据。**模型在特定硬件上的推理速度,除了受计算量影响外,还会受访存量、硬件特性、软件实现、系统环境等诸多因素影响,呈现出复杂的特性。**因此,在手头有硬件且测试方便的情况下,实测是最准确的性能评估方式

在设计网络结构时,如果有实测的条件,建议在模型迭代早期对性能也进行测试。一些 NAS 的方法也会对搜索出来的网络结构进行测速,或者干脆对硬件速度进行了建模,也作为初期搜索的重要参数。这种方法设计出来的网络在后期部署时,会极大减少因性能问题迭代优化的时间和人力开销。

七、参考文献

[1] Molchanov P, Tyree S, Karras T, et al. Pruning convolutional neural networks for resource efficient inference[J]. arxiv preprint arxiv:1611.06440, 2016.

[2] Ma N, Zhang X, Zheng H T, et al. Shufflenet v2: Practical guidelines for efficient cnn architecture design[C]//Proceedings of the European conference on computer vision (ECCV). 2018: 116-131.

  • 15
    点赞
  • 74
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

花花少年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值