参考
Python神经网络编程(Tariq Rashid著)
Github
MNIST 数据集
MNIST数据集
https://pjreddie.com/projects/mnist-in-csv/
对于一个在上一章节刚刚制作完成的神经网络来说,最需要的就是大量的数据用于对网络进行训练找到合适的权重。上面的网站里搜集了很多手写数字的图像(28乘以28的矩阵一共784个值)。每个值的大小标注了其所对应的格子的色素。其中用换行符/n分割不同数字,每个数字都包含785个数据,其中第一个数据如下图所示是7用作数据标签(监督学习),代表了它后面的784个数据都是组成数字7的像素。
因此,我们可以设想,我们的神经网络一共应该有784个输入节点,每个节点接受一个像素的值。隐藏层的节点数暂时设为100个,而输出层我们则需要10个节点,每一个节点表示可能的答案即数字。如数字1则第二个节点的输出结果应该在0.9-0.1之间,而其余节点的输出值则非常小。
完整代码
import numpy
import scipy.special#包含一系列特殊函数
import matplotlib
class neuralNetwork:
def __init__(self, inputnodes,hiddennodes,ouputnodes,learningrate):#初始化函数
self.inodes=inputnodes#接受用户设置的输入节点,隐层节点和输出层节点数
self.hnodes=hiddennodes
self.onodes=ouputnodes
self.lr=learningrate#接受用户的设置的学习率
self.activation_function=lambda x: scipy.special.expit(x)#选择s函数用作激活函数
#https://github.com/makeyourownneuralnetwork/makyourownneuralnetwork/blob/master/part2_neural_network.ipynb
self.wih = numpy.random.normal(0.0, pow(self.inodes, -0.5), (self.hnodes, self.inodes))
#以服从正太分布的形式生成输入层与隐层之间各条链的初始权重,分布中心是0.0,标准差是pow函数,大小是hXi
self.who = numpy.random.normal(0.0, pow(self.hnodes, -0.5), (self.onodes, self.hnodes))
#以同样的方式生成隐层与输出层之间的权重矩阵
pass
def train(self, inputs_list, targets_list):#通过用户传入的输入输出数据集训练
#通常输入层的神经元不应用激活函数
inputs = numpy.array(inputs_list, ndmin=2).T
targets = numpy.array(targets_list, ndmin=2).T
#将输入转换为2维数组
hidden_inputs = numpy.dot(self.wih, inputs)
#用点乘的方式计算输入层传入的输入信号
hidden_outputs = self.activation_function(hidden_inputs)
#对传入输入层的信号应用激活函数
final_inputs = numpy.dot(self.who, hidden_outputs)
#计算得到输出层得到的输入信号X=W.I
final_outputs = self.activation_function(final_inputs)
#计算输出层误差
output_errors = targets - final_outputs
#反向传播法计算隐层误差,隐层误差=输出层误差点乘权重E=W.E'
hidden_errors = numpy.dot(self.who.T, output_errors)
#利用梯度下降法更新隐层与输出层之间的权重
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))
#i=1, i+=1, i=2即i+=1等价于 i=i+1
# 即调整的权重等于原权重+调整值(后面的式子)。
# 调整值等于学习率乘以(误差矩阵乘以输出矩阵乘以1-输出矩阵)矩阵乘(输入矩阵的转置)
# 在numpy库中,点乘用*表示即对应元素乘,矩阵乘用numpy.dot()
pass
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
input_nodes = 784 # 28乘以28的矩阵,每个矩阵中包含灰度色素,所以输入节点一共有784个
hidden_nodes = 100 # 隐层节点可以影响神经网络的功效,在这里我们先设置为100个,注意在这一个模型下隐层只有一层
output_nodes = 10 #
# 设置学习率为0.3
learning_rate = 0.3
# 将神经网络类实例化为n
n = neuralNetwork(input_nodes,hidden_nodes,output_nodes, learning_rate)
# 生成一个神经网络n
training_data_file=open("E:\\2018SeniorYearInBG\\Python3.7.0\\neutralnetwork\\mnist_train.csv",'r') # 用只读的方式打开csv训练数据集
training_data_list=training_data_file.readlines()
training_data_file.close()
# readline() 和 readlines() 之间的差异是后者一次读取整个文件。
# 与read()是一次性将文件全部读取返回一个字符串变量
# readlines() 自动将文件内容按行读取并返回到一个列表中
# readline() 每次只读取一行,通常比readlines() 慢得多。仅当没有足够内存可以一次读取整个文件时,才应该使用readline()。
#https://blog.csdn.net/hunrizideshiluozhe/article/details/78967811
for record in training_data_list:
all_values=record.split(',')
# csv文件用,分开数据,training_data_List中每个项都是一个数字的全部数据,因此用for循环遍历每一项
# 在每一项中再用,分开该项包含的所有785个数字存入一个列表all_values中
inputs=(numpy.asfarray(all_values[1:])/255.0*0.99)+0.01
# 对allvalues列表中的数据进行处理。原来allvalues中的每一个数据都是在0—255,处理为0-1
targets=numpy.zeros(10)+0.01
# 先生成一个尺寸为10(即输出层节点数)值全为0.01的矩阵
targets[int(all_values[0])]=0.99
# 随后取每一项的第一个数据即标签所对应的的输出矩阵的数字的位置的0.01改为0.99由此输出矩阵建立
n.train(inputs,targets)
# 将格式整理好的输入输出数据矩阵导入训练模块进行训练
test_data_file=open("E:\\2018SeniorYearInBG\\Python3.7.0\\neutralnetwork\\mnist_test.csv",'r')
test_data_list=test_data_file.readlines()
test_data_file.close()
# 用同样的方法导入测试数据,着手测试已经训练好的神经网络
count=0 # 用于计算神经网络的正确率
for record in test_data_list:
all_values=record.split(',')
# 同样的方式,取测试每一项测试数据进入all_values
correct_label=int(all_values[0])
# 从这一项数据中读取标签存入correct_label作为正确值
print("correct label: ",correct_label)
# 将正确值打印出来用于对比
inputs=(numpy.asfarray(all_values[1:])/255.0*0.99)+0.01
# 对除标签以外的数据做标准化处理,符合神经网络的输入格式 asfarray=as float array
outputs=n.query(inputs)
# 将输入数据导入神经网络获得其对应的输出数据矩阵
label=numpy.argmax(outputs)
# argmax返回矩阵中最大值所对应的索引,即神经网络得到的答案
print("network's answer: ",label)
if label==correct_label:
count+=1
print("The correction rate: ",count/len(test_data_list))
# 打印神经网络的正确率
输出结果
输出如上,在最后一行将会打印出神经网络的正确率,可见100个隐藏层节点训练出来的结果正确率为0.9412已经是很高的正确率了。接下来,我们还可以研究隐藏层节点的数量,学习率的设计,激活函数的选择,乃至于神经网络模型的构架方面进一步的学习如何建立一个性能良好的神经网络。