人工智能应用-实验5-BP 神经网络分类手写数据集

🧡🧡实验内容🧡🧡

编写 BP 神经网络分类, 实现对 MNIST 数据集分类的操作。


🧡🧡代码🧡🧡

需要配置torch。由于是小demo。为了提高效率,我采用的是google的colab进行实验编码,省去配环境的烦恼。

import os
import numpy as np
import torch
import matplotlib.pyplot as plt
from time import time
from torchvision import datasets, transforms
from torch import nn, optim

#@title 加载
transform = transforms.Compose([
                transforms.ToTensor(), # 转为张量,同时如果是图片(uint8)类型,会自动进行归一化到(0,1)
                transforms.Normalize( (0.5, ) , (0.5, ) ) # 转为std=0.5、mean=0.5的分布, 灰色图像,通道只有一个  将值域(0,1)再次转为(-1,1)
                ])
train_set = datasets.MNIST('train_set', # 下载到该文件夹下
              download=not os.path.exists('train_set'), # 是否下载,如果下载过,则不重复下载
              train=True, # 是否为训练集
              transform=transform # 要对图片做的transform
              )
test_set = datasets.MNIST('test_set',
              download=not os.path.exists('test_set'),
              train=False,
              transform=transform
              )
test_set
# train_set[0][0]
train_loader = torch.utils.data.DataLoader(train_set, batch_size=64, shuffle=True)
test_loader = torch.utils.data.DataLoader(test_set, batch_size=64, shuffle=True)

dataiter = iter(train_loader)
images, labels = next(iter(dataiter))
print(images.shape)
print(labels.shape)


#@title Bp net
class BP_Net(nn.Module):
    def __init__(self):
        super().__init__()
        """
        定义第一个线性层,
        输入为图片(28x28),
        输出为第一个隐层的输入,大小为128。
        """
        self.linear1 = nn.Linear(28 * 28, 128)
        self.relu1 = nn.ReLU() # 在第一个隐层使用ReLU激活函数
        """
        定义第二个线性层,
        输入是第一个隐层的输出,
        输出为第二个隐层的输入,大小为64。
        """
        self.linear2 = nn.Linear(128, 64)
        self.relu2 = nn.ReLU() # 在第二个隐层使用ReLU激活函数
        """
        定义第三个线性层,
        输入是第二个隐层的输出,
        输出为输出层,大小为10
        """
        self.linear3 = nn.Linear(64, 10)
        self.softmax = nn.LogSoftmax(dim=1) # 最终的输出经过softmax进行归一化

    def forward(self, x):
        """
        定义神经网络的前向传播
        x: 输入的图片数据, shape为(64, 1, 28, 28)
        """
        x = x.view(x.shape[0], -1) # 首先将x的shape转为(64, 784)

        # 进行前向传播
        x = self.linear1(x)
        x = self.relu1(x)
        x = self.linear2(x)
        x = self.relu2(x)
        x = self.linear3(x)
        x = self.softmax(x)

        return x
model = BP_Net()
criterion = nn.NLLLoss()
optimizer = optim.SGD(model.parameters(), lr=0.003, momentum=0.9)

#@title 评估
from sklearn.metrics import confusion_matrix, roc_auc_score, roc_curve
model.eval() # 将模型设置为评估模式

correct_count, all_count = 0, 0
predictions = [] # 预测结果列表
true_labels = [] # 真实标签列表

for images,labels in test_loader: # 从test_loader中一批一批加载图片
    for i in range(len(labels)):
        logps = model(images[i])  # 进行前向传播,获取预测值
        probab = list(logps.detach().numpy()[0]) # 将预测结果转为概率列表。[0]是取第一张照片的10个数字的概率列表(因为一次只预测一张照片)
        pred_label = probab.index(max(probab)) # 取最大的index作为预测结果
        true_label = labels.numpy()[i]
        if(true_label == pred_label): # 判断是否预测正确
            correct_count += 1
        all_count += 1
        predictions.append(pred_label)
        true_labels.append(true_label)

# 准确率
print("Number Of Images Tested =", all_count)
print("Model Accuracy =", (correct_count/all_count))

# 混淆矩阵
def plot_confusion_matrix(cm, classes):
    plt.imshow(cm, interpolation='nearest', cmap=plt.cm.Blues)
    plt.title("Confusion Matrix")
    plt.colorbar()
    tick_marks = np.arange(len(classes))
    plt.xticks(tick_marks, classes)
    plt.yticks(tick_marks, classes)
    thresh = cm.max() / 2
    for i in range(cm.shape[0]):
        for j in range(cm.shape[1]):
            plt.text(j, i, format(cm[i, j], 'd'), ha="center", va="center",
                     color="white" if cm[i, j] > thresh else "black")
    plt.ylabel('True Label')
    plt.xlabel('Predicted Label')
    plt.tight_layout()
    plt.show()

cm = confusion_matrix(true_labels, predictions)
classes = [str(i) for i in range(10)]
plot_confusion_matrix(cm, classes)

#@title 验证
model.train() # 切回训练模式

## 验证本地图片
import cv2
from PIL import Image
for num in range(0,10):
    img = cv2.imread('./myImg/{}.jpg'.format(num), 0)  # 以灰度图的方式读取要预测的图片
    img = cv2.resize(img, (28, 28))
    height, width = img.shape
    dst = np.zeros((height, width), np.uint8)
    for i in range(height):
        for j in range(width):
            dst[i, j] = 255 - img[i, j]
    dst= dst / 255.0 #归一化
    dst = (dst - 0.5) / 0.5  # 标准化到[-1, 1]
    img = dst
    # print(img)
    img = np.array(img).astype(np.float32)
    img = np.expand_dims(img, 0)  # 扩展后,为[1,28,28]
    img = np.expand_dims(img, 0)  # 扩展后,为[1,1,28,28]
    img = torch.from_numpy(img)
    # print(img.shape)
    with torch.no_grad():
        output=model(img)
    # print(output.data)
    print(output.data.max(1)[1])


🧡🧡分析结果🧡🧡

数据预处理

  • 加载数据集:
    加载torch自带的minst数据集
  • 转换数据:
    先转为tensor变量(相当于直接除255归一化到值域为(0,1))
    在这里插入图片描述
    然后根据std=0.5,mean=0.5,再将值域标准化到(-1,1)
    在这里插入图片描述

设置基本参数:
在这里插入图片描述

构建BP神经网络:
如下,输入为一张2828图片,拆解成2828=784个特征,最终经过三个线性层(784,128)、(128、64)、(64,10),输出为10个特征(对应10个类),归一化这10个特征,它们的大小即认为它属于哪张图片的概率值,取出概率最大的特征对应的类别作为最终预测类别。
在这里插入图片描述

模型训练:
在这里插入图片描述
在这里插入图片描述

模型评估:
准确率:达到97.69%
在这里插入图片描述
混淆矩阵
在这里插入图片描述

接下来,分析网络层数对分类准确率的影响。
被对照试验:隐藏层数目改为2,神经元数目分别为128、64
准确率为:97.69%
对照实验1:隐藏层数目改为3,神经元数目分别为256、128、64
在这里插入图片描述
Loss图:
在这里插入图片描述
准确率和混淆矩阵如下:97.55%
在这里插入图片描述
对照实验2:隐藏层数目改为5,神经元数目分别为512、256、128、64、32
在这里插入图片描述
Loss图:
在这里插入图片描述
准确率和混淆矩阵:97.85%
在这里插入图片描述
总结结果如下表:
在这里插入图片描述
分析可知:

  • 运行时间:从实验结果来看,在增加隐藏层数的情况下,运行时间明显增加。
  • 准确率:实验结果显示,在增加隐藏层数的情况下,准确率大体上有所提升,但是总体变化幅度并不大,可能是因为epochs或者随机梯度下降等参数已经设为较优值,使得准确率已经接近最优效果,从而导致增加网络层数的提优空间并不明显。
    综合来看,增加隐藏层数对于提高分类准确率有一定的帮助,但是也会明显增加运行时间。其次,需要注意的是,若增加隐藏层数并非一定能够带来准确率的提升,过多的隐藏层可能会导致过拟合等问题。

🧡🧡实验总结🧡🧡

在完成基础实验上,我自己画了几张数字图,以对模型进行验证
在这里插入图片描述
结果如下,可以看到,对数字1和数字5分类错误(分布预测成了5和8),其余均分类正确,大体上效果良好。考虑原因,可能是因为minst的数据集是“黑底白字”,而我手画的图片则为“黑字白底”,导致了一些误差。
在这里插入图片描述
理论理解:
通过本次实验,大体上掌握了BP神经网络的定义和结构,总的来说,BP神经网络可以理解为一个黑盒子,通过不断根据loss进行反向传播,最终目的就是得到线性参数w和b,从而根据Y=wx+b 对输入的新x进行预测分类。
代码实践:
一开始想用纯numpy进行BP网络的编写,但是在编写后向传播时,可能是线代和高数知识有些遗忘,求导数时琢磨了很久。后面还是选择直接使用pytorch进行编写,也容易调参,方便进行实验。对我而言,代码中比较纠结的是shape的转换和传入,因此最好多查看中间过程的shape,以便更好理解。

  • 33
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: BP神经网络是一种常用的分类算法,可以用来对MNIST数据集进行分类实验MNIST数据集是一个手写数字识别数据集,包含了60000个训练样本和10000个测试样本。通过训练BP神经网络,可以对手写数字进行自动识别,实现数字分类的功能。在实验中,需要对BP神经网络的参数进行调整,如学习率、迭代次数等,以达到最优的分类效果。同时,还需要对数据集进行预处理,如归一化、降维等,以提高分类的准确率。 ### 回答2: mnist数据集是机器学习领域里面的一个经典的数据集,包含了6万张28*28的手写数字图片。bp神经网络是一种常见的分类算法,可以在mnist数据集上进行试验。 首先,我们需要将mnist数据集进行预处理,将每一幅28*28的图片转换成一个784维的向量。接着,我们需要将数据集分割成训练集和测试集,通常使用80%的数据作为训练集,20%的数据作为测试集。 然后,我们需要定义一个具有若干层的bp神经网络,并初始化权值和偏置项。在训练过程中,我们需要通过反向传播算法来不断调整网络的权值和偏置项,使得模型的损失函数不断减小。训练的主要参数包括学习率、迭代次数、批量大小以及正则化参数等。 接着,我们需要在测试集上对训练好的bp神经网络进行验证。通常使用准确率和混淆矩阵等评价指标来评估模型的性能。如果模型预测正确率高,说明模型分类准确性好。 需要注意的是,对于bp神经网络来说,很容易出现过拟合的情况,因此需要通过正则化等方法来规避此类问题。 总体来说,bp神经网络mnist数据集上的表现是非常优秀的,可以实现很高的准确率。但是,需要注意的是,在实际应用中,bp神经网络也存在很多局限性,比如对于噪声数据的处理能力较弱等问题。因此,在实践中需要根据具体场景进行算法的选择和优化。 ### 回答3: MNIST数据集是机器学习中一个被广泛应用手写数字识别数据集,由于该数据集包含大量的手写数字图片以及对应的标签,因此非常适合用来训练分类模型。本文将介绍如何使用BP神经网络来对MNIST数据集进行分类任务。 首先,我们需要对MNIST数据集进行预处理。该数据集包含60000个训练集样本和10000个测试集样本,每个样本是一个28*28的图像。我们需要将每张图片的像素值进行归一化处理,将像素值从[0,255]缩放到[0,1]的范围内。然后,我们需要将标签进行one-hot编码,将每个数字标签转换成一个长度为10的向量,其中对应标签的位置为1,其他位置为0。 接下来,我们使用Python的numpy库来实现BP神经网络。我们将输入层设置为28*28=784个节点,输出层设置为10个节点,中间隐藏层的节点数量可以根据实际需要进行调整。我们需要选择合适的损失函数和优化器,一般来说,交叉熵和随机梯度下降优化器会比较适合此类分类问题。然后,我们需要将数据集分批次进行训练,每次从训练集中随机抽取一批样本进行训练,直到模型收敛。 最后,我们需要对训练好的模型进行测试,使用测试集中的样本进行预测,并计算模型的准确率。如果模型的准确率较低,可以尝试调整中间隐藏层的节点数量、学习率、迭代次数等参数来优化模型性能。 总之,BP神经网络是一种简单而有效的分类算法,在MNIST数据集上的表现也非常优秀。通过对数据集进行预处理、构建合适的模型、选择合适的优化算法和损失函数,可以在此类分类问题上获得比较好的表现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值