深度学习模型之CNN(三)AlexNet网络结构及数据集下载

AlexNet详解

AlexNet时2012年ILSVRC 2012(ImageNet Large Scale Visual Recognition Challenge)竞赛的冠军网络,分类准确率由传统的70%+提升到80%+。它是由Hinton和他的学生Alex Krizhevsky设计的。也是从那年后,深度学习开始迅速发展。

ILSVRC 2012

  • 训练集:1,281,167张已标注图片
  • 验证集:50,000张已标注图片
  • 测试集:100,000张未标注图片

AlexNet网络架构

网络的亮点

  1. 首次使用GPU进行网络加速训练
  2. 使用ReLU激活函数,而不是传统的Sigmoid激活函数以及Tanh激活函数
  3. 使用LRN局部响应归一化
  4. 在全连接层的前两层中使用了Dropout随机失活神经元操作,以减少过拟合
  • 高端GPU的提速比可以达到CPU的20-50倍的速度差距
  • sigmoid激活函数的两个缺点:1、求导的过程比较麻烦;2、当网络比较深的时候会出现梯度消失的现象。ReLU能够解决以上问题
  • dropout操作可以减少过拟合现象

过拟合

过拟合:根本原因是特征维度过多,模型假设过于复杂,参数过多,训练数据过少,噪声过多,导致拟合的函数完美的预测训练集,但对新数据的测试集预测结果差。过度的拟合了训练数据,而没有考虑到泛化能力

过拟合

  • 第一幅图是网络的一个初始状态,随机地划分了一条边界对于样本进行分类
  • 通过不断的训练过程中,网络会慢慢学习出一条分类的边界如第二幅图所示,得到了一个比较好的分类的结果
  • 第三幅图虽然能够将训练样本进行完全正确的分类,但是图中出现了过拟合现象
  • 过拟合的函数能够完美地预测训练集,但是对新数据的测试机预测效果较差,过度的拟合了训练数据,而没有考虑到泛化能力

使用dropout减少过拟合现象

使用Dropout的方式在网络正向传播过程中随机失活一部分神经元

Dropout

  • 左图是一个正常的全连接的正向传播过程,每一个节点都与下层的节点进行全连接
  • 使用了dropout之后,会在每一层随机地失活一部分神经元,变相地减少了网络中训练的参数,从而达到了减少过拟合现象的作用

AlexNet网络结构

经卷积后的矩阵尺寸大小计算公式为:

\begin{flalign}
N = (W-F+2P)/S + 1
\end{flalign}

  • 输入图片大小:W×W
  • Filter大小:F×F
  • 步长:S
  • padding的像素数:P

AlexNet网络架构

  • 这个图可以看成上下两部分:作者使用了两块GPU进行了并行运算
  • 上下两部分都是一样的,只用看其中一部分即可

Conv1

Conv1

  • 原始图像是一个224*224的channel为3的彩色图像
  • 卷积核大小是11*11
  • 步长为4
  • 卷积核的大小为11
  • 一共有48*2=96个卷积核
  • 可以推理出padding的大小是1和2:表示在特征矩阵的左边加上一列0,右边加上两列0,上面加上一列0,下面加上两列0**(注意代表padding的2p值的是两边padding的像素之和,并不一定要求两边像素一定要一样)**

Maxpooling1

Maxpooling1

  • 最大池化下采样操作
  • 池化核大小等于3
  • padding为0
  • 步长为2
  • 这一层的输入是第一层卷积层的输出
  • 池化操作只会改变输出矩阵的高度和宽度,不会改变特征矩阵的深度

Conv2

Conv2

  • 卷积核的个数为128*2=256
  • 卷积核的大小为5
  • padding为 [ 2,2 ]
  • 步长为1

Maxpooling2

Maxpooling2

  • 池化核大小为3
  • padding为0
  • 步长等于2

Conv3

Conv3

  • 卷积核的个数为192*2=384
  • 卷积核的大小为3
  • padding为 [ 1,1 ]
  • 步长为1

Conv4

Conv4

  • 卷积核的个数为192*2=384
  • 卷积核的大小为3
  • padding为 [ 1,1 ]
  • 步长为1

Conv5

Conv5

  • 卷积核的个数为128*2=256
  • 卷积核的大小为3
  • padding为 [ 1,1 ]
  • 步长为1

Maxpooling3

Maxpooling3

  • 池化核的大小为3
  • padding等于0
  • 步长为2
  • 输出的特征矩阵展平之后和三个全连接层进行连接**(注意最后一个全连接层只有1000个节点,对应数据集的1000个类别,如果要将这个网络应用到自己的数据集的话,只需要将最后一层全连接层的节点个数改成和自己数据集的类别数一致即可)**

层级参数总结

AlexNet网络架构过程总结

下载花分类数据集

下载花分类数据集

步骤如下:

1
2
3
4
5
6
├── data_set 
├── split_data.py
└── flower_data
├── flower_photos(解压的数据集文件夹,3670个样本)
├── train(生成的训练集,3306个样本)
└── val(生成的验证集,364个样本)

附split_data.py代码

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
import os
from shutil import copy, rmtree
import random


def mk_file(file_path: str):
if os.path.exists(file_path):
# 如果文件夹存在,则先删除原文件夹在重新创建
rmtree(file_path)
os.makedirs(file_path)


def main():
# 保证随机可复现
random.seed(0)

# 将数据集中10%的数据划分到验证集中
split_rate = 0.1

# 指向你解压后的flower_photos文件夹
cwd = os.getcwd()
data_root = os.path.join(cwd, "flower_data")
origin_flower_path = os.path.join(data_root, "flower_photos")
assert os.path.exists(origin_flower_path), "path '{}' does not exist.".format(origin_flower_path)

flower_class = [cla for cla in os.listdir(origin_flower_path)
if os.path.isdir(os.path.join(origin_flower_path, cla))]

# 建立保存训练集的文件夹
train_root = os.path.join(data_root, "train")
mk_file(train_root)
for cla in flower_class:
# 建立每个类别对应的文件夹
mk_file(os.path.join(train_root, cla))

# 建立保存验证集的文件夹
val_root = os.path.join(data_root, "val")
mk_file(val_root)
for cla in flower_class:
# 建立每个类别对应的文件夹
mk_file(os.path.join(val_root, cla))

for cla in flower_class:
cla_path = os.path.join(origin_flower_path, cla)
images = os.listdir(cla_path)
num = len(images)
# 随机采样验证集的索引
eval_index = random.sample(images, k=int(num*split_rate))
for index, image in enumerate(images):
if image in eval_index:
# 将分配至验证集中的文件复制到相应目录
image_path = os.path.join(cla_path, image)
new_path = os.path.join(val_root, cla)
copy(image_path, new_path)
else:
# 将分配至训练集中的文件复制到相应目录
image_path = os.path.join(cla_path, image)
new_path = os.path.join(train_root, cla)
copy(image_path, new_path)
print("\r[{}] processing [{}/{}]".format(cla, index+1, num), end="") # processing bar
print()

print("processing done!")


if __name__ == '__main__':
main()

运行split_data.py之后,结果如图所示

split_data结果

总结

本节课主要讲AlexNet的网络结构,以及需要使用到的数据集,下节课将会使用Pytorch来搭建AlexNet,并用下载好的花分类数据集进行训练。