代码地址
https://github.com/YFR718/Pytorch_Ai
背景
lecun大佬最早对手写数字进行识别,1980年代。
网络结构
1.第一层C1是一个卷积层
输入图片: 32 * 32
卷积核大小: 5 * 5
卷积核种类: 6
输出feature map大小:2828(32-5+1)
神经元数量:28 * 28 * 6
可训练参数数量:(5 * 5+1) * 6,(每个卷积核25个权重值w,一个截距值bias;总共6个卷积核)
连接数量:(5 * 5+1)62828
2.第二层S2是一个下采样层(池化层):
输入:28 * 28
采样区域:2 * 2
采样方式:4个输入相加,乘以一个可训练参数,再加上一个可训练偏置,结果通过sigmoid。(论文原文是这样描述,但是实际中,我看到一般都是用最大池化)
种类数量:6
输出的feature map大小时:14 * 14(28/2)
神经元数量:14 * 14 * 6
可训练参数:2 * 6(和的权重w和偏置bias,然后乘以6)
连接数:(2 * 2+1)*6 * 14 * 14
3.第三层C3也是一个卷积层
输入:S2中所有6个或者几个特征的map组合,这个组合并无太大实际意义,受限于当时的硬件水平,才这样组合
卷积核大小:5 * 5
卷积核种类:16
输出feature map大小:10 * 10
C3中的每个特征map是连接到S2中的所有6个或者几个特征map的,表示本层的特征map是上一层提取到的
特征map的不同组合,存在的一个方式是:C3的前6个特征图以S2中3个相邻的特征图子集为输入。接下来
6个特征图以S2中4个相邻特征图子集为输入。然后的3个以不相邻的4个特征图子集为输入。最后一个
将S2中所有特征图为输入。此时可训练参数:6 * (3 * 25+1)+6 * (4 * 25+1)+3 * (4 * 25+1)+(25 * 6+1)=1516
连接数:10 * 10 * 1516=151600
4.第四层S4是一个下采样层(池化层)
输入:10 * 10
采样区域:2 * 2
采样方式:4个输入相加,乘以一个可训练参数,再加上一个可训练偏置,结果通过sigmoid
采样种类:16
输出feature map大小:5*5(10/2)
神经元数量:5 * 5 * 16=400
可训练参数:2 * 16=32(和的权重2+偏置bias,乘以16)
连接数:16 * (2 * 2+1) * 5 * 5=2000
5.第五层C5是一个卷积层(论文原文的描述)
输入:S4层的全部16个单元特征map(与S4全连接)
卷积核大小:5 * 5
卷积核种类:120
输出feature map大小:1 * 1
可训练参数/连接数:120 * (16 * 5*5+1)=48120
6.第六层F6层全连接层
输入:C5 120维向量
计算方式:计算输入向量和权重向量之间的点积,再加上一个偏置,结果通过sigmoid函数
可训练参数:84*(120+1)=10164
import torch.nn as nn
import torch
class LeNet(nn.Module):
def __init__(self):
super(LeNet,self).__init__()
self.conv = nn.Sequential(
# 32,32,1
nn.Conv2d(1,6,kernel_size=5),
# 28,28,6
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2),
# 14,14,6
nn.Conv2d(6,16,kernel_size=5),
# 10,10,16
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2),
# 5,5,16
)
self.liner = nn.Sequential(
nn.Linear(5*5*16,120),
nn.ReLU(inplace=True),
nn.Linear(120,84),
nn.ReLU(inplace=True),
nn.Linear(84,10),
)
def forward(self,x):
x = self.conv(x)
x = x.view(x.size()[0], -1)
x = self.liner(x)
return x
from torchsummary import summary
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = LeNet().to(device)
summary(model, input_size=(1, 32, 32))