本章节主要介绍手写数字图像集MNIST,并且通过神经网络对其进行前向传播。
3.6 手写数字识别
通过神经网络能够对手写数字进行识别处理。
3.6.1 MNIST数据集介绍
为了训练一个手写数字识别模型,必须要用到数据集,这里用的是MNIST数据集,这个数据库主要包含了60000张的训练图像和10000张的测试图像。数据集由四个压缩包构成
3.6.2 MNIST数据集的调用
通过编写一个mnist.py文件,其中定义的函数load_mnist(),能够很方便地读入MNIST数据,其数据形式以:“(训练数据,训练标签),(测试图像,测试标签)”的形式返还读入的MNIST数据。运行mnist.py文件,能够自动下载MNIST数据集,并且完成数据的读入。
下面编写读入MNIST数据集的代码,其中要用到一个mnist.py的文件,这个文件和程序运行文件我会分享到我的博客上:。
#代码在文件:mnist.a.py中
import sys,os
#os模块是Python标准库中提供的与操作系统交互的模块,提供了访问操作系统底层的接口,里面有很多操作系统的函数
#其中os.path模块主要用于文件属性的获取
#sys模块负责程序与Python解释器的交互。
sys.path.append(os.pardir) #为了导入父目录的文件而进行的设定,因为该文件和mnist文件不在一个文件夹中
from dataset.mnist import load_mnist #调用dataset文件夹中的文件mnist中的load_mnist函数(下载mnist文件)
(x_train,t_train),(x_test,t_test)=load_mnist(flatten=True,normalize=False,one_hot_label=False)
#load_mnist以(训练图片,训练标签),(测试图片,测试标签)的形式读入数据集
#normalize:是否将输入图片正规化为0.0-1.0的值,这里没有正规化,图片像素仍然为0-255
#flatten:是否展开输入图像(变为一维数组),这里是用一维数组显示的
#one_hot_label:仅正确标签为1,其他均为0的数组,形如[0,0,0,1,0,0],如果为False,则仅保存2,7等正确解的标签
#输出,确定训练集与测试集的数组形状
print('训练集图片形状',x_train.shape) #训练集图片形状
print('训练集标签形状',t_train.shape) #训练集标签形状
print('测试集图片形状',x_test.shape) #测试集图片形状
print('测试集标签形状',t_test.shape) #测试集标签形状
#mnist书写数据集中训练集有6万张图片,测试集中有一万张图片
输出:
训练集图片形状 (60000, 784)
训练集标签形状 (60000,)
测试集图片形状 (10000, 784)
测试集标签形状 (10000,)
3.6.3 对读入的数据集信息进行显示
#代码在文件:mnist_show.py中
import sys,os
sys.path.append(os.pardir) #为了导入父目录的文件而进行的设定
from dataset.mnist import load_mnist
import numpy as np
from PIL import Image #图像的显示使用PIL(Python Image Library)模块
def img_show(img): #定义数组转变函数
pil_img=Image.fromarray(np.uint8(img))
pil_img.show() #转换后的图片显示
#根据下一步操作可知,图片已经转变为一维数组了,这里需要把图片重新变为28像素X28像素的形状;这里通过Image.fromarray()函数进行转变
(x_train,t_train),(x_test,t_test)=load_mnist(flatten=True, normalize=False) #读入load——mnist调取的图片
img=x_train[3] #读取第三张图片的数组
lable=t_train[3] #读取第三张标签的数组
print(lable) #输出第三张标签的数组
print(img.shape) #一开始的图片数组形状
img=img.reshape(28,28) #把数组变为指定的形状
print(img.shape) #变换后的图片数组形状
img_show(img) #调用图片转化函数,进行图片的显示
输出:
文本:
1
(784,)
(28, 28)
图片:
3.6.4神经网络的前向学习
对手写数字图像集,通过神经网络进行前向学习,即给定了训练好的参数(参数信息在文件sample_weight.pkl中),通过输出对每个输入的图像进行预测,判断属于哪一个数字(在下一个章节会对参数的跟新进行说明),并且得出该神经网络的准确性。
神经网络的结构说明:图片大小为28*28=784,即输入为784个神经元,输出层为10个神经元(对应数字0-9),其中有两层隐藏层(度余个隐藏层有50个神经元,第二个神经元由100个神经元)。
#代码在文件:neuarl_network.py中
import sys, os
sys.path.append(os.pardir) # 为了导入父目录的文件而进行的设定
import numpy as np
import pickle #调用pickle库
from dataset.mnist import load_mnist
#1.sigmoid函数
def sigmoid(x):
return 1/(1+np.exp(-x))
#2.softmax激活函数 (感叹一下,数组计算就是快)
def softmax(a):
exp_a=np.exp(a)
sum_exp_a=np.sum(exp_a)
y= exp_a/ sum_exp_a
return y
'''
测试数据的获取:这里函数中的normalize是正规化的意思,正规化能够提高训练结果的准确率
'''
def get_test_data():
(x_train,t_train),(x_test,t_test)=\
load_mnist(flatten=True,normalize=True,one_hot_label=False) #读取数据集的信息 (进行正则化,精度高)
#load_mnist(flatten=True,normalize=False,one_hot_label=False) #读取数据集的信息 (不进行正则化,精度稍低)
return x_test,t_test
#神经元初始参数的设定(后面用反向传播学习到的参数)
def init_network():
with open("sample_weight.pkl",'rb') as f:
network=pickle.load(f) #获取文件sample_weight.pkl中的权重信息
return network
#前向传播,进行预测,该网络有两个隐藏层
def predict(network,x):
W1,W2,W3=network['W1'],network['W2'],network['W3']
b1,b2,b3=network['b1'],network['b2'],network['b3']
a1=np.dot(x,W1)+b1
z1=sigmoid(a1) #第一层输出
a2=np.dot(z1,W2)+b2
z2=sigmoid(a2) #第二层输出
a3=np.dot(z2,W3)+b3
y=softmax(a3) #最终输出
return y
#主函数(进行批处理)
x,t=get_test_data() #从函数get_test_data() 中获取测试数据
network=init_network() #权重的选定
batch_size=100 #批处理量
accuracy_cnt=0
for i in range(0,len(x),batch_size):
x_batch=x[i:i+batch_size]
y_batch=predict(network,x_batch)
p=np.argmax(y_batch,axis=1) #获取概率最高的元素的索引
accuracy_cnt +=np.sum(p==t[i:i+batch_size])
print("Accuracy:"+str(float(accuracy_cnt)/len(x)))
结果:
数据进行预处理:Accuracy:0.9352
更改其中的代码:注销第一句代码,运行第二句代码,其他不变:
结果:
数据进行预处理:Accuracy:0.92087
由上述可知:如果对数据进行预处理,即正则化,是能够提高模型识别的准确度的。
本小节的代码内容我已经打包好了,需要的可以留言。
手写数字识别代码
参考书籍:
1.《深度学习–基于python的理论与实现》