大作业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%

一些本地测试:

 

posted @ 2023-10-13 21:29  hbhhbh  阅读(44)  评论(0)    收藏  举报