padlepadle实现手写数字识别
发布日期:2021-05-07 01:32:31 浏览次数:22 分类:原创文章

本文共 6573 字,大约阅读时间需要 21 分钟。

目标

通过构建ANN,实现对手写数字识别,并对自己手写的数字进行预测

源码地址

数据分析

数据集为60000个训练样本和10000个测试数据,每个样本为图片和标签,图片大小为28*28,标签为0-9的数字

代码实现

导包

import numpy as npimport paddleimport paddle.fluid as fluidfrom PIL import Imageimport matplotlib.pyplot as pltimport os

获取数据并创建数据读取器

# 准备处理数据# 数据分为60000个训练样本和10000个测试数据。# 每一个样本分为图片和标签,图片为28*28,标签为0-9的数字。BATCH_SIZE = 128BUF_SIZE = 512# 训练数据提供器,每次随机读取batch_size大小的数据# shuffle 的第二个参数是在缓冲区中存放数据的个数train_reader = paddle.batch(    paddle.reader.shuffle(paddle.dataset.mnist.train(),                          buf_size=BUF_SIZE),  # 随机获取获取mnist的训练数据    batch_size=BATCH_SIZE)# 测试样本提供器test_reader = paddle.batch(    paddle.dataset.mnist.test(),    batch_size=BATCH_SIZE)

查看一个样本的样子

# 查看一个样本train_data = paddle.dataset.mnist.train()one_data = next(train_data())print('image shape: ', one_data[0].shape)print(one_data)# 打印出图片one_data = np.array(one_data[0], dtype='float32').reshape([28, 28])plt.imshow(one_data, cmap='gray')plt.show()

构建网络

这里使用全连接网络,隐藏层有两层,使用relu激活函数,输出层使用softmax激活函数。
第一层有100个神经元,输入为28 * 28 * 1 = 783,输出为100维的向量。
第二层也是100个神经元,输入为100维,输出为100维
输入层为10个神经元,输入100维,输出10

def Model(input):    # 第一个全连接层    h1 = fluid.layers.fc(input=input, size=100, act='relu')    # 第二个全连接层,输入为第一层的输出    h2 = fluid.layers.fc(input=h1, size=100, act='relu')    # 输出层    pre = fluid.layers.fc(input=h2, size=10, act='softmax')    return pre

创建输入的数据格式和输出的数据格式

# 图片为灰度图片,所以是单通道的paddle.enable_static()  # 这个可以注释试试,不报错就不用加x = fluid.data(name='x', shape=[None, 1, 28, 28], dtype='float32')# 标签,对应图片的类别,共10类,类型为整型y = fluid.data(name='y', shape=[None, 1], dtype='int64')

定义损失函数等

# 获取模型pre = Model(x)# 定义损失函数# 这里是多分类,因此使用交叉熵函数cost = fluid.layers.cross_entropy(input=pre, label=y)avg_cost = fluid.layers.mean(cost)# 计算分类准确率# loss 是计算实际值和真实值之间差距的一种方式# acc 是看这次分类中正确分类在全体样本中的比例acc = fluid.layers.accuracy(input=pre, label=y)

定义优化函数

# 定义优化函数# 优化函数是怎么把最后一层算出来的损失值给传递到前面的网络# 有梯度下降,随机梯度下降,批量梯度下降,带动量的梯度下降,adagrad# adam等等。一般来说使用adam就能让数据好又快的收敛LR = 0.001optimizer = fluid.optimizer.Adam(learning_rate=LR)opts = optimizer.minimize(avg_cost) # 这里就是最小化损失值,参数就是损失值变量

克隆main_program

# 克隆main_program 得到test_program,也就是共享一下训练数据训练出来的网络权重# 或者就是使用一下训练数据刚刚训练出来的网络test_program = fluid.default_main_program().clone(for_test=True)

创建运行的环境和Executor

# 创建运行用的Executor# 这里我们使用gpu,如果使用的是cpu版本就改为Falseuse_cuda = True# 创建运算场所place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace()# 创建Executorexe = fluid.Executor(place)# 在训练前,对网络参数进行初始化exe.run(fluid.default_startup_program())

创建数据提供器

# 创建数据提供器,使用DataFeeder创建一个Executor支持的输入结构# 喂给它的参数为[x, y]形式feeder = fluid.DataFeeder(place=place, feed_list=[x, y])

损失函数曲线

# 绘制训练的曲线iter = 0iters = []costs = []accs = []def draw_cost_acc():    plt.title('train cost and acc', fontsize=24)    plt.xlabel('tier', fontsize=20)    plt.ylabel('cost/acc', fontsize=20)    plt.plot(iters, costs, color='red', label='cost')    plt.plot(iters, accs, color='green', label='acc')    plt.legend()    plt.grid()    plt.show()

开始训练

# 开始训练# 共进行十个epochEPOCH = 10for epoch in range(EPOCH):  # 训练EPOCH轮    for batch, data in enumerate(train_reader()):  # 遍历train        train_cost, train_acc = exe.run(            program=fluid.default_main_program(),  # 执行主程序            feed=feeder.feed(data),     # 将数据喂给模型            fetch_list=[avg_cost, acc]        )                # 保存迭代次数,cost和acc方便一会画图使用        iter = iter + 1        iters.append(iter)        costs.append(train_cost[0])        accs.append(train_acc[0])                # 每200个batch输出一个信息        if batch % 200 == 0:            print('Pass: %d, Batch:%d, Cost:%0.5f, Acc: %0.5f'%            (epoch, batch, train_cost[0], train_acc[0]))        test_costs = []    test_accs = []    # 每一个epoch进行一次验证    for batch, data in enumerate(test_reader()):        test_cost, test_acc = exe.run(            program=test_program,   # 使用刚才克隆的Executor            feed=feeder.feed(data),            fetch_list=[avg_cost, acc]        )        # 保存下来test cost and test acc ,为了一会计算整体的cost和acc        test_costs.append(test_cost[0])        test_accs.append(test_acc[0])    # 计算这次验证的cost和acc    test_cost = (np.sum(test_costs) / len(test_costs))    test_acc = (np.sum(test_acc) / len(test_acc))    # 输出test信息    print('Test:%d, Cost:%0.5f, Acc: %0.5f' %(epoch, test_cost, test_acc))# 绘制训练的曲线draw_cost_acc() 

保存训练模型,供测试使用(paddle.fluid.io.save_inference_model)

paddle.fluid.io.save_inference_model(dirname, feeded_var_names, target_vars, executor, main_program=None, model_filename=None, params_filename=None, export_for_deployment=True, program_only=False)
  • dirname 模型和参数文件目录
  • feeded_var_names 预测时需要提供的变量名称, 也就是我们上面的输入变量名称
  • target_vars 保存预测结果的变量
  • executor 用于保存预测模型的 executor
  • 后面就自己看文档嘛
# 保存模型model_save_dir = r'\home\model\mnistmodel.model'if not os.path.exists(model_save_dir):    os.makedirs(model_save_dir)print('save models to %s' %(model_save_dir))fluid.io.save_inference_model(    model_save_dir,    feeded_var_names=['x'],    target_vars=[pre],       executor=exe)

模型预测

infer_path = '/home/aistudio/data/data57711/手写数字3.png'# 展示图片img = Image.open(infer_path)print(img.size)plt.imshow(img)plt.show()# 读取图片并进行预处理def load_img():    im = Image.open(infer_path).convert('L') # 将图片转为灰度图片    im = im.resize((28, 28), Image.ANTIALIAS)  # resize image with high-quality    # 由于训练的时候是批次读取数据的,所以图片从三维变为四维,这里要和训练对应上    im = np.array(im).reshape(28, 28).astype(np.float32)    # 归一化    im = im / 255.0        # 将自己写的图片转换为黑底白字    for i in range(im.shape[0]):        for j in range(im.shape[1]):            if im[i][j] > 0.5:                im[i][j] = 0            else:                im[i][j] = 1    plt.imshow(im.reshape(28, 28), cmap='gray')    plt.show()    return im.reshape(1, 1, 28, 28)load_img()

运行结果可以去上面的ai stdio网址里面看

创建测试用的executor

# 这里的计算环境还是使用上面定义好的infer_exe = fluid.Executor(place)# 创建一个作用域,通过with语句切换后,新创建的和上面同名的变量就不会冲突了# 就相当于for循环中的变量inference_scope = fluid.core.Scope()

加载模型(fluid.io.load_inference_model)

paddle.fluid.io.load_inference_model(dirname, executor, model_filename=None, params_filename=None, pserver_endpoints=None)
  • 参数
    • dirname : 模型文件路径
    • executor : 测试的executor
    • 自己看文档嘛
  • 返回值
    • program 返回训练的神经网络的结构, 相当于fulid.default_main_program()
    • feed_targer_names 字符串列表,包含所有需要提供数据的变量名称。
    • fetch_targets Variable类型列表,包含着模型的所有输出变量。
# 加载模型并进行预测with fluid.scope_guard(inference_scope):  # 切换作用域    [inference_program, feed_target_name,     fetch_targets] = fluid.io.load_inference_model(model_save_dir, infer_exe)    img = load_img()    results = infer_exe.run(        program=inference_program,        feed={   feed_target_name[0]: img},        fetch_list=fetch_targets    )    results = np.argsort(results)    print('图片预测结果为: ', results[0][0][-1])    print('图片真实结果为:3')
上一篇:中缀表达式转后缀表达式
下一篇:git连接小组远程仓库

发表评论

最新留言

很好
[***.229.124.182]2025年03月26日 06时12分12秒