识别手写数字 paddle+LeNet5卷积神经网络实现

本次实验使用paddle+LeNet5卷积神经网络实现,实现识别手写数字功能。
首先,先说明本次神经网络的细节。Lenet-5神经网络基本结构如下图所示:
LeNet5卷积神经网络
这里,我设定:

卷积层1
输入图片大小28×28×1
卷积核大小5×5
卷积核数量20
步长1
激活函数relu
输出大小24×24×20
池化层1
输入24×24×20
池大小2×2
步长2
输出大小12×12×20
卷积层2
输入大小12×12×20
卷积核大小5×5
卷积核数量20
步长1
激活函数relu
输出大小8×8×20
池化层2
输入8×8×20
池大小2×2
步长2
输出大小4×4×20
全连接层
输入4×4×20
大小10
激活函数softmax

到此,就确定好网络结构了。
下面是代码:

import paddle as paddle
import paddle.fluid as fluid
import matplotlib.pyplot as plt
import numpy as np

batch_size = 128 #设置每次获取的条数
buf_size = batch_size*100 #设置缓存条数

#获取数据载入内存的地址
train_reader = paddle.batch(paddle.reader.shuffle(paddle.dataset.mnist.train(), buf_size=buf_size), batch_size=batch_size)#训练数据地址
test_reader = paddle.batch(paddle.reader.shuffle(paddle.dataset.mnist.test(), buf_size=buf_size), batch_size=batch_size)#测试数据地址
#获取数据载入内存的地址

#建立神经网络结构
def convolutional_neural_network(img):#传入图片
    
    #卷积层1+池化层1
    conv_pool_1 = fluid.nets.simple_img_conv_pool(input=img, filter_size=5, num_filters=20, pool_size=2, pool_stride=2, act="relu")
    
    #卷积层2+池化层2
    conv_pool_2 = fluid.nets.simple_img_conv_pool(input=conv_pool_1, filter_size=5, num_filters=20, pool_size=2, pool_stride=2, act="relu")
    
    #全连接层
    prediction = fluid.layers.fc(input=conv_pool_2, size=10, act="softmax")
    
    return prediction#返回结果
#建立神经网络结构

#创建img、label张量

#name的‘img’表示张量img,输入的照片大小shape要为28*28,而且是灰度图,因此为[1, 28, 28]
img = fluid.layers.data(name='img', shape=[1, 28, 28], dtype='float32')

label = fluid.layers.data(name='label', shape=[1], dtype='int64')#name的‘y’表示张量y,shape为1是因为得到的结果应该是0~9之间的一个数字
#创建img、label张量

#得到神经网络结构
predict = convolutional_neural_network(img)
#得到神经网络结构

#定义损失函数,此处用的是交叉熵
cost = fluid.layers.cross_entropy(input=predict, label=label)#建立交叉熵,标签是label
avg_cost = fluid.layers.mean(cost)#定义平均值
#定义损失函数

accuracy = fluid.layers.accuracy(input=predict, label=label)#定义精确度

#建立优化方法,这里用的是随机梯度下降法
optimizer = fluid.optimizer.Adam(learning_rate=0.001)#learning_rate表示学习速率,太低或太高都不能很好训练出好的分类器
optimizer.minimize(avg_cost)#优化准则是让交叉熵的均值(avg_cost)达到最小(minimize)
#建立优化方法

#分配内存、创建执行器、初始化
place = fluid.CPUPlace()#分配内存
exe = fluid.Executor(place)#定义执行器
exe.run(fluid.default_startup_program())#初始化,fluid.default_startup_program()表示默认初始化函数
#分配内存、创建执行器、初始化

#创建数值数据转换成img、label的特殊类型的数据类型转换器
feeder = fluid.DataFeeder(place=place, feed_list=[img, label])#投喂格式为[img, label],意味着第列表或者数组的第一个元素赋值给img,第二个元素赋值给label
#创建数值数据转换成img、label的特殊类型的数据类型转换器

#训练
print("training begin!")

train_costs = []#保存训练中的所有样本的交叉熵,用于作图,方便观察多次训练中交叉熵的变化趋势
train_accuracys = []#保存训练中的所有样本的精确度,用于作图,方便观察多次训练中精确度的变化趋势
times = []#保存训练累积的的数据量,以便后期作为每一次训练的MSE指标的横坐标轴的数据
time = 0#表示已经累积的训练的数据量

for i in range(5):#训练循环:5次
    for index, data in enumerate(train_reader()):#根据train_reader保存的地址拿出数据下标以及数据,每次拿出batch_size条数据
        
        #通过执行器执行fluid.default_main_program(),这是默认的训练函数,feed=feeder.feed(data)表示赋值给[img,label]的数据,fetch_list=[avg_cost, accuracy]表示优化参数是交叉熵的均值以及精确度
        train_cost, train_accuracy = exe.run(program=fluid.default_main_program(), feed=feeder.feed(data), fetch_list=[avg_cost, accuracy])
        
        train_costs.append(train_cost[0])#train_costs每次保存每个样本的交叉熵
        train_accuracys.append(train_accuracy[0])#train_accuracys每次保存每个样本的精确度
        time=time+batch_size
        times.append(time)
        
#     test_costs = []
#     test_accuracys = []
    
    for index, data in enumerate(test_reader()):#根据test_reader保存的地址拿出数据下标以及数据,每次拿出batch_size条数据
        
        #通过执行器执行fluid.default_main_program(),这是默认的训练函数,feed=feeder.feed(data)表示赋值给[img,label]的数据,fetch_list=[avg_cost, accuracy]表示优化参数是交叉熵的均值以及精确度
        test_cost,test_accuracy =exe.run(program=fluid.default_main_program(), feed=feeder.feed(data), fetch_list=[avg_cost, accuracy])
        
#         test_costs.append(test_cost[0])
#         test_accuracys.append(test_accuracy[0])
print("training over!")
#训练

#保存训练好的分类器、数据、执行器
inference_path = "d:/first_CNN"
fluid.io.save_inference_model(inference_path, ['img'], [predict], exe)
#保存训练好的分类器、数据、执行器

#画出交叉熵、精确度随着训练数据量增加而变化的图像
plt.plot(times, train_costs, "r-", label="train_cost")
plt.plot(times, train_accuracys, "g--", label="train_accuracy")
plt.xlabel("numOfData")
plt.ylabel("cost&accuracy")
plt.legend(loc="best")
plt.savefig("d:/result")
plt.show()
#画出交叉熵、精确度随着训练数据量增加而变化的图像

# print("test_avg_cost is:",sum(test_costs)/len(test_costs),"/ntest_avg_acc is:",sum(test_accuracys)/len(test_accuracys))

#创建预测执行器
infer_exe = fluid.Executor(place)
inference_scope = fluid.core.Scope()
#创建预测执行器

infer_results = []#保存根据信息预测出来的数据(预测手写的数字的值)
trues = []#保存实际数据(这里指的是实际手写数字的值)

with fluid.scope_guard(inference_scope):
    
    #根据保存的分类器路径以及预测执行器,创建出用来预测的分类模型,得到分类器、字段名以及模型的所有输出变量
    [inference_program, feed_target_names, fetch_targets] = fluid.io.load_inference_model(inference_path, infer_exe)
    
    #创建infer_reader张量,指向实际房价的内存空间,且导入150条
    infer_reader = paddle.batch(paddle.dataset.mnist.test(), batch_size=150)
    
    #导入数据
    test_data = next(infer_reader())#迭代器,用于把数据导入变量
    test_x = np.array([data[0].reshape(1,28,28) for data in test_data]).astype("float32")
    test_y = np.array([data[1] for data in test_data]).astype("int64")
    #导入数据
    
    #预测
    result = infer_exe.run(inference_program, feed={feed_target_names[0]:np.array(test_x)}, fetch_list=fetch_targets)
    #预测
    
    acc=0#定义保存预测对的数量的变量
    print("inference result:")
    for i, val in enumerate(result[0]):
        index = np.argmax(val)#找出最大概率的下标
        print(i,":",index)
        infer_results.append(index)
        
    print("true :")
    for i, val in enumerate(test_y):
        print(i,":",val)
        trues.append(val)  
        
    for i in range(len(infer_results)):#比对预测值和实际值,得到共预测对的次数acc
        if infer_results[i]==trues[i]:
            acc=acc+1
#     print("MSE is:",mean_squared_error(infer_results,trues))#对比实际值与预测值,算出均方差(MSE)
#     print("infer_acc is:",accuracy_score(infer_results,trues))

    print("acc is%0.3f"%(acc/len(infer_results)))#打印出精确度

由于训练循环为5次,因此每次运行时间大概需要数分钟时间。
但运行结束,即能得到交叉熵、精确率随训练样本量增加而变化的图像以及测试的精确率:

训练时交叉熵&精确率
交叉熵、精确率随训练样本量增加而变化图

测试精确率
测试精确率图

精确率大小
5次运行结果0.993、1.000、0.993、0.993、0.993

由于偶然性,得到的精确率基本在0.99到1之间

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值