LeNet-5诞生于1994年,是最早的卷积神经网络之一, 由Yann LeCun完成,推动了深度学习领域的发展。在那时候,没有GPU帮助训练模型,甚至CPU的速度也很慢,因此,LeNet5通过巧妙的设计,利用卷积、参数共享、池化等操作提取特征,避免了大量的计算成本,最后再使用全连接神经网络进行分类识别,这个网络也是最近大量神经网络架构的起点,给这个领域带来了许多灵感。
LeNet-5卷积神经网络的结构组成为也很简单:两个卷积层convolutions,附带两次下采样(通过池化方法实现),和三个全连接层,如下图所示:
其中,卷积层和池化层负责对原始图像进行特征提取,全连接层负责对卷积池化提取到的特征进行学习,进一步根据这些特征来判断该输入图片属于哪一个类别。
下面重点在于代码实现。
卷积操作在pytorch中被封装成一个名称为torch.nn.Conv2d的类,具体如下图所示:
其中,类的参数解释如下:
(1)in_channels (int) - 输入图像中的通道数
(2)out_channels (int) - 由卷积产生的通道数
(3)kernel_size (int or tuple) - 卷积核的大小
(4)stride (int or tuple, optional) - 卷积的步长。默认值:1
(5)padding (int, tuple or str, optional) - 在输入的四边都加上padding。默认值:0
(6)padding_mode (string, optional) - padding的模式,可选参数有’zeros’, ‘reflect’, ‘replicate’ or ‘circular’. 分别代表’零填充’、‘镜像填充’、‘复制填充’,‘循环填充’。 默认值为:‘零填充’。
(7)dilation (int or tuple, optional) - 卷积核中元素之间的间距,对应卷积变体之扩张卷积。默认值:1
(8)groups (int, optional) - 从输入通道到输出通道的阻塞连接的数量,对应卷积变体之组卷积。默认值:1
(9)bias (bool, optional) - 如果为真,给输出增加一个可学习的偏置。默认值为真
池化操作在pytorch中被封装成一个名称为torch.nn.MaxPool2d的类,具体如下图所示:
其中,类的参数解释如下:
(1)kernel_size - 池化核的大小。
(2)stride - 池化的步长。默认值是kernel_size
(3)padding - 在输入的四边都加上padding。 隐含的零填充,在两边添加。
(4)dilation - 池化核中元素之间的间距, 默认值:1
(5)return_indices - 如果为真,将与输出一起返回最大索引。对以后的 torch.nn.MaxUnpool2d 有用。
(6)ceil_mode - 如果为真,将使用ceil而不是floor来计算输出形状。
全连接神经网络层在pytorch中被封装成一个名称为torch.nn.Linear的类,具体如下图所示:
其中,类的参数解释如下:
(1)in_features - 每个输入样本的大小
(2)out_features - 每个输出样本的大小
(3)bias - 如果设置为False,该层将不学习加性偏置。默认值。为真
常见的激活函数ReLU在pytorch中被封装成一个名称为torch.nn.ReLU的类,具体如下图所示:
其中,参数一般习惯指定为Ture,当为Ture时,ReLU的计算在底层会节省一下计算和存储资源。
代码详细如下,代码中已给出详细注释:
import torch.nn as nn
import torch
class Model(nn.Module):
#函数init定义的模型层级结构
def __init__(self):
super().__init__()
#第一次卷积
self.conv1 = nn.Conv2d(1, 6, 5)
self.relu1 = nn.ReLU()
#第一次池化
self.pool1 = nn.MaxPool2d(2)
#第二次卷积
self.conv2 = nn.Conv2d(6, 16, 5)
self.relu2 = nn.ReLU()
#第二次池化
self.pool2 = nn.MaxPool2d(2)
#第一次全连接
self.fc1 = nn.Linear(256, 120)
self.relu3 = nn.ReLU()
#第二次全连接
self.fc2 = nn.Linear(120, 84)
self.relu4 = nn.ReLU()
#第三次全连接
self.fc3 = nn.Linear(84, 10)
self.relu5 = nn.ReLU()
#函数forward定义的模型的前向计算过程,其中参数x代表输入图像。
#下述过程表示图像x先经过第一次卷积conv1得到结果y在送入激活函数,得到新的结果y在送入第二层卷积,以此类推。
def forward(self, x):
y = self.conv1(x)
y = self.relu1(y)
y = self.pool1(y)
y = self.conv2(y)
y = self.relu2(y)
y = self.pool2(y)
#这里是打平操作(Flatten)
y = y.view(y.shape[0], -1)
y = self.fc1(y)
y = self.relu3(y)
y = self.fc2(y)
y = self.relu4(y)
y = self.fc3(y)
y = self.relu5(y)
return y