针对前几次做的笔记,发现训练集太少的情况下,识别率太低。有可能降到50%的情况。后做了几次改进,不过这几次改进还是在训练集只有100个,测试集10个的情况下,识别率有了一点提高,能稳定在60%,70%。可能如果加大训练集的话,识别率会有很大提升。
具体的改进有以下几点:
(1)增加训练次数:
即把整个训练集运行多次,保持学习率不变。这是值得的,原因是通过提供更多的爬下斜坡的机会,有助于梯度在下降过程中进行权重更新。直觉告诉我们,训练的次数越多,所得到的性能可能就越好。实际上,太多的训练实际上会过犹不及,这是由于神经网络过度拟合训练数据,因此,网络会在先前没有见到过的新数据上表现不佳。过度拟合现象是需要注意的。改进的代码如下:
1 #训练四次 2 i = 4 3 for e in range(i): 4 #训练神经网络 5 for record in training_data_list: 6 #根据逗号,将文本数据进行拆分 7 all_values = record.split(',') 8 #将文本字符串转化为实数,并创建这些数字的数组。 9 inputs = (numpy.asfarray(all_values[1:])/255.0 * 0.99) + 0.01 10 #创建用零填充的数组,数组的长度为output_nodes,加0.01解决了0输入造成的问题 11 targets = numpy.zeros(output_nodes) + 0.01 12 #使用目标标签,将正确元素设置为0.99 13 targets[int(all_values[0])] = 0.99 14 n.train(inputs,targets) 15 pass 16 pass
(2)改变网络结构
尝试改变中间隐藏层节点的数目。
隐藏层是发生学习过程的地方。输入层只引进了输入信号,输出层只送出神经网络的答案,是隐藏层可以进行学习,将输入转化为答案,这是学习发生的场所。事实上,隐藏层节点前后的链接权重具有学习能力。
如果隐藏层节点太少,比如说3个,这就没有足够的空间让网络学习任何知识,并将所有输入转换为正确的输出,就像用5座车去装载10个人,你不可能将那么多人塞进去,科学家称这种限制为学习容量。
但是,如果有10000个隐藏层节点,会发生什么情况呢?虽然我们不会缺少学习容量,但是由于目前有太多的路径进行学习选择,因此可能难以训练网络。
运行结果显示,隐藏层节点为10个的时候,正确率某次运行结果可能低于30%,整体上不会高于60%,当隐藏层节点到50个的时候,所达到的性能其实和具有100个隐藏层节点所达到的性能差不多。所以可能到达某个阈值后,随着隐藏层节点的数量增加,结果会有所改善,但是不显著。由于增加隐藏层节点意味着增加了到前后层的每个节点的新网络链接,这一切都会产生额外的计算,因此训练神经网络所用的时间也增加了!
(3)改变学习率
改变学习率,就是改变梯度下降的速度。
如果过高的提高学习率,可能得到的结果更糟。好像大的学习率导致了梯度下降过程中有一些来回跳动和超调。
如果选择好的学习率,在性能上会有所改善。如果在不改变隐藏层节点数目的情况下,好的学习率可能会达到隐藏层节点数目最优时的性能,来借此以少胜多。
如果选择过低的学习率,性能可能并不变好,过小的学习率也是有害的,这是因为由于限制了梯度下降的速度,使用的步长太小了,因此对性能造成了损害。运行速度也变慢。
(4)同时增加训练次数和减少学习率
有专家的经验指出,在更多的训练次数情况下,减少学习率确实能够得到更好的性能。
改进后的代码:
1 import numpy 2 import scipy.special 3 import matplotlib.pyplot as plt 4 import pylab 5 # 神经网络类定义 6 class NeuralNetwork(): 7 # 初始化神经网络 8 def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate): 9 # 设置输入层节点,隐藏层节点和输出层节点的数量 10 self.inodes = inputnodes 11 self.hnodes = hiddennodes 12 self.onodes = outputnodes 13 # 学习率设置 14 self.lr = learningrate 15 # 权重矩阵设置 正态分布 16 self.wih = numpy.random.normal(0.0, pow(self.hnodes, -0.5), (self.hnodes, self.inodes)) 17 self.who = numpy.random.normal(0.0, pow(self.onodes, -0.5), (self.onodes, self.hnodes)) 18 # 激活函数设置,sigmod()函数 19 self.activation_function = lambda x: scipy.special.expit(x) 20 pass 21 22 # 训练神经网络 23 def train(self,input_list,target_list): 24 # 转换输入输出列表到二维数组 25 inputs = numpy.array(input_list, ndmin=2).T 26 targets = numpy.array(target_list,ndmin= 2).T 27 # 计算到隐藏层的信号 28 hidden_inputs = numpy.dot(self.wih, inputs) 29 # 计算隐藏层输出的信号 30 hidden_outputs = self.activation_function(hidden_inputs) 31 # 计算到输出层的信号 32 final_inputs = numpy.dot(self.who, hidden_outputs) 33 final_outputs = self.activation_function(final_inputs) 34 35 output_errors = targets - final_outputs 36 hidden_errors = numpy.dot(self.who.T,output_errors) 37 38 #隐藏层和输出层权重更新 39 self.who += self.lr * numpy.dot((output_errors*final_outputs*(1.0-final_outputs)), 40 numpy.transpose(hidden_outputs)) 41 #输入层和隐藏层权重更新 42 self.wih += self.lr * numpy.dot((hidden_errors * hidden_outputs * (1.0 - hidden_outputs)), 43 numpy.transpose(inputs)) 44 pass 45 # 查询神经网络 46 def query(self, input_list): 47 # 转换输入列表到二维数组 48 inputs = numpy.array(input_list, ndmin=2).T 49 # 计算到隐藏层的信号 50 hidden_inputs = numpy.dot(self.wih, inputs) 51 # 计算隐藏层输出的信号 52 hidden_outputs = self.activation_function(hidden_inputs) 53 # 计算到输出层的信号 54 final_inputs = numpy.dot(self.who, hidden_outputs) 55 final_outputs = self.activation_function(final_inputs) 56 return final_outputs 57 58 # 设置每层节点个数 59 input_nodes = 784 60 hidden_nodes = 100 61 output_nodes = 10 62 # 设置学习率为0.3 63 learning_rate = 0.3 64 # 创建神经网络 65 n = NeuralNetwork(input_nodes, hidden_nodes, output_nodes, learning_rate) 66 67 #读取训练数据集 转化为列表 68 training_data_file = open("D:/mnist_train_100.csv",'r') 69 training_data_list = training_data_file.readlines(); 70 training_data_file.close() 71 72 #训练四次 73 i = 2 74 for e in range(i): 75 #训练神经网络 76 for record in training_data_list: 77 #根据逗号,将文本数据进行拆分 78 all_values = record.split(',') 79 #将文本字符串转化为实数,并创建这些数字的数组。 80 inputs = (numpy.asfarray(all_values[1:])/255.0 * 0.99) + 0.01 81 #创建用零填充的数组,数组的长度为output_nodes,加0.01解决了0输入造成的问题 82 targets = numpy.zeros(output_nodes) + 0.01 83 #使用目标标签,将正确元素设置为0.99 84 targets[int(all_values[0])] = 0.99 85 n.train(inputs,targets) 86 pass 87 pass 88 89 90 #读取测试文件 91 test_data_file = open("D:/mnist_test_10.csv",'r') 92 test_data_list = test_data_file.readlines() 93 test_data_file.close() 94 95 # all_values = test_data_list[2].split(',') 96 # print(all_values[0]) #输出目标值 97 98 # image_array = numpy.asfarray(all_values[1:]).reshape((28,28)) 99 # print(n.query((numpy.asfarray(all_values[1:])/255.0*0.99)+0.01))#输出标签值 100 # plt.imshow(image_array,cmap='Greys',interpolation='None')#显示原图像 101 # pylab.show() 102 103 #进行统计 如果期望值和输出的值相同,就往score[]数组里面加1,否则加0 进而算准确率 104 score = [] 105 for record in test_data_list: 106 #用逗号分割将数据进行拆分 107 all_values = record.split(',') 108 #正确的答案是第一个值 109 correct_values = int(all_values[0]) 110 print(correct_values,"是正确的期望值") 111 #做输入 112 inputs = (numpy.asfarray(all_values[1:])/255.0 * 0.99) + 0.01 113 #测试网络 作输入 114 outputs= n.query(inputs) 115 #找出输出的最大值的索引 116 label = numpy.argmax(outputs) 117 print(label,"是网络的输出值 ") 118 #如果期望值和网络的输出值正确 则往score 数组里面加1 否则添加0 119 if(label == correct_values): 120 score.append(1) 121 else: 122 score.append(0) 123 pass 124 pass 125 print(score) 126 score_array = numpy.asfarray(score) 127 print("正确率是:",(score_array.sum()/score_array.size)*100,'%')
测试结果: