基于BP神经网络实现mnist手写数字识别

特点:

  • 实现模型保存与加载,训练结果不丢失
  • 实现数据可视化
  • 测试过程可交互,可以选择测试哪一条数据

Step1:准备数据。

(1)数据集介绍

MNIST数据集包含60000个训练集和10000测试数据集。分为图片和标签,图片是28*28的像素矩阵,标签为0~9共10个数字。

# 导包 与参数保存路径设置
import paddle
from paddle.vision.transforms import ToTensor
import os
import paddle.nn as nn
import paddle.nn.functional as F
import matplotlib.pyplot as plt
modelpath,optpath="linear_net.pdparams","adam.pdopt"

# # 加载数据函数
def getdata():
    print("data loading",end="\r")
    # 加载数据集
    train_dataset = paddle.vision.datasets.MNIST(mode='train', transform=ToTensor())
    test_dataset = paddle.vision.datasets.MNIST(mode='test', transform=ToTensor())
    # 用 DataLoader 实现数据加载
    train_loader = paddle.io.DataLoader(train_dataset, batch_size=64, shuffle=True)
    # 加载测试数据集
    test_loader = paddle.io.DataLoader(test_dataset, batch_size=64, drop_last=True)
    print("data loaded ")
    return train_loader, test_loader

#   train_loader, test_loader=getdata()

    # 加载数据集
    train_dataset = paddle.vision.datasets.MNIST(mode='train', transform=ToTensor())
    test_dataset = paddle.vision.datasets.MNIST(mode='test', transform=ToTensor())

#让我们一起看看数据集中的图片是什么样子的
train_data0, train_label_0 = test_dataset[5][0],test_dataset[5][1]
train_data0 = train_data0.reshape([28,28])
plt.figure(figsize=(2,2))
print(plt.imshow(train_data0, cmap=plt.cm.binary))
print('train_data0 的标签为: ' + str(train_label_0))
AxesImage(25,22;155x154)
train_data0 的标签为: [1]

 
#让我们再来看看数据样子是什么样的吧
print(train_data0)
Tensor(shape=[28, 28], dtype=float32, place=CUDAPlace(0), stop_gradient=True,
       [[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
         0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
         0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
         0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
         0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
         0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.30196080, 0.99607849,
         0.41960788, 0.01176471, 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.07450981, 0.89019614, 0.99607849,
         0.99607849, 0.03529412, 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.31764707, 0.99607849, 0.99607849,
         0.64705884, 0.00392157, 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.02745098, 0.79607850, 0.99607849, 0.99607849,
         0.28627452, 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.20784315, 0.99607849, 0.99607849, 0.98039222,
         0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.52549022, 0.99607849, 0.99607849, 0.70588237,
         0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.76862752, 0.99607849, 0.97254908, 0.18823531,
         0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.22745100, 0.99607849, 0.99607849, 0.92941183, 0.,
         0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.43529415, 0.99607849, 0.99607849, 0.51764709, 0.,
         0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.63921571, 0.99607849, 0.93333340, 0.10980393, 0.,
         0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.23529413, 0.98823535, 0.99607849, 0.87450987, 0., 0.,
         0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.30980393, 0.99607849, 0.99607849, 0.60392159, 0., 0.,
         0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.63921571, 0.99607849, 0.93333340, 0.20784315, 0., 0.,
         0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.10980393, 0.98823535, 0.99607849, 0.82352948, 0., 0., 0.,
         0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.33725491, 0.99607849, 0.99607849, 0.51372552, 0., 0., 0.,
         0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.41176474, 0.99607849, 0.91764712, 0.07843138, 0., 0., 0.,
         0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.68627453, 0.99607849, 0.80000007, 0.01960784, 0., 0., 0.,
         0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.01960784, 0.82745105, 0.99607849, 0.76862752, 0., 0., 0., 0.,
         0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.01176471, 0.61960787, 0.99607849, 0.62745100, 0., 0., 0., 0.,
         0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.10196079, 0.61568630, 0.41960788, 0., 0., 0., 0.,
         0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
         0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
         0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
         0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]])

    # 用 DataLoader 实现数据加载
    train_loader = paddle.io.DataLoader(train_dataset, batch_size=64, shuffle=True)
    # 加载测试数据集
    test_loader = paddle.io.DataLoader(test_dataset, batch_size=64, drop_last=True)
    print("data loaded ")
data loaded 

# 显示图像函数
def showimg(img):
    plt.figure("Image") # 图像窗口名称
    plt.imshow(img, cmap=plt.cm.binary)
    plt.axis('on') # 关掉坐标轴为 off
    plt.title('image') # 图像题目
    plt.show()

# # 保存和加载参数函数
# def savemodel(layer,adam):
#     # save 
#     print("saving model",end="\r")
#     paddle.save(layer.state_dict(),modelpath )
#     paddle.save(adam.state_dict(),optpath )
#     print("saved model ")
# def loadmodel(layer,adam):
#     # load
#     if os.path.isfile(modelpath) and os.path.isfile(optpath):
#         print("not first train,loading para",end="\r")
#         layer_state_dict = paddle.load(modelpath)
#         layer.set_state_dict(layer_state_dict)
#         opt_state_dict = paddle.load(optpath)
#         adam.set_state_dict(opt_state_dict)
#         print("not first train,loaded para ")
#     else:
#         print("first train!")

# 保存和加载参数函数
def savemodel(layer):
    # save 
    print("saving model",end="\r")
    paddle.save(layer.state_dict(),modelpath )
    # paddle.save(adam.state_dict(),optpath )
    print("saved model ")
def loadmodel(layer):
    # load
    if os.path.isfile(modelpath):
        print("not first train,loading para",end="\r")
        layer_state_dict = paddle.load(modelpath)
        layer.set_state_dict(layer_state_dict)
        # opt_state_dict = paddle.load(optpath)
        # adam.set_state_dict(opt_state_dict)
        print("not first train,loaded para ")
    else:
        print("first train!")

Step2.网络配置

以下的代码判断就是定义一个简单的多层感知器,一共有三层,两个大小为100的隐层和一个大小为10的输出层,因为MNIST数据集是手写0到9的灰度图像,类别有10个,所以最后的输出大小是10。最后输出层的激活函数是Softmax,所以最后的输出层相当于一个分类器。加上一个输入层的话,多层感知器的结构是:输入层-->>隐层-->>隐层-->>输出层。

# 定义多层感知器 
#动态图定义多层感知器
class DNN(paddle.nn.Layer):
    def __init__(self):
        super(DNN,self).__init__()
        self.fc1 = paddle.nn.Linear(in_features =28*28, out_features =100)#输入层 
        self.fc2 = paddle.nn.Linear(in_features =100, out_features =100)#隐藏层设置100个神经元
        self.fc3 = paddle.nn.Linear(in_features =100, out_features =10)#输出层 10个神经元对应10种数字

    def forward(self, input_):
        x = paddle.reshape(input_, [input_.shape[0], -1])
        x = self.fc1(x)
        x = F.relu(x)
        x = self.fc2(x)
        x = F.relu(x)
        x = self.fc3(x)
        y = F.softmax(x)
        return y

#BP 网络结构函数
class Mnist(paddle.nn.Layer):
    def __init__(self):
        super(Mnist, self).__init__()
        self.flatten = paddle.nn.Flatten()
        self.linear_1 = paddle.nn.Linear(784, 512)#隐藏层512个神经源
        self.linear_2 = paddle.nn.Linear(512, 10)
        self.relu = paddle.nn.ReLU()
        self.dropout = paddle.nn.Dropout(0.2)

    def forward(self, inputs):
        y = self.flatten(inputs)
        y = self.linear_1(y)
        y = self.relu(y)
        y = self.dropout(y)
        y = self.linear_2(y)
        return y

Step3.自己搭建一个BP神经网络

参考上面两个网络的搭建方法,搭建自己的网络,将代码写到下面code框中, 并进行后续训练、评估和测试

class Mnist1(paddle.nn.Layer):
    def __init__(self):
        super(Mnist1, self).__init__()
        self.flatten = paddle.nn.Flatten()
        self.linear_1 = paddle.nn.Linear(784, 512)#隐藏层512个神经源
        self.linear_2 = paddle.nn.Linear(512, 256)#隐藏层256个神经源
        self.linear_3 = paddle.nn.Linear(256, 128)#隐藏层128个神经源
        self.linear_4 = paddle.nn.Linear(128, 10)#分为10类
        self.relu = paddle.nn.ReLU()
        self.dropout = paddle.nn.Dropout(0.2)

    def forward(self, inputs):
        y = self.flatten(inputs)
        y = self.linear_1(y)
        y = self.relu(y)
        y = self.dropout(y)
        y = self.linear_2(y)
        y = self.relu(y)
        y = self.dropout(y)
        y = self.linear_3(y)
        y = self.relu(y)
        y = self.dropout(y)
        y = self.linear_4(y)
        return y

Step4.训练

# 训练函数--输入 网络、训练数据、epoch、优化器、损失函数 训练
def train(mnist,train_loader,epochs,optim,loss_fn):
    print("train begin")

    mnist.train()

    for epoch in range(epochs):
        for batch_id, data in enumerate(train_loader()):

            x_data = data[0]            # 训练数据
            y_data = data[1]            # 训练数据标签
            predicts = mnist(x_data)    # 预测结果

            # 计算损失 等价于 prepare 中loss的设置
            loss = loss_fn(predicts, y_data)

            # 计算准确率 等价于 prepare 中metrics的设置
            acc = paddle.metric.accuracy(predicts, y_data)

            # 下面的反向传播、打印训练信息、更新参数、梯度清零都被封装到 Model.fit() 中

            # 反向传播
            loss.backward()

            if (batch_id+1) % 900 == 0:
                print("epoch: {}, batch_id: {}, loss is: {}, acc is: {}".format(epoch, batch_id+1, loss.numpy(), acc.numpy()))

            # 更新参数
            optim.step()

            # 梯度清零
            optim.clear_grad()
    if epochs>0:savemodel(mnist)

    #BP
    # mnist=Mnist()
    #DNN
    mnist = Mnist1()
    optim = paddle.optimizer.Adam(parameters=mnist.parameters()) # 设置优化器
    loadmodel(mnist)
    loss_fn = paddle.nn.CrossEntropyLoss() # 设置损失函数
not first train,loaded para 

    epochs = int(input("train times:")) # 设置迭代次数
    train(mnist,train_loader,epochs,optim,loss_fn)
train times: 3
train begin
epoch: 0, batch_id: 900, loss is: [0.09206763], acc is: [0.984375]
epoch: 1, batch_id: 900, loss is: [0.05399161], acc is: [0.984375]
epoch: 2, batch_id: 900, loss is: [0.11109874], acc is: [0.984375]
saved model 

Step5.评估

# 评估函数
def eval(mnist,test_loader,loss_fn):
    mnist.eval()
    for batch_id, data in enumerate(test_loader()):

        x_data = data[0]            # 测试数据
        y_data = data[1]            # 测试数据标签
        predicts = mnist(x_data)    # 预测结果

        # 计算损失与精度
        loss = loss_fn(predicts, y_data)
        acc = paddle.metric.accuracy(predicts, y_data)

        # 打印信息
        if (batch_id+1) % 30 == 0:
            print("batch_id: {}, loss is: {}, acc is: {}".format(batch_id+1, loss.numpy(), acc.numpy()))

eval(mnist,test_loader,loss_fn)
batch_id: 30, loss is: [0.09358358], acc is: [0.984375]
batch_id: 60, loss is: [0.27202883], acc is: [0.9375]
batch_id: 90, loss is: [0.03672048], acc is: [0.984375]
batch_id: 120, loss is: [3.5817196e-05], acc is: [1.]
batch_id: 150, loss is: [0.07554816], acc is: [0.984375]

Step6.测试

# 测试函数 输入大于等于10000或小于0的数字会停止测试 退出程序
def test(mnist,test_loader):
    mnist.eval()
    alldata={}
    allpredicts={}
    alllabel={}
    for batch_id, data in enumerate(test_loader()):
        x_data = data[0]
        y_data = data[1]
        predicts = mnist(x_data)
        allpredicts[batch_id]=predicts
        alllabel[batch_id]=y_data
        alldata[batch_id]=x_data
    i=0
    while i<10000 and i>=0:
        batch_id=i//64
        id=i%64
        print("predict:",allpredicts[batch_id][id].argmax().numpy().tolist(),
            "label:",alllabel[batch_id][id].numpy().tolist())
        print("network output:",allpredicts[batch_id][id].numpy().tolist())
        img=(alldata[batch_id][id][0]).numpy()
        showimg(img)
        i=int(input("predict which line:"))
    print("predict finished")

test(mnist,test_loader)
predict: [7] label: [7]
network output: [-9.719499588012695, -3.4801108837127686, -0.651482880115509, 0.385851114988327, -2.0601513385772705, -7.415570259094238, -16.08660888671875, 16.32851791381836, -4.776862621307373, -3.5384793281555176]

<Figure size 640x480 with 1 Axes>
predict which line: 1
predict: [2] label: [2]
network output: [-6.095338821411133, 1.228253960609436, 19.041542053222656, 0.19300922751426697, -6.705218315124512, -6.877689838409424, -7.77207612991333, -2.713935613632202, 1.3736858367919922, -16.818513870239258]

<Figure size 640x480 with 1 Axes>
predict which line: 2
predict: [1] label: [1]
network output: [-6.339268207550049, 17.581079483032227, -1.0753511190414429, -9.902815818786621, -4.157736301422119, -9.313263893127441, -3.4409077167510986, 2.3445217609405518, -3.7683358192443848, -10.679972648620605]

<Figure size 640x480 with 1 Axes>
predict which line: 3
predict: [0] label: [0]
network output: [13.701967239379883, -6.619961261749268, 0.19982996582984924, -2.923210382461548, -5.800919532775879, -2.6428065299987793, 0.7682965397834778, -8.163551330566406, -6.404813289642334, -1.3585065603256226]

<Figure size 640x480 with 1 Axes>


def main():
    train_loader, test_loader=getdata()
    mnist=Mnist()
    optim = paddle.optimizer.Adam(parameters=mnist.parameters()) # 设置优化器
    loadmodel(mnist)
    loss_fn = paddle.nn.CrossEntropyLoss() # 设置损失函数
    epochs = int(input("train times:")) # 设置迭代次数
    train(mnist,train_loader,epochs,optim,loss_fn)
    eval(mnist,test_loader,loss_fn)
    test(mnist,test_loader)
main()
data loading
data loaded 
not first train,loaded para 
train times: 2
train begin
epoch: 0, batch_id: 900, loss is: [0.06289747], acc is: [0.984375]
epoch: 1, batch_id: 900, loss is: [0.01734219], acc is: [1.]
saved model 
batch_id: 30, loss is: [0.1096139], acc is: [0.96875]
batch_id: 60, loss is: [0.14677176], acc is: [0.953125]
batch_id: 90, loss is: [0.05241321], acc is: [0.96875]
batch_id: 120, loss is: [0.00182047], acc is: [1.]
batch_id: 150, loss is: [0.07601856], acc is: [0.984375]
predict: [7] label: [7]
network output: [-7.678086280822754, -5.868976593017578, -4.243804454803467, -1.5573679208755493, -12.051778793334961, -5.38519811630249, -11.370020866394043, 8.172942161560059, -7.072317123413086, -3.1511974334716797]

<Figure size 640x480 with 1 Axes>
predict which line: 5
predict: [1] label: [1]
network output: [-7.677154541015625, 5.846972465515137, -5.342567443847656, -5.321855545043945, -4.9580302238464355, -9.511335372924805, -6.31016206741333, -1.8860419988632202, -4.507370948791504, -9.752077102661133]

<Figure size 640x480 with 1 Axes>
predict which line: 1
predict: [2] label: [2]
network output: [-8.478514671325684, -2.1858773231506348, 8.671475410461426, -1.963241457939148, -14.843521118164062, -9.429603576660156, -7.946425914764404, -9.69050121307373, -3.7265031337738037, -15.485095024108887]

<Figure size 640x480 with 1 Axes>
predict which line: q
  • 18
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值