在设计CNN网络时,一般会考虑模型的参数量和计算量,模型参数量决定了计算设备需要的内存或显存,模型计算量决定了网络训练的速度。
本文主要包括以下主题内容:
- 张量的尺寸计算方式
- 参数量计算方式
- 计算量计算方式
在此之前先定义一个简单网络模型,后续计算以此模型做例子。
模型定义的代码以及模型的概要情况如下:
from tensorflow import keras
from tensorflow.keras import models
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Reshape
model = models.Sequential()
# 定义输入层 输入图片为100*100像素
model.add(Reshape((100, 100, 1), input_shape=(100, 100)))
# 进行三次卷积和池化
model.add(Conv2D(filters=32, kernel_size=(3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(filters=64, kernel_size=(3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(filters=128, kernel_size=(3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
# 进行flatten
model.add(Flatten())
# 添加全连接层
model.add(Dense(units=50, activation='relu'))
# 再添加一层全连接层作为输出层
model.add(Dense(units=2, activation='sigmoid'))
model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
reshape (Reshape) (None, 100, 100, 1) 0
_________________________________________________________________
conv2d (Conv2D) (None, 98, 98, 32) 320
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 49, 49, 32) 0
_________________________________________________________________
conv2d_1 (Conv2D) (None, 47, 47, 64) 18496
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 23, 23, 64) 0
_________________________________________________________________
conv2d_2 (Conv2D) (None, 21, 21, 128) 73856
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 10, 10, 128) 0
_________________________________________________________________
flatten (Flatten) (None, 12800) 0
_________________________________________________________________
dense (Dense) (None, 50) 640050
_________________________________________________________________
dense_1 (Dense) (None, 2) 102
=================================================================
Total params: 732,824
Trainable params: 732,824
Non-trainable params: 0
_________________________________________________________________
模型接受一张100*100像素的单通道图片,然后经过三次卷积和池化,再接一层全连接层,最后是输出层。其中每层卷积层kernel size都是3*3,每层池化层pool size都是2*2,还有一些默认信息如下:
卷积层:
- strides: 1
- padding: 0
池化层:
- strides: 2
- padding: 0
1. 张量的尺寸计算方式
(1)卷积层的张量输出尺寸:
其中、分别代表输出张量的高和宽,和分别代表输入张量的高和宽,是卷积核大小(kernel size),是填充数(padding),是移动的步长(strides)。
比如我们计算上面定义的模型的conv2d层输出的高:
图像输入的高为100、卷积核大小为3*3、步长为1、填充数为0,所以有
(2)池化层的张量输出尺寸:
其中、分别代表输出张量的高和宽,和分别代表输入张量的高和宽,是池化层尺寸(pool size),是移动的步长(strides)。
比如我们计算上面定义的模型的max_pooling2d层输出的高:
图像输入的高为98、池化层尺寸为2*2、步长为2、填充数为0,所以有
2. 参数量计算方式
(1)卷积层参数量计算:
其中分别代表参数量(parameters),是卷积核大小(kernel size),是卷积核数量(filters),是卷积核的深度(depth)。
公式可以理解为:
一层卷积层的参数量 卷积核包含的参数量bias参数量
而一个卷积核包含的参数量为:
有个卷积核,所以卷积核参数量为:
每一个卷积核的输出最后都接有一个bias,所以bias参数量即为卷积核数量
(PS: 这里考虑的卷积核是正方形的,所以是,如果不是正方形则那么就是宽乘高:)
比如我们计算上面定义的模型的conv2d层的参数量:
卷积核大小为3*3、卷积核深度是1、conv2d层有32个卷积核,所以有
再比如我们计算上面定义的模型的conv2d_1层的参数量:
卷积核大小为3*3、卷积核深度是32、conv2d_1层有64个卷积核,所以有
这里可能会有疑问,为什么卷积核深度就为32了呢?这里解析一下:
我们知道卷积核是有三个维度的,包含,但是我们定义卷积核的时候一般都是只指定它的和,而不用管,这是因为卷积核深度是由前面输入的张量数量决定的。比如第一层卷积层,如果输入接收的是RGB图片,那么卷积核的深度就是3;像这里模型中conv2d_1层的上一层max_pooling2d层输出的张量数量为32,所以conv2d_1层卷积核的深度就是32。
一开始接触或许难以理解,可以根据下面网站的CNN可视化图来慢慢体会
https://poloclub.github.io/cnn-explainer/
一些个人理解:
不管一开始输入图像的channel是多少,经过第一层卷积层后,最后输出的feature map的深度都变成了1(因为都被求和了),feature map数量为卷积核数量,对于再下一层的卷积层,可以把输入的feature map数量理解为输入的channel数量,所以卷积核的深度等于输入的feature map数量。
(2)池化层参数量计算:
池化层所涉及的参数都是超参数,所以认为实际参数量为0
(3)全连接层参数量计算:
其中分别代表参数量(parameters),是全连接层神经元数量(units),是输入大小(inputs)。
公式可以理解为:
全连接层参数量 做全连接相乘的权重数量bias数量;
而每个神经元都接有一个bias,所以bias数量等于
比如我们计算上面定义的模型的dense层的参数量:
输入大小为12800、dense层有50个神经元,所以有
3. 计算量计算方式
这里CNN的计算量是以计算机做乘法或加法的次数为单位(比如卷积过程中也就是点乘再求和这两种操作)。
(1)卷积层计算量计算:
为了便于理解,我们先考虑卷积层输出结果中单个pixel的计算量,由于这个pixel的结果其实就是经过卷积操作,然后再加上bias得到的,那么可以认为:
单个pixel计算量 卷积操作(点乘和求和)计算量 bias计算量
也就是:
单个pixel计算量 点乘计算量 求和计算量 1 (加一个bias就是一次加法,计算量为1)
所以单个pixel计算量公式为:
(PS: N个数相加,加的次数为N-1)
其中表示计算量,和分别表示卷积核的深度(depth)和尺寸(kernel size),同样这里也只考虑了卷积核尺寸为正方形的情况,如果不是正方形拆开考虑即可()。
由单个pixel计算量拓展到整个卷积层计算量公式为:
其中表示计算量,分别表示卷积核的深度(depth)和尺寸(kernel size)和数量(filters),表示输出feature map的尺寸。
(2)全连接层计算量计算:
计算过程和上面卷积层的类似,都是:点乘计算量 求和计算量 bias计算量。
单个神经元的计算公式为:
其中表示计算量,是输入大小。
拓展到整个全连接层计算公式:
其中表示计算量,是输入大小,U为该层神经元数量。