padlepadle实现手写数字识别

目标

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

源码地址

添加链接描述

数据分析

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

代码实现

导包

import numpy as np
import paddle
import paddle.fluid as fluid
from PIL import Image
import matplotlib.pyplot as plt
import os

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

# 准备处理数据
# 数据分为60000个训练样本和10000个测试数据。
# 每一个样本分为图片和标签,图片为28*28,标签为0-9的数字。
BATCH_SIZE = 128
BUF_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.001
optimizer = 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版本就改为False
use_cuda = True
# 创建运算场所
place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace()
# 创建Executor
exe = fluid.Executor(place)
# 在训练前,对网络参数进行初始化
exe.run(fluid.default_startup_program())

创建数据提供器

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

损失函数曲线

# 绘制训练的曲线
iter = 0
iters = []
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()

开始训练

# 开始训练
# 共进行十个epoch
EPOCH = 10

for 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')
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值