(一)alexnet网络结构详解
第一层:
该层的顺序是:卷积—>ReLU—>池化—>归一化
卷积池化层原理:
根据神经元公式:h(x)=f(wx+b)
- 上式就是神经元所表示的函数,x表示输入(图片矩阵),w表示权重(卷积核参数),b表示偏置,f表示激活函数(ReLU),h(x)表示输出,输出后的数据经过池化,然后归一化。形成完成的卷积池化层。
训练卷积神经网络的过程就是不断调整权重w(卷积核参数)与偏置b的过程,以使其输出h(x)达到预期值。
参数数量
- 卷积层的参数 = 卷积核大小 x 卷积核的数量 + 偏置数量(即卷积核的数量)
- 参数分为 w 和 b ,“+”前面一部分是 w 的数量, “+”后面那部分是 b 的数量
- 本层参数数量为: (11 x 11 x 3 x 96) + 96 = 34848
卷积层:
-
卷积运算公式
-
alexnet网络中,当输入图像尺寸为227x227x3时,卷积后得到的feature map 尺寸为(227 - 11 + 0) / 4 + 1 = 55
-
参数解析
torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True)
-
nn.Conv2d
:对多个输入平面组成的输入信号进行二维卷积 -
in_channels
:输入图像的通道数 -
out_channels
:卷积产生的通道数 -
kernel_size
:卷积核尺寸,可以设为1个int型数或者一个(int, int)型的元组 -
stride
:卷积步长,默认为1。可以设为1个int型数或者一个(int, int)型的元组 -
padding
:填充,控制padding_mode的数目 -
dilation
:扩张操作:控制kernel点(卷积核点)的间距,默认值为1 -
groups
:group参数的作用是控制分组卷积,默认不分组,为1组 -
bias
:为真,则在输出中添加一个可学习的偏差。(添加偏置)默认:True
ReLU层:torch.nn.ReLU()
将输出的Feature Map经过RuLU层,增加网络中的非线性因素。
池化层
- 输出:(55 - 3)/ 2 + 1 = 27
第二层
卷积层
torch.nn.Conv2d(96, 256, 5, 1, 2)
输入是两组 27x27x48的Feature Map,这一层一共有256个5×5×3卷积核,生成256个feature map,步长为1,padding为2,每组得到的Feature Map为27×27×128
- (27 - 5 + 2 x 2 )+ 1 = 27
ReLU层:torch.nn.ReLU()
增加网络中的非线性因素。
池化层+局部响应归一化
torch.nn.MaxPool2d(3,2)
由卷积层二得到的Feature Map,将其经过池化层,使用3×3的步长为2的池化单元,得到每组的输出为13 ×13 ×128- (27 - 3)/ 2 + 1 = 13
第三层
卷积层:
torch.nn.Conv2d(256,384, 3, 1, 1)
输入是两组13×13×128的Feature Map,这一层一共有384个3×3×3卷积核,生成384个feature map,步长为1,padding为1,每组得到的Feature Map为13×13×384。- (13 - 3 + 2)+ 1 = 13
ReLU层:torch.nn.ReLU()
将卷积层输出的Feature Map经过RuLU层。输出是13×13×384,分为两组,每组为13×13×192
第四层:
卷积层:
torch.nn.Conv2d(384,384, 3, 1, 1)
输入是两组13×13×192的Feature Map,这一层一共有384个3×3×3卷积核,生成384个feature map,步长为1,padding为1,每组得到的Feature Map为13×13×192。
ReLU层:torch.nn.ReLU()
将卷积层输出的Feature Map经过RuLU层。输出是13×13×384,分为两组,每组为13×13×192
第五层:
卷积层:
torch.nn.Conv2d(384,256, 3, 1, 1)
输入是两组13x13x192的Feature Map,这一层一共有256个5×5×3卷积核,生成256个feature map,步长为1,padding为2,每组得到的Feature Map为13×13×128
ReLU层:torch.nn.ReLU()
将输出的Feature Map经过RuLU层,增加网络中的非线性因素。
池化层+局部响应归一化
torch.nn.MaxPool2d(3,2)
由卷积层二得到的Feature Map,将其经过池化层,使用3×3的步长为2的池化单元,得到每组的输出为6×6×128。总的输出为6×6×256- (13 - 3)/ 2 + 1 = 6
第六层:
全连接层:
- 根据神经元公式:h(x)=f(wx+b)
全连接层x表示上一层的输出值,w表示本层的神经元权重,权重数量等于本全连接层神经元数目,然后再加偏置b,偏置数量等于本层神经元数目。 - 参数数量:6 x 6 x 256 x 4096 + 4096
这个参数数量远远大于之前所有卷积层的参数数量之和。也就是说AlexNet的参数大部分位于后面的全连接层 - 这一层是卷积->全连接的连接:
torch.nn.Linear(9216, 4096)
输入为6×6×256,该层有4096个卷积核,每个卷积核的大小为6×6×256。由于卷积核的尺寸刚好与待处理特征图(输入)的尺寸相同,即卷积核中的每个系数只与特征图(输入)尺寸的一个像素值相乘,一一对应,因此,该层被称为全连接层。由于卷积核与特征图的尺寸相同,卷积运算后只有一个值,因此,卷积后的像素层尺寸为 4096×1×1,即有4096个神经元
ReLU:这4096个运算结果通过ReLU激活函数生成4096个值
Dropout:torch.nn.Dropout(0.5)
随机断开50%神经元的连接,防止过拟合现象。
第七层
全连接层:
- 这一层是全连接->全连接的连接:
torch.nn.Linear(4096, 4096)
- 参数数量:4096*4096 + 4096
ReLU:这4096个运算结果通过ReLU激活函数生成4096个值
Dropout:torch.nn.Dropout(0.5)
防止过拟合现象。
第八层:
输出层:第七层输出的4096个数据与第八层的1000个神经元进行全连接,输出一个元素个数为1000的一维向量。
- 参数数量:全连接层,节点数量为1000。参数数量为: 4096*1000 + 1000
(二)代码实现
import torch.nn as nn
import torch.functional as fun
# AlexNet一共有八层,五个卷积层和三个全连接层。
class Net(nn.Module):
def __init__(self):
super(Net,self).__init__()
self.Conv1 = nn.Conv2d(3,96,11,4,0)
self.Pool = nn.MaxPool2d(3, 2)
self.Conv2 = nn.Conv2d(96,256,5,1,2)
self.Conv3 = nn.Conv2d(256,384,3,1,1)
self.Conv4 = nn.Conv2d(384,384,3,1,1)
self.Conv5 = nn.Conv2d(384,256,3,1,1)
# 使用Dropout训练期间选择性的暂时忽略一些神经元,来减小模型的过拟合
self.drop = nn.Dropout(0.5)
# 全连接层
self.fc1 = nn.Linear(9216,4096)
self.fc2 = nn.Linear(4096,4096)
self.fc3 = nn.Linear(4096,100)
def forward(self, x):
# 使用RuLu函数来增加模型的非线性能力
x = self.pool(fun.relu(self.conv1(x)))
x = self.pool(fun.relu(self.conv2(x)))
x = fun.relu(self.conv3(x))
x = fun.relu(self.conv4(x))
x = self.pool(fun.relu(self.con5(x)))
x = x.view(-1, self.num_flat_features(x))
x = fun.relu(self.fc1(x))
x = self.drop(fun.relu(self.fc1(x)))
x = self.drop(fun.relu(self.fc2(x)))
x = self.fc3(x)
return x
net = Net()