【Python实战】——神经网络识别手写数字(二)+https://developer.aliyun.com/article/1506501
3 模型优化
3.1 调整神经元数量
3.1.1 每次epoch训练预测情况
运行程序:
##更换隐藏神经元数量为50 epochs = 50 train_acc=[] test_acc=[] NN = NeuralNetwork(num_of_in_nodes = image_pixels, num_of_out_nodes = 10, num_of_hidden_nodes = 50, learning_rate = 0.1) for epoch in range(epochs): print("epoch: ", epoch) for i in range(len(train_imgs)): NN.train(train_imgs[i], train_labels_one_hot[i]) corrects, wrongs = NN.evaluate(train_imgs, train_labels) print("accuracy train: ", corrects / ( corrects + wrongs)) train_acc.append(corrects / ( corrects + wrongs)) corrects, wrongs = NN.evaluate(test_imgs, test_labels) print("accuracy: test", corrects / ( corrects + wrongs)) test_acc.append(corrects / ( corrects + wrongs))
运行结果:
epoch: 0 accuracy train: 0.93605 accuracy: test 0.935 epoch: 1 accuracy train: 0.95185 accuracy: test 0.9501 epoch: 2 accuracy train: 0.9570333333333333 accuracy: test 0.9526 epoch: 3 accuracy train: 0.9630833333333333 accuracy: test 0.9556 epoch: 4 accuracy train: 0.9640166666666666 accuracy: test 0.9556 epoch: 5 accuracy train: 0.9668333333333333 accuracy: test 0.957 epoch: 6 accuracy train: 0.96765 accuracy: test 0.957 epoch: 7 accuracy train: 0.9673166666666667 accuracy: test 0.9566 epoch: 8 accuracy train: 0.96875 accuracy: test 0.9559 epoch: 9 accuracy train: 0.97145 accuracy: test 0.957 epoch: 10 accuracy train: 0.974 accuracy: test 0.9579 epoch: 11 accuracy train: 0.9730666666666666 accuracy: test 0.9569 epoch: 12 accuracy train: 0.9730166666666666 accuracy: test 0.9581 epoch: 13 accuracy train: 0.9747666666666667 accuracy: test 0.959 epoch: 14 accuracy train: 0.9742166666666666 accuracy: test 0.9581 epoch: 15 accuracy train: 0.97615 accuracy: test 0.9596 epoch: 16 accuracy train: 0.9759 accuracy: test 0.9586 epoch: 17 accuracy train: 0.9773166666666666 accuracy: test 0.9596 epoch: 18 accuracy train: 0.9778833333333333 accuracy: test 0.9606 epoch: 19 accuracy train: 0.9789166666666667 accuracy: test 0.9589 epoch: 20 accuracy train: 0.9777333333333333 accuracy: test 0.9582 epoch: 21 accuracy train: 0.9774 accuracy: test 0.9573 epoch: 22 accuracy train: 0.9796166666666667 accuracy: test 0.9595 epoch: 23 accuracy train: 0.9792666666666666 accuracy: test 0.959 epoch: 24 accuracy train: 0.9804333333333334 accuracy: test 0.9591 epoch: 25 accuracy train: 0.9806 accuracy: test 0.9589 epoch: 26 accuracy train: 0.98105 accuracy: test 0.9596 epoch: 27 accuracy train: 0.9806833333333334 accuracy: test 0.9587 epoch: 28 accuracy train: 0.9809833333333333 accuracy: test 0.9595 epoch: 29 accuracy train: 0.9813333333333333 accuracy: test 0.9595
3.1.2 正确率绘图
运行程序:
#正确率绘图 # matplotlib其实是不支持显示中文的 显示中文需要一行代码设置字体 import numpy as np import matplotlib as mpl import matplotlib.pyplot as plt mpl.rcParams['font.family'] = 'SimHei' plt.rcParams['axes.unicode_minus'] = False # 步骤二(解决坐标轴负数的负号显示问题) import matplotlib.pyplot as plt x=np.arange(1,31,1) plt.title('神经元数量为50时正确率') plt.plot(x, train_acc, color='green', label='训练集') plt.plot(x, test_acc, color='red', label='测试集') plt.legend() # 显示图例 plt.show()
运行结果:
3.2 更换隐藏层层数
3.2.1 每次epoch训练预测情况
运行程序:
#隐藏层层数为2 class NeuralNetwork: def __init__(self, num_of_in_nodes, #输入节点数 num_of_out_nodes, #输出节点数 num_of_hidden_nodes1,#隐藏第一层节点数 num_of_hidden_nodes2,#隐藏第二层节点数 learning_rate):#学习率 self.num_of_in_nodes = num_of_in_nodes self.num_of_out_nodes = num_of_out_nodes self.num_of_hidden_nodes1 = num_of_hidden_nodes1 self.num_of_hidden_nodes2 = num_of_hidden_nodes2 self.learning_rate = learning_rate self.create_weight_matrices() #初始为一个隐藏节点 def create_weight_matrices(self):#创建权重矩阵 #A method to initialize the weight #matrices of the neural network#一种初始化神经网络权重矩阵的方法 rad = 1 / np.sqrt(self.num_of_in_nodes) X = truncated_normal(mean=0, sd=1, low=-rad, upp=rad) #形成指定分布 self.weight_1 = X.rvs((self.num_of_hidden_nodes1, self.num_of_in_nodes)) #rvs:产生服从指定分布的随机数 rad = 1 / np.sqrt(self.num_of_hidden_nodes1) X = truncated_normal(mean=0, sd=1, low=-rad, upp=rad) self.weight_2 = X.rvs((self.num_of_hidden_nodes2, self.num_of_hidden_nodes1)) #rvs: 产生服从指定分布的随机数 rad = 1 / np.sqrt(self.num_of_hidden_nodes2) X = truncated_normal(mean=0, sd=1, low=-rad, upp=rad) self.weight_3 = X.rvs((self.num_of_out_nodes, self.num_of_hidden_nodes2)) #rvs: 产生服从指定分布的随机数 def train(self, input_vector, target_vector): #input_vector and target_vector can #be tuple, list or ndarray input_vector = np.array(input_vector, ndmin=2).T#输入 target_vector = np.array(target_vector, ndmin=2).T#输出 output_vector1 = np.dot(self.weight_1, input_vector) #隐藏层值 output_hidden1 = activation_function(output_vector1)#删除不激活 output_vector2 = np.dot(self.weight_2, output_hidden1)#输出 output_hidden2 = activation_function(output_vector2)#删除不激活 output_vector3 = np.dot(self.weight_3, output_hidden2)#输出 output_network = activation_function(output_vector3)##删除不激活 # calculate output errors:计算输出误差 output_errors = target_vector - output_network # update the weights:更新权重 tmp = output_errors * output_network * (1.0 - output_network) self.weight_3 += self.learning_rate * np.dot(tmp, output_hidden2.T) hidden1_errors = np.dot(self.weight_3.T, output_errors) tmp = hidden1_errors * output_hidden2 * (1.0 - output_hidden2) self.weight_2 += self.learning_rate * np.dot(tmp, output_hidden1.T) # calculate hidden errors:计算隐藏层误差 hidden_errors = np.dot(self.weight_2.T, hidden1_errors) # update the weights: tmp = hidden_errors * output_hidden1 * (1.0 - output_hidden1) self.weight_1 += self.learning_rate * np.dot(tmp, input_vector.T) #测试集 def run(self, input_vector): # input_vector can be tuple, list or ndarray input_vector = np.array(input_vector, ndmin=2).T output_vector = np.dot(self.weight_1, input_vector) output_vector = activation_function(output_vector) output_vector = np.dot(self.weight_2, output_vector) output_vector = activation_function(output_vector) output_vector = np.dot(self.weight_3, output_vector) output_vector = activation_function(output_vector) return output_vector #判别矩阵 def confusion_matrix(self, data_array, labels): cm = np.zeros((10, 10), int) for i in range(len(data_array)): res = self.run(data_array[i]) res_max = res.argmax() target = labels[i][0] cm[res_max, int(target)] += 1 return cm #精确度 def precision(self, label, confusion_matrix): col = confusion_matrix[:, label] return confusion_matrix[label, label] / col.sum() #评估 def evaluate(self, data, labels): corrects, wrongs = 0, 0 for i in range(len(data)): res = self.run(data[i]) res_max = res.argmax() if res_max == labels[i]: corrects += 1 else: wrongs += 1 return corrects, wrongs ##迭代30次 epochs = 30 train_acc=[] test_acc=[] NN = NeuralNetwork(num_of_in_nodes = image_pixels, num_of_out_nodes = 10, num_of_hidden_nodes1 = 100, num_of_hidden_nodes2 = 100, learning_rate = 0.1) for epoch in range(epochs): print("epoch: ", epoch) for i in range(len(train_imgs)): NN.train(train_imgs[i], train_labels_one_hot[i]) corrects, wrongs = NN.evaluate(train_imgs, train_labels) print("accuracy train: ", corrects / ( corrects + wrongs)) train_acc.append(corrects / ( corrects + wrongs)) corrects, wrongs = NN.evaluate(test_imgs, test_labels) print("accuracy: test", corrects / ( corrects + wrongs)) test_acc.append(corrects / ( corrects + wrongs))
运行结果:
epoch: 0 accuracy train: 0.8972333333333333 accuracy: test 0.9005 epoch: 1 accuracy train: 0.8891833333333333 accuracy: test 0.8936 epoch: 2 accuracy train: 0.9146833333333333 accuracy: test 0.9182 epoch: 3 D:\ananconda\lib\site-packages\ipykernel_launcher.py:5: RuntimeWarning: overflow encountered in power """ accuracy train: 0.8974833333333333 accuracy: test 0.894 epoch: 4 accuracy train: 0.8924166666666666 accuracy: test 0.8974 epoch: 5 accuracy train: 0.91295 accuracy: test 0.914 epoch: 6 accuracy train: 0.9191166666666667 accuracy: test 0.9205 epoch: 7 accuracy train: 0.9117666666666666 accuracy: test 0.9162 epoch: 8 accuracy train: 0.9220333333333334 accuracy: test 0.9222 epoch: 9 accuracy train: 0.9113833333333333 accuracy: test 0.9112 epoch: 10 accuracy train: 0.9134333333333333 accuracy: test 0.911 epoch: 11 accuracy train: 0.9112166666666667 accuracy: test 0.9103 epoch: 12 accuracy train: 0.914 accuracy: test 0.9126 epoch: 13 accuracy train: 0.9206833333333333 accuracy: test 0.9214 epoch: 14 accuracy train: 0.90945 accuracy: test 0.9073 epoch: 15 accuracy train: 0.9225166666666667 accuracy: test 0.9287 epoch: 16 accuracy train: 0.9226 accuracy: test 0.9205 epoch: 17 accuracy train: 0.9239833333333334 accuracy: test 0.9202 epoch: 18 accuracy train: 0.91925 accuracy: test 0.9191 epoch: 19 accuracy train: 0.9223166666666667 accuracy: test 0.92 epoch: 20 accuracy train: 0.9113 accuracy: test 0.9084 epoch: 21 accuracy train: 0.9241666666666667 accuracy: test 0.925 epoch: 22 accuracy train: 0.9236333333333333 accuracy: test 0.9239 epoch: 23 accuracy train: 0.9301166666666667 accuracy: test 0.9259 epoch: 24 accuracy train: 0.9195166666666666 accuracy: test 0.9186 epoch: 25 accuracy train: 0.9200833333333334 accuracy: test 0.9144 epoch: 26 accuracy train: 0.9204833333333333 accuracy: test 0.9186 epoch: 27 accuracy train: 0.9288666666666666 accuracy: test 0.9259 epoch: 28 accuracy train: 0.9293 accuracy: test 0.9282 epoch: 29 accuracy train: 0.9254666666666667 accuracy: test 0.9242
3.2.2 正确率绘图
运行程序:
#正确率绘图 # matplotlib其实是不支持显示中文的 显示中文需要一行代码设置字体 import numpy as np import matplotlib as mpl import matplotlib.pyplot as plt mpl.rcParams['font.family'] = 'SimHei' plt.rcParams['axes.unicode_minus'] = False # 步骤二(解决坐标轴负数的负号显示问题) import matplotlib.pyplot as plt x=np.arange(1,31,1) plt.title('隐藏层数为2时正确率') plt.plot(x, train_acc, color='green', label='训练集') plt.plot(x, test_acc, color='red', label='测试集') plt.legend() # 显示图例 plt.show()
运行结果: