神经网络——识别数字图片
本人经过实验室对神经网络的学习,需完成通过神经网络实现数字图片识别的demo,现将思路与代码总结在博客中。
提示:以下思路及代码仅供参考
我们使用MINST数据集
第一部分:60000张数字图片用于训练模型的数据,大小均为28 * 28的灰度图像。
第二部分:10000张数字图片用于测试模型效果,大小也均为28 * 28的灰度图像。
设计并编写反向传播神经网络模型,通过60000幅图像对模型进行训练,并利用模型对10000幅测试用例进行分析,最终显示正确率。
代码如下:
import tensorflow as tf
import numpy as np
代码如下(示例):
mint = tf.keras.datasets.mnist;
(x_train, y_train), (x_test, y_test) = mint.load_data("D:\\ChromeCoreDownloads\\anaconda\\Anaconda3-2020.02_64\\Lib\\site-packages\\tensorflow\\keras\\datasets\\mnist\\mnist.npz")
#要将训练集和测试机都转成float32的类型,否则后续运算中会报错,类型不匹配
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
#将训练集和测试集归一化
x_train /= 256
x_test /= 256
此处我是直接导入的已经下载在本地的MNIST数据集,也可不添加load_data()里的路径参数,它会自动从网上下载,但每次运行均会下载一次,因此保存至本地会方便一些。
#激活函数
def get_act(inx):
return 1.0 / (1 + np.exp(-inx))
#求导函数
def sigmoid_derivative(x):
new_x = []
for i in range(len(x)):
new_x.append(get_act(x[i]) * (1 - get_act(x[i])))
new_x = np.array(new_x)
new_x = np.reshape(new_x, (x.shape[0], x.shape[1]))
return new_x
#设置网络基本参数
sampleNum =len(x_train) #样本个数
outputNum = 10 #0-9的数字,因此共10个神经元
inputNum = 784 #一张照片28*28的规格,因此输入层有784个神经元
hiddenNum = 45 #隐藏层神经元个数
#初始化输入层与隐藏层之间的权值矩阵
w = 1 * np.random.random((hiddenNum, inputNum))
w /= sum(w)
#初始化隐藏层与输出层之间的权值矩阵
v = 1 * np.random.random((outputNum, hiddenNum))
v /= sum(v)
inputLearnRate = 1 #输入层学习率
hiddenLearnRate = 1 #隐藏层学习率
hiddenOffset = np.zeros(hiddenNum) #隐藏层的偏置向量
hiddenOffset = np.reshape(hiddenOffset, (hiddenNum, 1))
outOffset = np.zeros(outputNum) #输出层的偏置向量
outOffset = np.reshape(outOffset, (outputNum, 1))
代码中w /= sum(w)
与v /= sum(v)
即是将矩阵中每个元素都除以矩阵每个元素相加的总和,使操作后的元素总和为1,目的是防止元素过大化影响结果。
#训练
print("Start training...")
for count in range(len(x_train)):
x_t = x_train[count]
x_t = np.reshape(x_t, (784, 1))
x_t += 0.001
# print(x_t)
# print()
expectLables = np.zeros(outputNum) #预期结果
expectLables[y_train[count]] = 1
expectLables = np.reshape(expectLables, (10, 1))
hiddenValue = np.dot(w, x_t) + hiddenOffset #隐藏层的输入
hiddenact = get_act(hiddenValue) #隐藏层的输出
outputValue = np.dot(v, hiddenact) + outOffset #输出层的输入
outputact = get_act(outputValue) #输出层的输出
error = (expectLables - outputact) * outputact * (1.0 - outputact)
error_L = np.dot(v.T, error) * hiddenact * (1.0 - hiddenact)
outOffset = outOffset + error #更新输出层的偏置向量
hiddenOffset = hiddenOffset + error_L #更新隐藏层的偏置向量
v = v + inputLearnRate * np.dot(error, np.transpose(hiddenact))
w = w + hiddenLearnRate * np.dot(error_L, np.transpose(x_t))
print("start testing")
right = 0
rightCount = np.zeros(10)
for count in range(len(x_test)):
x_t = x_test[count]
x_t = np.reshape(x_t, (784, 1))
hiddenValue = np.dot(w, x_t) + hiddenOffset # 隐藏层的输入
hiddenact = get_act(hiddenValue) # 隐藏层的输出
outputValue = np.dot(v, hiddenact) + outOffset # 输出层的输入
#print(outputValue)
outputact = get_act(outputValue) # 输出层的输出
#print(outputact)
# print(y_test[count])
max_num = outputact[0]
index = 0
for i in range(1, len(outputact)):
if outputact[i] > max_num:
max_num = outputact[i]
index = i
if(index == y_test[count]):
rightCount[y_test[count]] += 1
rightSum = rightCount.sum()
print("The number of right result: {0}".format(rightSum))
rate = rightSum / len(x_test)
print("正确率:",end=' ')
print(rate)
本次编写demo的过程中遇到了不少问题,例如:
1.为防止权值过大需要对其进行一定的处理,使各个元素之和为1。
2.权值修正时使用加号还是用减号都需要好好的推导一遍(你越想要某个输出越大那么它对应的权值就应该越大,因此权值的修正应该是预期的增大,其它的减小)。
3.为了使矩阵通过激活函数激活可利用循环对每个元素进行计算,但numpy提供了exp()
函数可对整个矩阵进行操作。
4.(临时写的比较仓促,后续想到了再补充文章)