LeNet-5网络结构解释
LeNet-5中主要有2个卷积层、2个下抽样层(池化层)、3个全连接层3种连接方式
输入层
数据 input 层,输入图像的尺寸统一归一化为32*32
例如Mnist的数据格式为28x28,需要resize到32x32
c1-卷积层
self.conv1 = nn.Conv2d(1, 6, 5)
-
输入
格式为:[1,32,32] -
处理过程
卷积数量6,卷积核数据f = 5,pading默认为0,stride默认为1
卷积核处理后的数据计算公式为:(in+2xp-f)/s+1 = (32+2x0-5)/1+1 = 28 -
输出
featuremap大小和数量:[28,28,6]
由y = wx+b,可知,参数和w和b组成,其中w = fxf, 每个卷积和,一个偏置参数,因此b = 1,所以:参数个数为(5x5+1)x6=156(其中5x5对应kernel size,+1为bias,6为feature map 数目)
S2-池化层(subsampling)
x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))
-
输入
featuremap数据:[28,28,6]
-
处理过程
卷积核f = 2,步长为s = 2
计算公式同卷积:(in+2xp-f)/s+1 = 28/2 = 14 -
输出
featuremap [14,14,6]
C3-卷积层
self.conv2 = nn.Conv2d(6, 16, 5)
-
输入
[14,14,6]的featuremap数据
-
处理过程
分别使用16个5x5卷积核,对输入的6张featuremap进行处理,按照特殊的卷积核输入组合,输出一个10x10的featuremap
卷积层跟输入的featuremap对应关系表如下图所示
卷积核处理后的数据计算公式为:(in+2xp-f)/s+1 = (14+2x0-5)/1+1 = 10
-
输出
featuremap [10,10,16]
# 如果是方阵,则可以只使用一个数字进行定义 x = F.max_pool2d(F.relu(self.conv2(x)), 2)
S4-池化层
-
输入
featuremap [10,10,16] -
处理过程
卷积核f = 2,步长默认为卷积的大小stride = 2
同S2,直接是将featuremap的数据量减半 -
输出
featuremap [5,5,16]
C5-全连接层
对C5没太立即,看网上资料大部分说是全集程,但实际代码实现用的又是全连接方法?
x = input.view(-1, 5x5x16)#[1,400]
self.fc1 = nn.Linear(16 * 5 * 5, 120)
x = F.relu(self.fc1(x))
全连接神经网络结构一旦固定,需要学习的参数w是固定的,因此针对nn.Linear(16 * 5 * 5)要求输入必须是[32, 32]大小的
-
输入
featuremap [5,5,16] -
处理过程
将输入数据展平成一维的数据[1,400]
x = input.view(-1, 5x5x16)#[1,400]
然后,使用全连接转化成[1,120]
self.fc1 = nn.Linear(16 * 5 * 5, 120)
最后对数据进行线性整流
x = F.relu(self.fc1(x))
-
输出
featuremap [1,120]
F6-全连接
self.fc2 = nn.Linear(120, 84)
x = F.relu(self.fc2(x))
同C5,将数据从[1,120]转换成[1,84],并应用线性整流
输出层-全连接层
self.fc3 = nn.Linear(84, 10)
x = self.fc3(x)
将数据从[1,84]转化成[1,10],10代表属于每一个分类的阈值
当然如果,你的分类数目不是10,改成你对应的数字即可
实现代码(前馈过程)
class Net(nn.Module):
def __init__(self,imgChannel):
super(Net, self).__init__()
self.features = nn.Sequential(
nn.Conv2d(imgChannel, 6, 5),#self.C1
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2),# self.S2
nn.Conv2d(6, 16, 5),#self.C3
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2),#self.S4
)
self.classifier = nn.Sequential(
nn.Linear(16 * 5 * 5, 120),#self.fc1
nn.ReLU(inplace=True),
nn.Linear(120, 84),#self.fc2
nn.ReLU(inplace=True),
nn.Linear(84, 10),#self.fc3
)
def forward(self, x):
x = self.features(x)
x = x.view(-1, self.num_flat_features(x))#[1,400]
x =self.classifier(x)
return x
def num_flat_features(self, x):
# 除去批处理维度的其他所有维度
#torch.Size([1, 16, 5, 5])--->torch.Size([16, 5, 5])
size = x.size()[1:]
num_features = 1
for s in size:
num_features *= s
return num_features#400
测试结果
net = Net()
print(net)
input = torch.randn(1, 1, 32, 32)
net.forward(input)
使用一个随机数据,经网络处理后的输出为
tensor([[
-0.0648, -0.1591, 0.0945, 0.0710, 0.0155,
-0.0186, 0.0386, 0.0749,-0.0204, -0.0839]],
grad_fn=<AddmmBackward>)