大作业LeNET
学科前沿大作业
任务介绍:
通过使用LeNET模型来进行MINIST测试集识别
算法原理:
Lenet是一个 7 层的神经网络,包含 3 个卷积层,2 个池化层,1 个全连接层,1个输出层。其中所有卷积层的卷积核都为 5x5,步长=1,池化方法都为平均池化,激活函数为 Sigmoid(目前使用的Lenet已改为ReLu)

(通常的LeNET模型采用上图)
模型特点:
首次提出卷积神经网络基本框架: 卷积层,池化层,全连接层;
卷积层的权重共享,相较于全连接层使用更少参数,节省了计算量与内存空间;
卷积层的局部连接,保证图像的空间相关性;
使用映射到空间均值下采样,减少特征数量;
具体推导:

上图是识别数字8的一个过程,接下来将详细剖析每一层的作用:
输入层:
首先通过尺寸归一化,把输入图像全部转化成32×32大小。
卷积层:
卷积的作用主要是:通过卷积运算,可以使原信号特征增强,降低噪音。在图像上卷积之后主要是减少图像噪声,提取图像的特征。
卷积网络能很好地适应图像的平移不变性:例如稍稍移动一幅猫的图像,它仍然是一幅猫的图像。卷积操作保留了图像块之间的空间信息,进行卷积操作的图像块之间的相对位置关系没有改变。
- 输入图像的大小为32×32
- 卷积核kernel size的大小为5×5
- 卷积核数量为6个
- 输出featuremap大小:28×28 (新特征图的大小 = [(输入图像的大小 - 卷积核的大小) / 步幅] + 1)
- 神经元数量:28×28×6
- 训练参数:(5×5+1)×6=156 由于参数(权值)共享的原因,对于同个卷积核每个神经元均使用相同的参数,因此,参数个数为(5×5+1)×6= 156,其中5×5为卷积核参数,1为偏置参数.
- 连接数:训练参数×输出featuremap大小=(5×5+1)×6×28×28=122304

上图为卷积的大概方式
池化层:
-
池化层的输入大小:28×28
-
池化大小:2×2
-
池化层数:6
-
输出featureMap大小:14×14
-
神经元数量:14×14×6
-
训练参数:2×6
-
连接数:(2×2+1)×6×14×14
池化层的作用是特征映射。如果池化单元为2×2,6个特征图的大小经池化后从28×28变为14×14。因为在本文的池化单元之间没有重叠(有的时候池化单元会重叠),在池化区域内进行聚合统计后得到新的特征值,因此经2×2池化后,每两行两列重新算出一个特征值出来,相当于图像大小减半,因此卷积后的28×28图像经2×2池化后就变为14×14。
池化层的计算过程:2×2 单元里的值相加,然后再乘以训练参数w,再加上一个偏置参数b(每一个特征图共享相同的w和b),然后取sigmoid值(S函数:0-1区间),作为对应的该单元的值。

上图为池化过程
后面的池化与卷积方式类似,不做阐述
全连接层:
全连接层一般接在卷积神经网络的最后,用于提取卷积和池化之后的特征向量;并基于提取的特征向量进行图像分类。所以全连接层即充当了特征提取器,又充当了分类器的角色。
实验过程:
下载数据集:
MNIST数据集来自美国国家标准与技术研究所, 训练集 (training set)、测试集(test set)由分别由来自250个不同人手写的数字构成
MNIST数据集包含:Training set images、Training set images、Test set images、Test set labels
模型的配置:
class LeNet(nn.Module): def __init__(self): super(LeNet, self).__init__() self.conv1 = nn.Conv2d(1, 6, kernel_size=5)#卷积层1 self.pool1 = nn.MaxPool2d(kernel_size=2)#池化层1 self.conv2 = nn.Conv2d(6, 16, kernel_size=5)#卷积层2 self.pool2 = nn.MaxPool2d(kernel_size=2)#池化层2 self.fc1 = nn.Linear(16 * 4 * 4, 120)#全连接层1 self.fc2 = nn.Linear(120, 84)#全连接层2 self.fc3 = nn.Linear(84, 10)#全连接层3 def forward(self, x): x = self.pool1(torch.relu(self.conv1(x))) x = self.pool2(torch.relu(self.conv2(x))) x = x.view(-1, 16 * 4 * 4) x = torch.relu(self.fc1(x)) x = torch.relu(self.fc2(x)) x = self.fc3(x) return x
一些训练的数据配置:
num_epochs = 2 # 模型训练轮数 momentum = 0.5 # 设置SGD中的冲量 # 学习率 lr = 0.01 # 定义LeNet模型
进行模型训练:
model = LeNet() # 切换到训练状态 model.train() # 交叉熵损失函数 criterion = nn.CrossEntropyLoss() # 随机梯度下降优化器 optimizer = torch.optim.SGD(model.parameters(), lr=lr, momentum=0.5) for epoch in range(num_epochs): train_loss, correct, total = 0, 0, 0 for batch_idx, (inputs, targets) in enumerate(data_train_loader): outputs = model(inputs) loss = criterion(outputs, targets) optimizer.zero_grad() loss.backward() optimizer.step() train_loss += loss.item() _, predicted = outputs.max(1) total += targets.size(0)#总数 correct += predicted.eq(targets).sum().item() print(f"epoch: {epoch + 1}/{num_epochs}", batch_idx, len(data_train_loader), f"Loss: {train_loss / (batch_idx + 1):.3f} | Acc: {100. * correct / total:.3f}%({correct}/{total})") save_info = { "model": model.state_dict() }
预测结果:
训练测试集的准确率为96%
一些本地测试:




浙公网安备 33010602011771号