看了《python神经网络编程》,跟着书上敲了一下mnist手写数字的代码,对神经网络有了初步的了解。
此项目为三层神经网络识别,激活函数采用sigmoid函数,数据集为mnist手写数字集,训练集包括60000个样本,测试集10000个样本。
第一部分,创建神将网络模型
import numpy
import matplotlib.pyplot
#%matplotlib inline用在Jupyter notebook中(代替plt.show()),使用%matplotlib命令可以将matplotlib的图表直接嵌入到Notebook之中
%matplotlib inline
#sigmoid函数,在这组函数中,S函数称为expit()
import scipy.special
class neuralNetwork:
def __init__(self,inputnodes,hiddennodes,outputnodes,learningrate):
self.inodes = inputnodes #输入节点
self.hnodes = hiddennodes #隐藏节点
self.onodes = outputnodes #输出节点
self.lr = learningrate #学习率
# 初始化参数
self.wih=(numpy.random.rand(self.hnodes,self.inodes )-0.5)
self.woh=(numpy.random.rand(self.onodes,self.hnodes)-0.5)
# 激活函数为sigmoid函数,使用lambda创建函数(匿名函数),方便快捷
self.activation_function = lambda x:scipy.special.expit(x)
pass
# 训练d代码
def train(self,input_list,target_list):
# 将输入转换为numpy数组,dmin指定生成数组的最小维度
inputs = numpy.array(input_list,ndmin=2).T
targets = numpy.array(target_list,ndmin=2).T
# 计算隐藏层
hidden_inputs = numpy.dot(self.wih,inputs)
# 调用sigmoid激活函数
hidden_outputs = self.activation_function(hidden_inputs)
# 输出层
final_inputs=numpy.dot(self.woh,hidden_outputs)
final_outputs = self.activation_function(final_inputs)
# 计算误差
error = targets-final_outputs
# 隐藏层误差节点反向传播的误差
hidden_error = numpy.dot(self.woh.T,error)
# 优化权重, 正常对应元素相乘,·乘是矩阵点击
# transpose()简单来说,就相当于数学中的转置,在矩阵中,转置就是把行与列相互调换位置;
self.woh += self.lr * numpy.dot((error * final_outputs * (1.0-final_outputs)),numpy.transpose(hidden_outputs))
self.wih += self.lr * numpy.dot((hidden_error*hidden_outputs*(1.0-hidden_outputs)),numpy.transpose(inputs))
pass
# 查询函数
def query(self,inputs):
inputs = numpy.array(inputs,ndmin=2).T
hidden_inputs = numpy.dot(self.wih,inputs)
hidden_outputs = self.activation_function(hidden_inputs)
final_inputs=numpy.dot(self.woh,hidden_outputs)
final_outputs = self.activation_function(final_inputs)
return final_outputs
pass
第二部分 训练网络
inputnodes=28*28
hiddennodes=100
outputnodes=10
learningrate=0.1
# 创造神经网络实例
n = neuralNetwork(inputnodes,hiddennodes,outputnodes,learningrate)
# 获取mnist_train数据集
training_date_file = open("mnist_train.csv","r")
training_date_list = training_date_file.readlines()
training_date_file.close()
a=0
for record in training_date_list:
# 用“,”分割长的字符串值,拆分为单个值
all_values = record.split(',')
# 第一个值为标签,忽略, 将剩余784个值转换为28*28数组
# numpy.asfarray()将文本字符串转换为实数并创建这些数字的数组,
# 因为文件是用文本读取的,每一条记录仍然是文本,用“,”分割得到的仍然是文本
# all_values[1:]/255.0*0.99)+0.01 是将输入颜色从0-255缩小到0.01-1.00,最小值为0.01是避免先前观察到的0值输入最终会人为地造成权重更新失败
inputs =( numpy.asfarray(all_values[1:])/255.0*0.99)+0.01
# 将训练目标标签从字符串形式转换为整数形式,正确元素设置为0.99 标签“0”转换为整数0
targets = numpy.zeros(outputnodes)+0.01
targets[int(all_values[0])]=0.99
n.train(inputs,targets)
# a用来计数,查看训练进度
a=a+1
if(a%10000==0):
print(a)
pass
网络训练结束
第三部分 网络测试
# 测试网络
test_date_file = open("mnist_test.csv","r")
test_date_list = test_date_file.readlines()
test_date_file.close()
# 创建空列表,用作积分卡,在测试每条记录之后都会进行更新
scorecard=[]
b=0
for record in test_date_list:
all_values = record.split(',')
inputs = (numpy.asfarray(all_values[1:])/255.0*0.99)+0.01
# 目标标签
correct_label=int(all_values[0])
outputs = n.query(inputs)
# 测试所得标签
label=numpy.argmax(outputs)
# 如果相等,在记分卡追加1,不相等0
if(label==correct_label):
scorecard.append(1)
else:
scorecard.append(0)
# b用来计数,查看测试进度
b= b+1
if(b%1000==0):
print(b)
pass
#输出正确率
scorecard_array=numpy.asarray(scorecard)
print("Accuracy= ",scorecard_array.sum()/scorecard_array.size)
结果:
模型改进:
1.调整学习率,变大,变小
- 当前学习率为0.1,准确率为0.9477
- 调整学习率为0.2,学习率有所提升.
- 调整为0.05,学习率有所下降
2.多次运行,训练一次称为一个世代
3.改变网络形状,改变隐藏节点的数量等