视觉神经网络的演化(1)-- 早期探索

LeNet可以说是CNN的开端,麻雀虽小,但五脏俱全,卷积层、池化层、全连接层,这些都是现代CNN网络的基本组件。而AlexNet是另一个具有历史意义的网络结构,它的成功表示了深度学习重回历史舞台。

LeNet-5

下图是广为流传LeNet的网络结构,随着网络越来越深,图像的宽度和高度都在缩小,信道数量一直在增加。目前,一个或多个卷积层后边跟一个池化层,再接上一个全连接层的排列方式很常用。

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
import torch
from torch import nn

class LeNet5(nn.Module):
'''
LeNet5网络
INPUT -> 图像规格(28, 28, 1), 待分类数(10)
'''
def __init__(self):
super(LeNet5, self).__init__()
self.conv1 = nn.Sequential(
nn.Conv2d(1, 6, kernel_size=5, padding=2, bias=False),
# 卷积后图像尺寸 = (28+2*2-5)/步长+1 = 28
nn.Tanh(),
nn.MaxPool2d(kernel_size=2, stride=2)
# 经过池化层后图像尺寸 = (28-2)/步长+1 = 14
)
self.conv2 = nn.Sequential(
nn.Conv2d(6, 16, kernel_size=5, bias=False),
# 卷积后图像尺寸 = (14-5)/步长+1 = 10
nn.Tanh(),
nn.MaxPool2d(kernel_size=2, stride=2)
# 经过池化层后图像尺寸 = (10-2)/步长+1 = 5
)
self.classifier = nn.Sequential(
nn.Linear(16*5*5, 120),
nn.Tanh(),
nn.Linear(120, 84),
nn.Tanh(),
nn.Linear(84, 10)
)

def forward(self, x):
x = self.conv1(x)
x = self.conv2(x)
# nn.Linear()的输入输出都是一维数组,所以要把tensor展成一维
x = x.view(x.size(0), 16*5*5)
# x = x.view(x.size(0), -1)
x = self.classifier(x)
return x

model = LeNet5()
print(model)

input_tensor = torch.randn((1, 1, 32, 32))
input_var = torch.autograd.Variable(input_tensor)
out = model(input_var)

AlexNet

AlexNet 可以说是具有历史意义的一个网络结构,可以说在AlexNet之前,深度学习已经沉寂了很久。历史的转折在2012年到来,AlexNet 在当年的ImageNet图像分类竞赛中,top-5错误率比上一年的冠军下降了十个百分点,而且远远超过当年的第二名。
AlexNet的诞生开启了深度学习的时代,虽然后来大量比AlexNet更快速更准确的卷积神经网络结构相继出现,但是AlexNet作为开创者依旧有着很多值得学习参考的地方,之后在Imagenet上取得更好结果的ZF-net,VGG等网络,都是在其基础上修改得到。

该网络包括:卷积层 5个,池化层 3个,全连接层:3个(其中包含输出层) 。

创新
(1)采用了ReLU激活函数,而不像早期卷积神经网络所采用的Tanh或Sigmoid激活函数
(2)用多层小卷积代替单个大卷积层。
(3)提出了LRN层(局部响应归一化层),增强模型泛化能力。
(4)每个全连接层后面加上Dropout层减少了模型的过拟合问题。
(5)使用了数据增强。

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
import torch
from torch import nn

class AlexNet(nn.Module):
'''
AlexNet网络
INPUT -> 图像规格(227, 227, 3), 待分类数(1000)
'''
def __init__(self):
super(AlexNet, self).__init__()
self.features = nn.Sequential(
nn.Conv2d(3, 96, kernel_size=11, stride=4, bias=False),
# 卷积后图像尺寸 (227-11)/步长+1 = 55
nn.LocalResponseNorm(96),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2),
# 经过池化层后图像尺寸 (55-3)/步长+1 = 27
nn.Conv2d(96, 256, kernel_size=5, padding=2, bias=False),
# 卷积后图像尺寸 (27+2*2-5)/步长+1 = 27
nn.LocalResponseNorm(256),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2),
# 经过池化层后图像尺寸 (27-3)/步长+1 = 13
nn.Conv2d(256, 384, kernel_size=3, padding=1, bias=False),
# 卷积后图像尺寸 (13+1*2-3)/步长+1 = 13
nn.ReLU(inplace=True),
nn.Conv2d(384, 384, kernel_size=3, padding=1, bias=False),
# 卷积后图像尺寸 (13+1*2-3)/步长+1 = 13
nn.ReLU(inplace=True),
nn.Conv2d(384, 256, kernel_size=3, padding=1, bias=False),
# 卷积后图像尺寸 (13+1*2-3)/步长+1 = 13
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2)
# 经过池化层后图像尺寸 (13-3)/步长+1 = 6
)
self.classifier = nn.Sequential(
nn.Linear(256*6*6, 4096),
nn.ReLU(inplace=True),
nn.Dropout(),
nn.Linear(4096, 4096),
nn.ReLU(inplace=True),
nn.Dropout(),
nn.Linear(4096, 1000),
)

def forward(self, x):
x = self.features(x)
x = x.view(x.size(0), 256*6*6)
x = self.classifier(x)
return x

model = AlexNet()
print(model)

input_tensor = torch.randn((1, 3, 227, 227))
input_var = torch.autograd.Variable(input_tensor)
out = model(input_var)