python手机代码识别数字_利用python构建神经网络识别手写数字(附源代码)

一.运行环境配置

本次实验的运行环境win10(bit64),采用python环境为3.7.6,安装Python环境推荐使用Anaconda。Anaconda是一个免费开源的Python和R语言的发行版本,用于计算科学(数据科学、机器学习、大数据处理和预测分析)。在python编程中下载相关库是很浪费时间的,Anaconda有效地帮我们解决了这个问题。

我用的编译器是pycharm,建议基于虚拟环境进行编程,pycharm提供了很便利的方式搭建虚拟环境:

这里注意要在inhrerit global site-packages打勾,否则不会继承Anaconda中的数据包。你也可以通过virtualenv在cmd中配置,这里不作演示。

二.准备手写数字的数据集

数据集包括训练集和测试集

也可以在后面我的github上进行下载。

数据集中用数百个像素点(0-255)表示单个数字,第一个数字为数字设定值,后面我们将对其进行切片操作。

三.用python构建神经网络

1.我们先对函数进行初始化,设置输入层节点,输出层节点,学习率和隐层节点。然后再设置连接权重。我们要采用随机矩阵,而不是单个数字,因此采用分布中心值、标准方差和numpy数组的大小作为参数。代码如图:

self.wih = numpy.random.normal(0.0,pow(self.hnodes,0.5),(self.hnodes,self.inodes))

self.who = numpy.random.normal(0.0,pow(self.onodes,0.5),(self.onodes,self.hnodes))

第一个参数为正态分布的中心设定,第二个表示节点数目的0.5次方,第三个参数是我们希望的numpy数组大小。

为了方面后面获得隐藏层节点的输出信息,我们要定义一个激活函数,这里我们不用传统的def()函数,采用lambda快速创建。

self.activation_function = lambda x:scipy.special.expit(x)

这里调用scipy.special函数库,该条命令的含义是输入x,输出expit函数。

2.下面来写查询网络部分的代码:

我们先来做由输入层到隐层这部分,神经元输入层和隐层的节点是相当多的,如果我们逐个节点进行计算,其运算过程是不可想象的,而引入矩阵则可以大大方便我们。隐层的信号即为权重矩阵点乘输入矩阵,隐层的输出则由前面的激活函数获得,从隐层到输出层的过程与此类似,这里一并贴出代码:

def query(self, inputs_list):

inputs = numpy.array(inputs_list,ndmin=2).T

hidden_inputs = numpy.dot(self.wih,inputs)

hidden_outputs = self.activation_function(hidden_inputs)

final_inputs = numpy.dot(self.who,hidden_outputs)

final_outputs = self.activation_function(final_inputs)

return final_outputs

3. 我们开始编程最复杂的训练部分,首先是针对给定的训练样本计算输出,这与我们刚刚在query函数中所写的差不多。

inputs = numpy.array(inputs_list, ndmin=2).T

targets = numpy.array(target_list, ndmin=2).T

hidden_inputs = numpy.dot(self.wih, inputs)

hidden_outputs = self.activation_function(hidden_inputs)

final_inputs = numpy.dot(self.who, hidden_outputs)

final_outputs = self.activation_function(final_inputs)

output_errors = targets - final_outputs

hidden_errors = numpy.dot(self.who.T,output_errors)

这里补充一下神经网络更新节点j与下一层节点k之间链接权重的矩阵形式的表达式:

在python中对输入层和隐藏层,隐藏层和输出层进行相关编码:

self.who += self.lr * numpy.dot((output_errors * final_outputs * (1.0-final_outputs)),numpy.transpose(hidden_outputs))

self.wih += self.lr * numpy.dot((hidden_errors * hidden_outputs * (1.0-hidden_outputs)),numpy.transpose(inputs))

四.识别手写数字

1. 初始化神经网络

input_nodes = 784

hidden_nodes = 100

output_nodes = 10

learning_rate = 0.3

n = neuralNetwork(input_nodes,hidden_nodes,output_nodes,learning_rate)

数据集中每个数组用一个28X28的数组表示,故输入节点为784个。

输出为个位数字,故输出节点为10个。

隐层节点数量可自由设置,数量多少会对识别率产生影响,这里我们设为100.

2.导入训练集,这里为提高识别率,我们将训练集循环两次,并对各像素点进行初始化,使其范围编程0.01-0.09,目标输出数组设定值设为1,其他值为0。

data_file = open("mnist_dateset/mnist_train.csv",'r')

data_list = data_file.readlines()

data_file.close()

epochs = 2

for i in range(epochs):

for record in data_list:

all_values = record.split(',')

inputs = (numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01

targets = numpy.zeros(output_nodes) + 0.01

targets[int(all_values[0])] = 0.99

n.train(inputs, targets)

2. 读取测试集,验证我们识别的准确率。

数据初始化部分与导入训练集大致相同,随后进行一些绘图的相关设置,同时计算识别成功的次数和总数字数,相除得出识别率。

test_data_file = open("mnist_dateset/mnist_test.csv",'r')

test_data_list = test_data_file.readlines()

test_data_file.close()

# print(data_list[0])

scorecard = []

for record in test_data_list:

all_values = record.split(',')

correct_value = int(all_values[0])

print(all_values[0])

image_array = numpy.asfarray(all_values [1:]).reshape((28,28))

matplotlib.pyplot.imshow( image_array , cmap='Greys' , interpolation='None')

inputs = (numpy.asfarray(all_values[1:])/255.0 * 0.99) + 0.01

outputs = n.query(inputs)

label = numpy.argmax(outputs)

print(label)

if (label == correct_value):

scorecard.append(1)

else:

scorecard.append(0)

scorecard_array = numpy.asarray(scorecard)

五.一些优化

你可以通过更改学习率,隐层节点数量来提高识别率,也可以加入一些较为复杂的算法。该程序中我们使用了sigmoid函数,虽然很美,但由于梯度消失问题而逐渐被淘汰,图像如下

本来以为激活函数的改变会对识别率有很大影响,但尝试了Relu和tanh激活函数后发现其对最终结果几乎没有影响。可能改变对神经网络架构影响大的因素才会更有效地提高识别率。以上代码的识别率约为80,将隐层节点改为200,循环训练集5次(电脑运行了大约十分钟)后识别率变为97.25,代码已经在github上更新。

最后附上源代码链接(内含数据集):

你可能感兴趣的:(python手机代码识别数字)