一、LeNet介绍
LeNet5诞生于1994年,是最早的卷积神经网络之一,是Yann LeCun等人在多次研究后提出的最终卷积神经网络结构,是一种用于手写体字符识别非常高效的网络。一般LeNet即指代LeNet-5。LeNet网络包括了深度学习的基本模块:卷积、池化、全连接层。
二、LeNet网络架构
LeNet-5由七层组成(不包括输入层),每一层都包含可训练权重。通过卷积、池化等操作进行特征提取,最后利用全连接实现分类识别,下面是他的网络结构示意图:
C:卷积层
S:池化层
F:全连接层
输入为32*32像素图片
(一)C1层-卷积层(5*5)
有6个5*5的卷积核的卷积层(convolution),输入图片(32*32)经过C1卷积层后输出特征图片大小为28*28(32-5+1),这样可以防止输入图像的信息掉出卷积核边界。
C1包含156 个 ((5*5+1)*6)可训练参数(权重)和122304个((5*5+1)*6*28*28)连接。 通过取值共享我们只需要学习156各参数。
注:局部连接和权值共享(参考:https://blog.csdn.net/dulingwen)
(二)S2层-池化层(下采样层)
将28*28的6个特征图经过2*2的池化单元进行下采样后输出6个(14*14)的特征图,相当于对特征进行了进一步的提取,下面是下采样过程:
将S2中池化核(2*2)的四个输入相加,然后乘以可训练系数w(权重),然后加到可训练偏差b(bias),S1中包含可训练参数12个(2*6)和5880个((2*2+1)*6*14*14)连接。
(三) C3层-卷积层
有16个5*5的卷积核的卷积层(convolution),输入特征图(14*14)经过C31卷积层后输出特征图片大小为10*10(14+5-1)。
C3包含1516个(6*(3*5*5+1)+6*(4*5*5+1)+3*(4*5*5+1)+1*(6*5*5+1))可训练参数(权重)和151600个((10*10*1516)连接。
需要注意的是C3层与S2的层并不是全部连接C3,前6个特征图以S2中3个相邻的特征图子集为输入。接下来6个特征图以S2中4个相邻特征图子集为输入。然后的3个以不相邻的4个特征图子集为输入。最后一个将S2中所有特征图为输入。通过这种方式提取更多特征,连接的规则如下表所示:
(四) S4层-池化层(下采样层)
将10*10的16个特征图经过2*2的池化单元进行下采样后输出16个(5*5)的特征图,相当于对特征进行了进一步的提取,下面是下采样过程:
将S4中池化核(2*2)的四个输入相加,然后乘以可训练系数w(权重),然后加到可训练偏差b(bias),S1中包含可训练参数32个(2*16)和2000个((2*2+1)*16*5*5)连接。
(五)C5层-卷积层
有120个5*5的卷积核的卷积层(convolution),输入图片(5*5)经过C5卷积层后输出特征图片大小为1*1(5-5+1),这样可以防止输入图像的信息掉出卷积核边界。
C5包含48120 个 ((120*(16*5*5+1))可训练参数(权重)和48120个((120*(16*5*5+1))连接。
(六)F6层-全连接层
F6完全连接到C5,输出84张特征图,征图大小与C5一样都是1×1。它有10164个可训练参数。这里84与输出层的设计有关。
F6包含10164个((120+1)*84)可训练参数(权重)和10164个((120+1)*84)连接。
(七)OUTPUT层(输出层)
Output层也是全连接层,与F6层的84张(1*1)的特征图全连接,最后输出10个节点,分别代表数字0到9,且如果节点i的值为0,则网络识别的结果是数字i。
三、代码实现Pytorch
class LeNet(nn.Module):
def __init__(self):
super(LeNet, self).__init__()
self.conv = nn.Sequential(
nn.Conv2d(1, 6, 5), # in_channels, out_channels, kernel_size
nn.Sigmoid(),
nn.MaxPool2d(2, 2), # kernel_size, stride
nn.Conv2d(6, 16, 5),
nn.Sigmoid(),
nn.MaxPool2d(2, 2)
)
self.fc = nn.Sequential(
nn.Linear(16*4*4, 120),
nn.Sigmoid(),
nn.Linear(120, 84),
nn.Sigmoid(),
nn.Linear(84, 10)
)
def forward(self, img):
feature = self.conv(img)
output = self.fc(feature.view(img.shape[0], -1))
return output