import numpy as np
import scipy.special
import matplotlib.pyplot as plt
class neuralNetwork:
def __init__(self, inputNodes, hiddenNodes1,heddenNodes2, outputNodes, learningRate):
# 一、设置每层节点个数和学习率
self.inodes = inputNodes
self.hnodes1 = hiddenNodes1
self.hnodes2 = heddenNodes2
self.onodes = outputNodes
self.lr = learningRate
# 二、初始化存储权重的矩阵
# 1.随机初始化权重矩阵,np.random.rand(x,y)随机生成元素在-1到1的x*y的矩阵
# self.ihWeightMatrix = np.random.rand(self.hnodes,self.inodes)-0.5 #减去0.5使范围缩小到-0.5到0.5
# self.hoWeightMatrix = np.random.rand(self.onodes,self.hnodes)-0.5
# numpy.random.normal(中心点的值,节点数目的-0.5次方 即与下一层节点相关的标准方差,数组形状)
# 2.也可以以正态分布方式初始化矩阵
self.ihWeightMatrix = np.random.normal\
(0.0, pow(self.hnodes1, -0.5), (self.hnodes1, self.inodes))
#要改成两行需要加\才可以
self.iiWeightMatrix = np.random.normal\
(0.0, pow(self.hnodes2, -0.5), (self.hnodes2, self.hnodes1))
self.hoWeightMatrix = np.random.normal\
(0.0, pow(self.onodes, -0.5), (self.onodes, self.hnodes2))
# 三、设置激活函数sigmoid
# lambda是匿名的 输入是传入到参数列表x的值,输出是根据表达式计算得到的值
# scipy.special.expit(x)就是sigmoid函数,它等于1/(1+exp(-x))
self.activateFunc = lambda x: scipy.special.expit(x)
pass
def train(self, inputsList, targetsList):
# 一、先根据实际输入生成输出
inputs = np.array(inputsList, ndmin=2).T
hiddenInputs1 = np.dot(self.ihWeightMatrix, inputs)
hiddenOutputs1 = self.activateFunc(hiddenInputs1)
hiddenInputs2 = np.dot(self.iiWeightMatrix, hiddenOutputs1)
hiddenOutputs2 = self.activateFunc(hiddenInputs2)
finalInputs = np.dot(self.hoWeightMatrix, hiddenOutputs2)
finalOutputs = self.activateFunc(finalInputs)
# 二、再将实际输出与理想值比较
targets = np.array(targetsList, ndmin=2).T
outputErrors = targets - finalOutputs
# 反向传播误差值:上一层的errors=WeightsMatrix的转置×这层的errors
hiddenErrors2 = np.dot(self.hoWeightMatrix.T, outputErrors)
hiddenErrors1 = np.dot(self.iiWeightMatrix.T, hiddenErrors2)
# 三、根据梯度下降公式求出用于更新j层到k层之间权重的矩阵式:(•是矩阵相乘;transpose作用是使矩阵转置)
# △W(j,k)=α×E(k)×sigmoid(O(k))×(1-sigmoid(O(k)))•(O(j)的转置)
# 更新self.hoWeightMatrix
self.hoWeightMatrix += self.lr * np.dot((outputErrors * finalOutputs * (1 - finalOutputs)),
np.transpose(hiddenOutputs2))
# 更新self.iiWeightMatrix
self.iiWeightMatrix += self.lr * np.dot((hiddenErrors2 * hiddenOutputs2 * (1 - hiddenOutputs2)),
np.transpose(hiddenOutputs1))
# 更新self.ihWeightMatrix
self.ihWeightMatrix += self.lr * np.dot((hiddenErrors1 * hiddenOutputs1 * (1 - hiddenOutputs1)),
np.transpose(inputs))
pass
def query(self, inputsList):
# 一、将输入的向量转置便于计算X=W(matrix)*I
# ndmin=定义数组的最小维度 或 数组嵌套层数;“.T”表示将矩阵转置
inputs = np.array(inputsList, ndmin=2).T
# 二、计算隐藏层1的输入X=W(matrix)*I
# dot可用于求数乘积、向量内积、矩阵乘法
hiddenInputs1 = np.dot(self.ihWeightMatrix, inputs)
# 三、隐藏层1输入通过sigmoid函数映射成输出
hiddenOutputs1 = self.activateFunc(hiddenInputs1)
# 四、计算隐藏层2的输入X=W(matrix)*I
# dot可用于求数乘积、向量内积、矩阵乘法
hiddenInputs2 = np.dot(self.iiWeightMatrix, hiddenOutputs1)
# 五、隐藏层2输入通过sigmoid函数映射成输出
hiddenOutputs2 = self.activateFunc(hiddenInputs2)
# 六、计算输出层的输入
finalInputs = np.dot(self.hoWeightMatrix, hiddenOutputs2)
# 七、输出层输入通过sigmoid函数映射成输出
finalOutputs = self.activateFunc(finalInputs)
return finalOutputs
#误差分析:均方误差
def MSE(predict,fact,n):
return np.sum((predict-fact)**2)/n
#初始化一个神经网络
input_nodes = 784
hidden_nodes1 = 30
hidden_nodes2 = 60
output_nodes = 10
learning_rate = 0.05
n = neuralNetwork(input_nodes, hidden_nodes1,hidden_nodes2,output_nodes, learning_rate)
#将训练集存入一个列表
#'r'指以只读的方式打开,mnistTrain是一个文件句柄
#读入文件中的所有行保存在trainList的列表中,列表每一项对应文件的一行字符串,可通过trainList[i]调取
mnistTrain=open("mnist_train.csv",'r')
trainList=mnistTrain.readlines()
mnistTrain.close() #关闭文件
#开始实际训练
epochs=1 #整个训练集遍历epochs次
for i in range(epochs):
for record in trainList:
# 根据‘,’进行拆分
allValues=record.split(',')
# csv中要输入的像素点值在0~255太大,将其缩小映射到0.01~1.0方便训练(可取1但不能取0,是因为输入0值可能更新权重会失败)
reducedInputs = (np.asfarray(allValues[1:])) / 255 * 0.99 + 0.01
#初始化目标矩阵,用0.01和0.99而不用0和1,因为sigmoid实际输出值不可能是0或1
targets=np.zeros(output_nodes)+0.01
targets[int(allValues[0])]=0.99
n.train(reducedInputs,targets)
pass
pass
#进行测试
mnistTest=open("mnist_test.csv",'r')
testList=mnistTest.readlines()
mnistTest.close()
score=[] #用计分来记录准确度
sum=0.0
for record in testList:
allValues=record.split(',')
#期望结果
expectedResult=int(allValues[0])
print(expectedResult,"正确的结果")
reducedInputs = (np.asfarray(allValues[1:])) / 255 * 0.99 + 0.01
outputs=n.query(reducedInputs)
# 实际输出结果
factResult=np.argmax(outputs) #.argmax输出outputs中的最大值
print(factResult,"网络输出的结果\n")
#累加计算误差平方和
sum+=((factResult-expectedResult)**2)
if(factResult==expectedResult):
score.append(1)
else:
score.append(0)
pass
pass
scoreArr=np.asarray(score)
#均方差
mse=sum/len(testList)
print("accuracy:",scoreArr.sum()/scoreArr.size*100,'%')
print("均方误差MSE:",mse)
#可视化例子:
i=int(input("可视化例子请输入要测试的记录编号:"))
allValues=testList[i].split(',')
print(allValues[0])
#asfarray将文本字符串转成实数并创建数组,.reshape确保数字列表每28个元素折返一次,得到28*28矩阵
imgArr=np.asfarray(allValues[1:]).reshape((28,28))
#imshow打印成图像,cmap是颜色映射,interpolation是抗锯齿的度
plt.imshow(imgArr,cmap='Blues',interpolation='None')
plt.show()
print(n.query((np.asfarray(allValues[1:])/ 255 * 0.99) + 0.01))
手撸神经网络(识别手写数字)
最新推荐文章于 2023-01-11 14:09:43 发布