上一篇介绍了如何在 TensorFlow 中加载数据集。从本文开始将以王者荣耀为例,介绍卷积神经网络(CNN)。由于涉及的内容较多,本文主要先介绍以下内容:
- 卷积神经网络结构
- TensorFlow 中定义卷积神经网络模型
- 宏观理解卷积神经网络
卷积神经网络结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
Model: "sequential_1"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
sequential (Sequential) (None, 224, 224, 3) 0
_________________________________________________________________
rescaling_1 (Rescaling) (None, 224, 224, 3) 0
_________________________________________________________________
conv2d (Conv2D) (None, 222, 222, 16) 448
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 111, 111, 16) 0
_________________________________________________________________
conv2d_1 (Conv2D) (None, 109, 109, 32) 4640
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 54, 54, 32) 0
_________________________________________________________________
conv2d_2 (Conv2D) (None, 52, 52, 64) 18496
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 26, 26, 64) 0
_________________________________________________________________
conv2d_3 (Conv2D) (None, 24, 24, 128) 73856
_________________________________________________________________
max_pooling2d_3 (MaxPooling2 (None, 12, 12, 128) 0
_________________________________________________________________
dropout (Dropout) (None, 12, 12, 128) 0
_________________________________________________________________
flatten (Flatten) (None, 18432) 0
_________________________________________________________________
dense (Dense) (None, 128) 2359424
_________________________________________________________________
dense_1 (Dense) (None, 3) 387
=================================================================
Total params: 2,457,251
Trainable params: 2,457,251
Non-trainable params: 0
以上为王者荣耀案例的网络模型图和模型 summary
,可以看出模型分为输入层(Input Layer)、隐藏层(Hidden Layer)、输出层(Ouput Layer)。
输入层
输入层指定了输入数据的 shape
。案例中的输入为宽高 224
,通道数 3
的图像,所以,input_shape
为 (224,224,3)
。
1
2
3
4
layers.experimental.preprocessing.RandomFlip("horizontal",
input_shape=(img_height,
img_width,
3))
注:由于使用了数据增强,所以
input_shape
的指定包含在了data_augmentation
中。
隐藏层
在隐藏层中,案例主要是嵌套了几次卷积(Conv2D)和最大池化(MaxPooling2D),然后使用 Dropout
和 Flatten
,最后使用全连接层(Dense)连接。
1
2
3
4
5
6
7
8
9
10
11
layers.Conv2D(16, 3, activation='relu'),
layers.MaxPooling2D(),
layers.Conv2D(32, 3, activation='relu'),
layers.MaxPooling2D(),
layers.Conv2D(64, 3, activation='relu'),
layers.MaxPooling2D(),
layers.Conv2D(128, 3, activation='relu'),
layers.MaxPooling2D(),
layers.Dropout(0.2),
layers.Flatten(),
layers.Dense(128, activation='relu'),
输出层
输出层使用全连接层(Dense)实现分类输出。因为,案例最终分为 3
个英雄,因此指定 Dense 的 units
为 3
。
1
layers.Dense(len(class_names), activation='softmax')
TensorFlow 中定义卷积神经网络模型
TensorFlow keras 模块 提供了非常便利的 Sequential 来定义模型。利用 Sequential
就可以将网络模型图直接“翻译”成 TensorFlow 代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from tensorflow.keras import layers
from tensorflow.keras.models import Sequential
model = Sequential([
data_augmentation,
layers.experimental.preprocessing.Rescaling(1./255),
layers.Conv2D(16, 3, activation='relu'),
layers.MaxPooling2D(),
layers.Conv2D(32, 3, activation='relu'),
layers.MaxPooling2D(),
layers.Conv2D(64, 3, activation='relu'),
layers.MaxPooling2D(),
layers.Conv2D(128, 3, activation='relu'),
layers.MaxPooling2D(),
layers.Dropout(0.2),
layers.Flatten(),
layers.Dense(128, activation='relu'),
layers.Dense(len(class_names), activation='softmax')
])
其中,每一种 layer
(Conv2D、MaxPooling2D、Dropout、Flatten、Dense) 在 keras
中都有对应的实现,具体可以参见 tf.keras.layers
。
注:除了
Sequential
其实还有许多方法可以定义模型,不过对于初学者Sequential
基本够用了,再后续的课程中,我们再介绍其他方式。
宏观理解卷积神经网络
通过以上的讲述,大家已经知道了卷积神经网络的结构,并且知道如何在 TensorFlow 中定义它。但是,为什么卷积神经网络要设计成这样的结构呢?
全连接
为了回答这个问题,我们先来看个例子。
通过人眼看这上图的全局,我们可以直接识别出这是 铠
;如果机器要去看这张图的全局,其实就是要查看图中所有的像素(224 _ 224 _ 3);对应的网络,其实就是全连接网络。
这个网络看起来像是在暴力解决问题,而且准确率低下。原因在于,总是查看全局才能识别出来,就会失去泛化能力,会出现训练集结果很好,测试和验证集效果不好,也就是过拟合(Overfitting)。
这里,我打个比方,帮助大家理解。总是查看全局,就相当于要识别刚才的图是 铠
,那就需要看到他的头、铠甲、手臂、刀、背景、腿等。
那么,如果给出上图,那机器就会不认为他是铠
了,但事实上,人家只是秀一下肌肉而已。
因此,全连接层的缺点在于,只看全局,缺少泛化能力。
采样
看以上两张分辨率不同的图,人眼都能分别出是铠
。这其实是因为,下采样(降低分辨率)后的图,并没有减少大部分的识别特征,图中依旧保留着头、铠甲、手臂、刀、背景、腿等。
也就是说,适当地对图像进行下采样处理,并不会影响识别。既然这样,我们就可以在全连接层前面,对图像做一个预处理。这相当于,在全连接网络前面,加一个 MaxPooling
层。
注:关于
MaxPooling
后续会详细讲解,目前大家只需要知道MaxPooling
的作用就是下采样即可。
这不但降低了模型参数的个数,还一定程度上,提高了泛化的能力。
卷积
在机器学习计算机视觉基础 中已介绍过卷积的概念。卷积核的本质就像一个滤波器(Filter),卷积实际上可以充当一个对原图像进行二次转化,提取特征的作用。相对于全局,特征其实就是局部的意思。
如上图,将铠
分成三块,发现我们还是能很快识别出来。也就是说,我们的大脑具备将分散的图像组合起来识别的能力。
在看上图,将三块的位置调换下,发现我们还是能识别出来(虽然没有上面的那么快)。
也就是说:
- 局部特征加上相对位置,就可以对物体进行识别。
- 局部与局部之间关联性小,局部的变化,很少影响到另一个局部。
而提取局部特征正是卷积具备的能力,因此,在采样前面,还可以加上卷积。
但是,一张图像中的局部特征很多,单独一个卷积层能提取的特征数量有限。另外,采样层选出来的特征就一定是重要的特征吗?
这时候,兄弟有难大家帮,多加几个卷积和采样不就多了帮手吗?加上后,就成为了最终的网络模型。
这其实是级联分类 的思想。我们知道模型训练的时候,其实就是训练一堆的参数。而我们加了几层卷积和采样后,通过训练集数据,就会训练出一组参数,这组参数代表着特征的有效程度。
因此,经过每一层卷积核采样后,都会挑出一个最符合要求的分类(权值高),删除不想要的数据(权值低)。这样,数据经过层层过滤,最后就得到了我们想要的数据。
在这里,每一层都是提取上一层特征后的特征,而采样层又会泛化这个特征,所以,以王者荣耀为例,可以假设地描述为:
- 第一层卷积和采样提取图像的纹理(比如:横、竖、曲等);
- 第二层在第一层的基础上,提取到了图像的边缘信息(武器、人物、服装轮廓等);
- 第三层提取到了图像的详细特征(人物头部、武器把手、服装质地等特征);
- …
- 最后,经过全连接层,比如,识别到了
铠
的头、衣服、武器,就认为这个图像里面有铠
;
小结
本文为大家介绍了卷积神经网络的网络结构,典型的卷积神经网络由卷积层、采样层、全连接层组成。
- 卷积层负责提取图像中的局部特征;
- 采样层用来降低参数量级(降维)、防止过拟合;
- 全连接层用来输出想要的结果。
由于篇幅原因,未能将 CNN 知识点讲完。后续的文章会为大家带来更详细的解释,其中包括:卷积层、采样层、全连接层、Dropout、Flatten、Dense 等。因此,如果本文中大家有不理解的地方,不用太担心,后续会逐一细讲,咱们下一篇见。