➡️点击上方蓝色字体关注我⬅️
----------------------------------
由于受到计算机性能的影响,虽然LeNet在图像分类中取得了较好的成绩,但是并没有引起很多的关注。知道2012年,Alex等人提出的AlexNet网络在ImageNet大赛上以远超第二名的成绩夺冠,卷积神经网络乃至深度学习重新引起了广泛的关注。
AlexNet特点
AlexNet是在LeNet的基础上加深了网络的结构,学习更丰富更高维的图像特征。AlexNet的特点:
更深的网络结构
使用层叠的卷积层,即卷积层+卷积层+池化层来提取图像的特征
使用Dropout抑制过拟合
使用数据增强Data Augmentation抑制过拟合
使用Relu替换之前的sigmoid的作为激活函数
多GPU训练
ReLu作为激活函数
在最初的感知机模型中,输入和输出的关系如下:
只是单纯的线性关系,这样的网络结构有很大的局限性:即使用很多这样结构的网络层叠加,其输出和输入仍然是线性关系,无法处理有非线性关系的输入输出。因此,对每个神经元的输出做个非线性的转换也就是,将上面就加权求和的结果输入到一个非线性函数,也就是激活函数中。这样,由于激活函数的引入,多个网络层的叠加就不再是单纯的线性变换,而是具有更强的表现能力。
在最初,sigmoid和tanh函数最常用的激活函数。
在继续介绍之前,这里我给神经网络新手同学们精挑细选了13个深度学习入门练手项目,非常适合你用来提升自己的代码实战能力,并且每个项目的教程视频+数据集+代码都可以点击思维导图的小按钮直接跳转。
需要的同学可以直接长按扫码添加我的小助手让她无偿及时发送给大家!
1.sigmoid
在网络层数较少时,sigmoid函数的特性能够很好的满足激活函数的作用:它把一个实数压缩至0到1之间,当输入的数字非常大的时候,结果会接近1;当输入非常大的负数时,则会得到接近0的结果。这种特性,能够很好的模拟神经元在受刺激后,是否被激活向后传递信息(输出为0,几乎不被激活;输出为1,完全被激活)。sigmoid一个很大的问题就是梯度饱和。观察sigmoid函数的曲线,当输入的数字较大(或较小)时,其函数值趋于不变,其导数变的非常的小。这样,在层数很多的的网络结构中,进行反向传播时,由于很多个很小的导数累成,导致其结果趋于0,权值更新较慢。
2.relu
针对sigmoid梯度饱和导致训练收敛慢的问题,在AlexNet中引入了ReLU。ReLU是一个分段线性函数,小于等于0则输出为0;大于0的则恒等输出。相比于sigmoid,ReLU有以下有点:
计算开销下。sigmoid的正向传播有指数运算,倒数运算,而ReLu是线性输出;反向传播中,sigmoid有指数运算,而ReLU有输出的部分,导数始终为1.
梯度饱和问题
稀疏性。Relu会使一部分神经元的输出为0,这样就造成了网络的稀疏性,并且减少了参数的相互依存关系,缓解了过拟合问题的发生。
这里有个问题,前面提到,激活函数要用非线性的,是为了使网络结构有更强的表达的能力。那这里使用ReLU本质上却是个线性的分段函数,是怎么进行非线性变换的。
这里把神经网络看着是一个巨大的变换矩阵M,其输入为所有训练样本组成的矩阵A,输出为矩阵B。
这里的M是一个线性变换的话,则所有的训练样本A进行了线性变换输出为B。
那么对于ReLU来说,由于其是分段的,0的部分可以看着神经元没有激活,不同的神经元激活或者不激活,其神经玩过组成的变换矩阵是不一样的。
设有两个训练样本a1,a2 ,其训练时神经网络组成的变换矩阵为M1,M2。由于M1变换对应的神经网络中激活神经元和M2是不一样的,这样M1,M2实际上是两个不同的线性变换。也就是说,每个训练样本使用的线性变换矩阵Mi是不一样的,在整个训练样本空间来说,其经历的是非线性变换。
简单来说,不同训练样本中的同样的特征,在经过神经网络学习时,流经的神经元是不一样的(激活函数值为0的神经元不会被激活)。这样,最终的输出实际上是输入样本的非线性变换。
单个训练样本是线性变换,但是每个训练样本的线性变换是不一样的,这样整个训练样本集来说,就是非线性的变换。
数据增强
神经网络由于训练的参数多,表能能力强,所以需要比较多的数据量,不然很容易过拟合。当训练数据有限时,可以通过一些变换从已有的训练数据集中生成一些新的数据,以快速地扩充训练数据。对于图像数据集来说,可以对图像进行一些形变操作:
翻转
随机裁剪
平移,颜色光照的变换
...
AlexNet中对数据做了以下操作:
随机裁剪,对256×256的图片进行随机裁剪到227×227,然后进行水平翻转。
测试的时候,对左上、右上、左下、右下、中间分别做了5次裁剪,然后翻转,共10个裁剪,之后对结果求平均。
对RGB空间做PCA(主成分分析),然后对主成分做一个(0, 0.1)的高斯扰动,也就是对颜色、光照作变换,结果使错误率又下降了1%。
层叠池化
在LeNet中池化是不重叠的,即池化的窗口的大小和步长是相等的,如下
在AlexNet中使用的池化(Pooling)却是可重叠的,也就是说,在池化的时候,每次移动的步长小于池化的窗口长度。AlexNet池化的大小为3×3的正方形,每次池化移动步长为2,这样就会出现重叠。重叠池化可以避免过拟合,这个策略贡献了0.3%的Top-5错误率。与非重叠方案s=2,z=2相比,输出的维度是相等的,并且能在一定程度上抑制过拟合。
局部相应归一化
ReLU具有让人满意的特性,它不需要通过输入归一化来防止饱和。如果至少一些训练样本对ReLU产生了正输入,那么那个神经元上将发生学习。然而,我们仍然发现接下来的局部响应归一化有助于泛化。表示神经元激活,通过在位置应用核,然后应用ReLU非线性来计算,响应归一化激活通过下式给定:
其中,是卷积核的个数,也就是生成的FeatureMap的个数;是超参数,论文中使用的值是
输出和输入的上标表示的是当前值所在的通道,也即是叠加的方向是沿着通道进行。将要归一化的值所在附近通道相同位置的值的平方累加起来
Dropout
这个是比较常用的抑制过拟合的方法了。
引入Dropout主要是为了防止过拟合。在神经网络中Dropout通过修改神经网络本身结构来实现,对于某一层的神经元,通过定义的概率将神经元置为0,这个神经元就不参与前向和后向传播,就如同在网络中被删除了一样,同时保持输入层与输出层神经元的个数不变,然后按照神经网络的学习方法进行参数更新。在下一次迭代中,又重新随机删除一些神经元(置为0),直至训练结束。
Dropout应该算是AlexNet中一个很大的创新,现在神经网络中的必备结构之一。Dropout也可以看成是一种模型组合,每次生成的网络结构都不一样,通过组合多个模型的方式能够有效地减少过拟合,Dropout只需要两倍的训练时间即可实现模型组合(类似取平均)的效果,非常高效。
如下图:
Alex网络结构
上图中的输入是,不过经过计算并不是论文中的,而使用作为输入,则
网络包含8个带权重的层;前5层是卷积层,剩下的3层是全连接层。最后一层全连接层的输出是1000维softmax的输入,softmax会产生1000类标签的分布网络包含8个带权重的层;前5层是卷积层,剩下的3层是全连接层。最后一层全连接层的输出是1000维softmax的输入,softmax会产生1000类标签的分布。
卷积层C1
该层的处理流程是: 卷积-->ReLU-->池化-->归一化。
卷积,输入是,使用96个的卷积核,得到的FeatureMap为。
ReLU,将卷积层输出的FeatureMap输入到ReLU函数中。
池化,使用步长为2的池化单元(重叠池化,步长小于池化单元的宽度),输出为()
局部响应归一化,使用进行局部归一化,输出的仍然为,输出分为两组,每组的大小为
卷积层 C2,C4,C5中的卷积核只和位于同一GPU的上一层的FeatureMap相连。从上面可以看出,参数大多数集中在全连接层,在卷积层由于权值共享,权值参数较少。
卷积层C2
该层的处理流程是:卷积-->ReLU-->池化-->归一化
卷积,输入是2组。使用2组,每组128个尺寸为的卷积核,并作了边缘填充padding=2,卷积的步长为1. 则输出的FeatureMap为2组,每组的大小为. ()
ReLU,将卷积层输出的FeatureMap输入到ReLU函数中
池化运算的尺寸为,步长为2,池化后图像的尺寸为,输出为
局部响应归一化,使用进行局部归一化,输出的仍然为,输出分为2组,每组的大小为
卷积层C3
该层的处理流程是: 卷积-->ReLU
卷积,输入是,使用2组共384尺寸为的卷积核,做了边缘填充padding=1,卷积的步长为1.则输出的FeatureMap为
ReLU,将卷积层输出的FeatureMap输入到ReLU函数中
卷积层C4
该层的处理流程是: 卷积-->ReLU
该层和C3类似。
卷积,输入是,分为两组,每组为.使用2组,每组192个尺寸为的卷积核,做了边缘填充padding=1,卷积的步长为1.则输出的FeatureMap为,分为两组,每组为
ReLU,将卷积层输出的FeatureMap输入到ReLU函数中
卷积层C5
该层处理流程为:卷积-->ReLU-->池化
卷积,输入为,分为两组,每组为。使用2组,每组为128尺寸为的卷积核,做了边缘填充padding=1,卷积的步长为1.则输出的FeatureMap为
ReLU,将卷积层输出的FeatureMap输入到ReLU函数中
池化,池化运算的尺寸为3×3,步长为2,池化后图像的尺寸为 ,即池化后的输出为
全连接层FC6
该层的流程为:(卷积)全连接 -->ReLU -->Dropout
卷积->全连接: 输入为,该层有4096个卷积核,每个卷积核的大小为。由于卷积核的尺寸刚好与待处理特征图(输入)的尺寸相同,即卷积核中的每个系数只与特征图(输入)尺寸的一个像素值相乘,一一对应,因此,该层被称为全连接层。由于卷积核与特征图的尺寸相同,卷积运算后只有一个值,因此,卷积后的像素层尺寸为,即有4096个神经元。
ReLU,这4096个运算结果通过ReLU激活函数生成4096个值
Dropout,抑制过拟合,随机的断开某些神经元的连接或者是不激活某些神经元
全连接层FC7
流程为:全连接-->ReLU-->Dropout
全连接,输入为4096的向量
ReLU,这4096个运算结果通过ReLU激活函数生成4096个值
Dropout,抑制过拟合,随机的断开某些神经元的连接或者是不激活某些神经元
输出层
第七层输出的4096个数据与第八层的1000个神经元进行全连接,经过训练后输出1000个float型的值,这就是预测结果。
Pytorch实现
import torch.nn as nn
2 from torchsummary import summary
3
4 try:
5 from torch.hub import load_state_dict_from_url
6 except ImportError:
7 from torch.utils.model_zoo import load_url as load_state_dict_from_url
8
9 model_urls = {
10 'alexnet': 'https://download.pytorch.org/models/alexnet-owt-4df8aa71.pth',
11 }
12
13 class AlexNet(nn.Module):
14 def __init__(self,num_classes=1000):
15 super(AlexNet,self).__init__()
16 self.features=nn.Sequential(
17 nn.Conv2d(3,96,kernel_size=11,stride=4,padding=2), #(224+2*2-11)/4+1=55
18 nn.ReLU(inplace=True),
19 nn.MaxPool2d(kernel_size=3,stride=2), #(55-3)/2+1=27
20 nn.Conv2d(96,256,kernel_size=5,stride=1,padding=2), #(27+2*2-5)/1+1=27
21 nn.ReLU(inplace=True),
22 nn.MaxPool2d(kernel_size=3,stride=2), #(27-3)/2+1=13
23 nn.Conv2d(256,384,kernel_size=3,stride=1,padding=1), #(13+1*2-3)/1+1=13
24 nn.ReLU(inplace=True),
25 nn.Conv2d(384,384,kernel_size=3,stride=1,padding=1), #(13+1*2-3)/1+1=13
26 nn.ReLU(inplace=True),
27 nn.Conv2d(384,256,kernel_size=3,stride=1,padding=1), #13+1*2-3)/1+1=13
28 nn.ReLU(inplace=True),
29 nn.MaxPool2d(kernel_size=3,stride=2), #(13-3)/2+1=6
30 ) #6*6*256=9126
31
32 self.avgpool=nn.AdaptiveAvgPool2d((6,6))
33 self.classifier=nn.Sequential(
34 nn.Dropout(),
35 nn.Linear(256*6*6,4096),
36 nn.ReLU(inplace=True),
37 nn.Dropout(),
38 nn.Linear(4096,4096),
39 nn.ReLU(inplace=True),
40 nn.Linear(4096,num_classes),
41 )
42
43 def forward(self,x):
44 x=self.features(x)
45 x=self.avgpool(x)
46 x=x.view(x.size(0),-1)
47 x=self.classifier(x)
48 return x
49
50 def alexnet(pretrain=False,progress=True,**kwargs):
51 r"""
52 Args:
53 pretrained(bool):If True, retures a model pre-trained on IMageNet
54 progress(bool):If True, displays a progress bar of the download to stderr
55 """
56 model=AlexNet(**kwargs)
57 if pretrain:
58 state_dict=load_state_dict_from_url(model_urls['alexnet'],
59 progress=progress)
60 model.load_state_dict(state_dict)
61 return model
62
63 if __name__=="__main__":
64 model=alexnet()
65 print(summary(model,(3,224,224)))
Output:
2 ----------------------------------------------------------------
3 Layer (type) Output Shape Param #
4 ================================================================
5 Conv2d-1 [-1, 96, 55, 55] 34,944
6 ReLU-2 [-1, 96, 55, 55] 0
7 MaxPool2d-3 [-1, 96, 27, 27] 0
8 Conv2d-4 [-1, 256, 27, 27] 614,656
9 ReLU-5 [-1, 256, 27, 27] 0
10 MaxPool2d-6 [-1, 256, 13, 13] 0
11 Conv2d-7 [-1, 384, 13, 13] 885,120
12 ReLU-8 [-1, 384, 13, 13] 0
13 Conv2d-9 [-1, 384, 13, 13] 1,327,488
14 ReLU-10 [-1, 384, 13, 13] 0
15 Conv2d-11 [-1, 256, 13, 13] 884,992
16 ReLU-12 [-1, 256, 13, 13] 0
17 MaxPool2d-13 [-1, 256, 6, 6] 0
18 AdaptiveAvgPool2d-14 [-1, 256, 6, 6] 0
19 Dropout-15 [-1, 9216] 0
20 Linear-16 [-1, 4096] 37,752,832
21 ReLU-17 [-1, 4096] 0
22 Dropout-18 [-1, 4096] 0
23 Linear-19 [-1, 4096] 16,781,312
24 ReLU-20 [-1, 4096] 0
25 Linear-21 [-1, 1000] 4,097,000
26 ================================================================
27 Total params: 62,378,344
28 Trainable params: 62,378,344
29 Non-trainable params: 0
30 ----------------------------------------------------------------
31 Input size (MB): 0.57
32 Forward/backward pass size (MB): 11.16
33 Params size (MB): 237.95
34 Estimated Total Size (MB): 249.69
35 ----------------------------------------------------------------