AlexNet网络结构详解(含各层维度大小计算过程)与PyTorch实现
AlexNet网络架构
1.模型架构
AlexNet网络结构相对简单,使用了8层卷积神经网络,前5层是卷积层,后三层是全连接层。
从上图看,在网络设计上其实并非如上图所示,上图包含了GPU通信的部分。这是由当时GPU受限制引起的,作者使用两块GPU进行计算,因此分为上下两部分。但是以目前GPU的处理能力,单GPU足够了,因此其结构图可以如下所示:
卷积是为了增加通道大小,池化是为了简化特征。
卷积层C1:
C1的基本结构为:卷积–>ReLU–>池化
1.卷积:输入是(227
×
\times
× 227
×
\times
× 3),96个大小为( 11
×
\times
× 11
×
\times
× 3)卷积核,padding=0,stride=4,所以经过变化(227-11+2
×
\times
× 0+4)/4=55,所以最终的输出为(55
×
\times
× 55
×
\times
× 96)。
2.激活函数:ReLU
3.池化:输入是(55
×
\times
× 55
×
\times
× 96),池化核大小为(3
×
\times
× 3),padding=0,stride=2,所以经过变化(55-3+2
×
\times
× 0+2)/2=27,所以最终的输出为(27
×
\times
× 27
×
\times
× 96)。(此处未将输出分到两个GPU中,若按照论文将分成两组,每组为27×27×48)。
卷积层C2:
C2的基本结构为:卷积–>ReLU–>池化
1.卷积:输入是(27
×
\times
× 27
×
\times
× 96),256个大小为( 5
×
\times
× 5
×
\times
× 96)卷积核,padding=2,stride=1,所以经过变化(27-5+2
×
\times
× 2+1)/1=27,所以最终的输出为(27
×
\times
× 27
×
\times
× 256)。
2.激活函数:ReLU
3.池化:输入是(27
×
\times
× 27
×
\times
× 256),池化核大小为(3
×
\times
× 3),padding=0,stride=2,所以经过变化(27-3+2
×
\times
× 0+2)/2=13,所以最终的输出为(13
×
\times
× 13
×
\times
× 256)。(此处未将输出分到两个GPU中,若按照论文将分成两组,每组为13×13×128)。
卷积层C3:
C3的基本结构为:卷积–>ReLU–>池化,注意一点:此层没有进行MaxPooling操作。
1.卷积:输入是(13
×
\times
× 13
×
\times
× 256),384个大小为( 3
×
\times
× 3
×
\times
× 256)卷积核,padding=1,stride=1,所以经过变化(13-3+2
×
\times
× 1+1)/1=13,所以最终的输出为(13
×
\times
× 13
×
\times
× 384)。
2.激活函数:ReLU。(此处未将输出分到两个GPU中,若按照论文将分成两组,每组为13×13×192)
卷积层C4:
C4的基本结构为:卷积–>ReLU–>池化,注意一点:此层没有进行MaxPooling操作。
1.卷积:输入是(13
×
\times
× 13
×
\times
× 384),384个大小为( 3
×
\times
× 3
×
\times
× 384)卷积核,padding=1,stride=1,所以经过变化(13-3+2
×
\times
× 1+1)/1=13,所以最终的输出为(13
×
\times
× 13
×
\times
× 384)。(此处未将输出分到两个GPU中,若按照论文将分成两组,每组为13×13×192)
2.激活函数:ReLU
卷积层C5:
C5的基本结构为:卷积–>ReLU–>池化,。
1.卷积:输入是(13
×
\times
× 13
×
\times
× 384),256个大小为( 3
×
\times
× 3
×
\times
× 834)卷积核,padding=1,stride=1,所以经过变化(13-3+2
×
\times
× 1+1)/1=13,所以最终的输出为(13
×
\times
× 13
×
\times
× 256)。
2.激活函数:ReLU
3.池化:输入是(13
×
\times
× 13
×
\times
× 256),池化核大小为(3
×
\times
× 3),padding=0,stride=2,所以经过变化(13-3+2
×
\times
× 0+2)/2=6所以最终的输出为(6
×
\times
× 6
×
\times
× 256)。(此处未将输出分到两个GPU中,若按照论文将分成两组,每组为6×6×128)。
全连接层FC6:
FC6的基本结构为:全连接–>ReLU–>Dropout
1.全连接:此层的全连接实际上是通过卷积进行的,输入(6
×
\times
× 6
×
\times
× 256),4096个大小为( 6
×
\times
× 6
×
\times
× 256)卷积核,padding=0,stride=1,所以经过变化(6-6-2
×
\times
× 0+1)/1=1,所以最终的输出为(1
×
\times
× 1
×
\times
× 4096)。
2.激活函数:ReLU
3.Dropout:全连接层中去掉了一些神经节点,达到防止过拟合,FC6输出为1×1×4096。
全连接层FC7:
FC7的基本结构为:全连接–>ReLU–>Dropout
1.全连接:输入(1
×
\times
× 1
×
\times
× 4096)。
2.激活函数:ReLU
3.Dropout:全连接层中去掉了一些神经节点,达到防止过拟合,FC7输出为1×1×4096。
全连接层FC8:
FC8的基本结构为:全连接–>softmax
1.全连接:输入(1
×
\times
× 1
×
\times
× 4096)。
2.softmax:softmax为1000,FC8输出为1×1×1000;
在整个过程中,并没有将C1与C2中的Local Response Normalization(局部响应归一化)操作添加在其中,此操作就是将ReLU得到的结果进行归一化,读者可以查看一下原论文
2.AlexNet网络架构的贡献:
2.1 ReLU激活函数的引入
采用修正线性单元(ReLU)的深度卷积神经网络训练时间比等价的tanh单元要快几倍。而时间开销是进行模型训练过程中很重要的考量因素之一。同时,ReLU有效防止了过拟合现象的出现。由于ReLU激活函数的高效性与实用性,使得它在深度学习框架中占有重要地位。
2.2层叠池化操作
以往池化的大小PoolingSize与步长stride一般是相等的,例如:图像大小为256*256,PoolingSize=2×2,stride=2,这样可以使图像或是FeatureMap大小缩小一倍变为128,此时池化过程没有发生层叠。但是AlexNet采用了层叠池化操作,即PoolingSize > stride。这种操作非常像卷积操作,可以使相邻像素间产生信息交互和保留必要的联系。论文中也证明,此操作可以有效防止过拟合的发生。
2.3Dropout操作
Dropout操作会将概率小于0.5的每个隐层神经元的输出设为0,即去掉了一些神经节点,达到防止过拟合。那些“失活的”神经元不再进行前向传播并且不参与反向传播。这个技术减少了复杂的神经元之间的相互影响。在论文中,也验证了此方法的有效性。
2.4网络层数的增加
与原始的LeNet相比,AlexNet网络结构更深,LeNet为5层,AlexNet为8层。在随后的神经网络发展过程中,AlexNet逐渐让研究人员认识到网络深度对性能的巨大影响。当然,这种思考的重要节点出现在VGG网络(下文中将会讲到),但是很显然从AlexNet为起点就已经开始了这项工作。
3.Pytorch代码实现:
import torch
from torch import nn
import d2lzh_pytorch as d2l
class AlexNet(nn.Module):
def __init__(self):
super(AlexNet,self).__init__()
self.conv=nn.Sequential(
nn.Conv2d(in_channels=1,out_channels=96,kernel_size=11,stride=4),
nn.ReLU(),
nn.MaxPool2d(3,2),
nn.Conv2d(in_channels=96,out_channels=256,kernel_size=5,stride=1,padding=2),
nn.ReLU(),
nn.MaxPool2d(3,2),
nn.Conv2d(in_channels=256,out_channels=384,kernel_size=3,stride=1,padding=1),
nn.ReLU(),
nn.Conv2d(in_channels=384,out_channels=384,kernel_size=3,stride=1,padding=1),
nn.ReLU(),
nn.Conv2d(in_channels=384,out_channels=256,kernel_size=3,stride=1,padding=1),
nn.ReLU(),
nn.MaxPool2d(3,2)
)
self.fc=nn.Sequential(
nn.Linear(5*5*256,4096),
nn.ReLU(),
nn.Dropout(0.5),
nn.Linear(4096,4096),
nn.ReLU(),
nn.Dropout(0.5),
nn.Linear(4096,10)
)
def forward(self,img):
feature=self.conv(img)
output=self.fc(feature.view(img.shape[0],-1))
return output
net=AlexNet()
print(net)