
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')
发表评论
最新留言
很好
[***.229.124.182]2025年03月26日 06时12分12秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
python中sort和sorted的区别
2021-05-08
maven安装
2021-05-08
合并两个有序数组
2021-05-08
聊聊我的五一小假期
2021-05-08
Vue新建项目——页面初始化
2021-05-08
Node.js包使用系列(一)——修改NPM全局下载和缓存路径
2021-05-08
TDengine使用(一)——TDengine下载与安装
2021-05-08
6.14编一个程序,将两个字符串s1和s2比较,不要用strcmp函数。
2021-05-08
Java纯文本文件显示工具制作
2021-05-08
Unity2D Fixed Joint 2D详解
2021-05-08
三、案例:留言板 & url.parse()
2021-05-08
Python实验26:计算文件MD5值
2021-05-08
LeetCode:28. 实现 strStr()——————简单
2021-05-08
LeetCode:697. 数组的度————简单
2021-05-08
LeetCode:1052. 爱生气的书店老板————中等
2021-05-08
C语言的6大基本数据类型!(学习C语言小白必备!!)
2021-05-08
Nginx配置反向代理与负载均衡
2021-05-08
Lionheart万汇:布林线双底形态分析技巧
2021-05-08
LHCM万汇:在需求上升中,美国贸易赤字创下历史新高
2021-05-08