1 LeNet结构
主要是为了手写数字识别
具体结构讲解:从图中例子可得
1 先传入一个灰度图像尺寸为1x28x28,通道数为1,尺寸为28x28的灰度图像
2 第一层5x5卷积,经过公式 输入图像尺寸-卷积核尺寸+2padding/步长+1,(其中,因为是正方形,所以长宽都一样,直接一个式子得出)因为没有padding,输出特征图20个通道,24x24的尺寸。
3 经过第二层Pooling层,计算方式同上,得到20x12x12
4 在经过第三层5x5卷积,输出50x8x8,
5 第四层Polling,得到50x4x4
6 扁平化然后reshape为500x1的神经元用于全连接(也可以把上述得到的进行扁平化再进行一次全连接,800 -500)
7 然后Relu激活函数
8 全连接输出 10x1,代表十个数字的置信度
9 使用softmax来计算输出的值的在0-9的概率
(上述,其实上述每一层卷积都要使用Relu激活函数),下面代码复现再具体看
2 代码复现
python
import torch
import torch.nn as nn
class LeNet(nn.Module):
def __init__(self) -> None:
super().__init__()
self.features = nn.Sequential(
nn.Conv2d(in_channels=1, out_channels=20, kernel_size=5, stride=1, padding=0),
nn.ReLU(),
nn.MaxPool2d(kernel_size=(2, 2), stride=2),
nn.Conv2d(in_channels=20, out_channels=50, kernel_size=5, stride=1, padding=0),
nn.ReLU(),
# nn.MaxPool2d(kernel_size=(2, 2), stride=2),
nn.AdaptiveMaxPool2d((4, 4)) # 这个是为了不止让限制为28x28的输入图像
)
self.classify = nn.Sequential(
nn.Linear(50 * 4 * 4, 500),
nn.ReLU(),
nn.Linear(500, 10)
)
def forward(self, x):
z = self.features(x)
z = z.view(-1, 800)
z = self.classify(z)
return z
if __name__ == '__main__':
net = LeNet()
img = torch.randn(2, 1, 28, 28)
scores = net(img)
print(scores)
probs = torch.softmax(scores, dim=1)
print(probs)
3 LeNet5
结构图
1 C1层
C1层是一个卷积层
将输入的1x32x32 通过5x5卷积,卷积成 6x28x28的feature map
2 S2层
S2层是一个下采样层,对C1层的进行下采样,把6x28x28池化成6x14x14
和max pooling和average pooling不一样, 在C1中每个单元的4个输入相加, 乘以一个可训练参数w, 再加上一个可训练偏置b, 结果通过sigmoid函数计算得到最终池化之后的值
就是说对于C1层,每个2x2的区域进行相加,类似如使用2x2卷积,步长为2,然后每个区域4个值乘以一个可训练参数w, 再加上一个可训练偏置b, 结果通过sigmoid函数计算得到最终池化之后的值
3 C3层
C3层是一个卷积层,使用的是5x5卷积,把6x14x14卷积成16x10x10
但是这个卷积跟平常卷积不一样,使用的是类似分组卷积的东西,不过也不一样,如下图
每次卷积核每次卷积不同的通道来提取特征,得到15个通道,比如第一个通道卷积他的前三层通道来输出第一个通道,以此类推
4 S4层
S4层是一个下采样层 (和S2一样),具体看S2,把16x10x10下采样为16x5x5
5 C5层
C5层是一个卷积层,使用5x5卷积,把16x5x5卷积成120x1x1,也就是用于下面全连接
6 F6 F7层
F6 7层是一个全连接层
把120x1最后全连接为10x1用来做置信度