基于Python的BP网络实现手写数字识别

发布于:2022-12-30 ⋅ 阅读:(827) ⋅ 点赞:(0)

资源下载地址:https://download.csdn.net/download/sheziqiong/86790047
资源下载地址:https://download.csdn.net/download/sheziqiong/86790047
目录
基于Python的BP网络实现手写数字识别 1
一、实验目的 1
二、实验过程与结果 1

  1. 获取MNIST数据 1
  2. 构建BP神经网络 2
  3. 训练构建的BP神经网络 3
  4. 测试BP网络 4
    三、结果分析与实验结论 6
    四、收获、体会及建议 6
    由测试结果可以发现,模型基本上可以准确识别大部分的手写数字,只有个别的数字由于特征不是非常明显甚至兼有其他数字的特征,因此被错误识别。总的来说,模型的训练效果还是不错的。
    三、结果分析与实验结论
    通过实验可以发现,使用BP网络进行训练识别手写数字在一开始基本是随机识别,但是在对整个数据集进行多次训练之后,在训练集和测试集上的准确率都能达到较高的水准并且可以看到,在前几次迭代训练的结果中,损失函数下降的非常快,准确率也快速上升。
    此外,两种模型测试集上的损失函数总体上一直在下降,没有出现上升而准确率总体上一直在上升没有出现下降。因此模型并没有出现过拟合的现象,还可以继续迭代进行训练。
    对比两种模型可以看到,基于CNN的BP网络的准确率均高于全连接层的BP神经网络,有较好的训练效果。但是CNN训练的时间相较于全连接层较长,在数据较多时可能略显吃力。
    四、收获、体会及建议
    通过手写数字识别的实验,我对BP神经网络的原理和结果有了更加深刻的了解和认识;学习了如何使用深度学习框架加载数据集并进行处理和训练;对搭建神经网络的方法和神经网络相关的保存、评估等方法也有所认识。此外,还对比了两种不同的BP神经网络,本文转载自http://www.biyezuopin.vip/onews.asp?id=15396,总的收获还是非常大的。
from read_and_plot_func import *
import torch
import torch.nn as nn
import torchvision
import torch.utils.data.dataloader as dataloader
import numpy as np

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(device)


def data_tf(image):
    """
    数据归一化并将维度展开:[28,28]->[1,784]
    :param image:
    :return:
    """
    img = np.array(image, dtype='float32') / 255
    # img = (img - 0.5) / 0.5
    img = img.reshape((-1,))
    img = torch.from_numpy(img)
    return img


def data_reader(path, train_size, test_size):
    """
    加载MNIST数据集,分训练集和测试集返回标签、数据
    :param path:
    :return:
    """
    train_set = torchvision.datasets.MNIST(
        root=path, train=True,
        transform=data_tf, download=True
    )
    train_loader = dataloader.DataLoader(
        dataset=train_set, shuffle=True, batch_size=train_size
    )
    """
    dataloader返回(images,labels)
    其中,
    images维度:[batch_size,1,28,28]->[batch_size, 28*28]
    labels:[batch_size],即和图片对应
    shuffle: 打乱数据
    """
    # print(train_set)
    test_set = torchvision.datasets.MNIST(
        root=path, train=False,
        transform=data_tf, download=True
    )
    test_loader = dataloader.DataLoader(
        dataset=test_set, shuffle=False, batch_size=test_size
    )
    # print(test_set)

    # firstImg, firstImg_label = train_set[0]
    # print(firstImg.shape)
    # print(firstImg_label)

    # batch_images, batch_label = next(iter(train_loader))
    # print(batch_images.shape)
    # print(batch_label.shape)
    return train_loader, test_loader


class BPNNMdel(torch.nn.Module):
    def __init__(self):
        super(BPNNMdel, self).__init__()
        self.layer1 = nn.Sequential(nn.Linear(784, 400), nn.ReLU())
        self.layer2 = nn.Sequential(nn.Linear(400, 200), nn.ReLU())
        self.layer3 = nn.Sequential(nn.Linear(200, 100), nn.ReLU())
        self.layer4 = nn.Sequential(nn.Linear(100, 10))  # 输出维度必须大于标签的维度,即最好大于分类数,否则报错

    def forward(self, img):
        img = self.layer1(img)
        img = self.layer2(img)
        img = self.layer3(img)
        img = self.layer4(img)
        return img


def train_model(train_data, test_data, iterations, model, model_criterion, model_optimizer):
    """
    模型训练和评估函数,完成模型训练的整个过程
    :param train_data: 训练用数据集
    :param test_data: 测试用数据集
    :param iterations: 训练迭代的次数
    :param model: 神经网络模型
    :param model_criterion: 损失函数
    :param model_optimizer: 反向传播优化函数
    :return:
    """
    model_train_losses = []
    model_train_acces = []
    model_eval_losses = []
    model_eval_acces = []
    for epoch in range(iterations):
        # 网络训练
        train_loss = 0
        train_acc = 0
        model.train()
        for i, data in enumerate(train_data):
            img, label = data
            img = img.to(device)
            label = label.to(device)
            out = model(img)
            loss = model_criterion(out, label)

            model_optimizer.zero_grad()
            loss.backward()
            model_optimizer.step()

            train_loss += loss.item()

            _, pred = out.max(1)
            num_correct = (pred == label).sum().item()
            acc = num_correct / img.shape[0]
            train_acc += acc
        model_train_losses.append(train_loss / len(train_data))
        model_train_acces.append(train_acc / len(train_data))

        # 网络评估
        eval_loss = 0
        eval_acc = 0
        model.eval()
        with torch.no_grad():
            for i, data in enumerate(test_data):
                img, label = data
                img = img.to(device)
                label = label.to(device)
                out = model(img)
                loss = model_criterion(out, label)

                eval_loss += loss.item()

                _, pred = out.max(1)
                num_correct = (pred == label).sum().item()
                acc = num_correct / img.shape[0]
                eval_acc += acc
            model_eval_losses.append(eval_loss / len(test_data))
            model_eval_acces.append(eval_acc / len(test_data))
        print('epoch: {}, Train Loss: {:.6f}, Train Acc: {:.6f}, Eval Loss: {:.6f}, Eval Acc: {:.6f}'
              .format(epoch+1, train_loss / len(train_data), train_acc / len(train_data),
                      eval_loss / len(test_data), eval_acc / len(test_data)))
    return model_train_losses, model_train_acces, model_eval_losses, model_eval_acces


if __name__ == "__main__":
    # 获取数据
    train_load, test_load = data_reader('./data', train_size=64, test_size=64)  # 使用torchvision库函数读取数据
    train, test = load_data('./data/self')  # 从本地读取数据,暂时没有使用
    # for i, data in enumerate(train_load):
    #     images, labels = data
    #     print(images)
    #     print(labels)
    #     print(i)
    # x_train, y_train = train
    # print(y_train[5])
    # 构建网络、损失函数
    epochs = 25  # 迭代次数
    learning_rate = 0.01  # 学习率
    Model = BPNNMdel()
    Model = Model.to(device)
    print(Model)
    criterion = nn.CrossEntropyLoss()
    optimizer = torch.optim.SGD(Model.parameters(), lr=learning_rate)
    # 训练
    train_ID = 're'
    train_losses, train_acces, eval_losses, eval_acces = train_model(
        train_data=train_load, test_data=test_load, iterations=epochs,
        model=Model, model_criterion=criterion, model_optimizer=optimizer
    )
    state = {
        'model': Model.state_dict(),
        'optimizer': optimizer.state_dict()
    }
    torch.save(state, './save_model/BP_%s.pth' % train_ID)
    # 绘图
    plot_all(train_losses, train_acces, eval_losses, eval_acces, 'BP')

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
资源下载地址:https://download.csdn.net/download/sheziqiong/86790047
资源下载地址:https://download.csdn.net/download/sheziqiong/86790047


网站公告

今日签到

点亮在社区的每一天
去签到