首页 > 编程知识 正文

1~10手写体图片,基于神经网络的手写数字识别

时间:2023-05-05 23:21:50 阅读:32901 作者:2950

文章目录一、问题说明二、设计简要说明三、程序清单四、结果分析五、调试报告六、实验总结

一、问题说明

虽然进行了手写识别,但是与实验5相比,升级的地方是网络层的封装和坡度降低时通过上反向传播提交代码的复用性和训练效率较高。

二、设计简述机器学习的三个基本步骤——

编程思路—— (此图可放大观看)。

三、程序列表importnumpyasnpfrommnistimportload _ mnistfromcollectionsimportordereddict #规则词典,记录传递的变量顺序。 传播更好的值获取class Relu: def __init__(self ) : self.mask=nonedefforward (x ) : #数组中小于0的元素的索引self.min 小于0的是True ) out=x.copy ) # out变量表示要传播到下一层的数据。 也就是说,上图中的y out[self.mask]=0 #将True的值更改为0返回输出后台(self,dout ) 3360 dout [ self.mask ]=0#。 如果正向传播的输入值小于或等于0,则反向传播的值为0dx=doutreturndxclasslinear : def _ init _ (self,w, b ) : self.W=W #权重参数self.b=b #偏置参数self.x=None # )用于存储输入数据的成员变量权重和用于存储偏置参数的梯度self.dw=将定义的所有连接层的前向传播defforward(self,x ) : #输入数据保存到成员变量用于backward计算的self.x=x # )代码完成,将所有连接层的前向传播的输出保存在变量out中out=self.x.dot(self.w ) self.b return out #所有连接层的反向传播defbackward(self,dout ) : # dx、dw、db、dw、db保存在成员变量self.dW中。 在self.db中为dx=dout.dot(self.w.t ) self.dw=self.x.t.dot ) dout (self.db=NP.sum ) dout, axis=0)返回dx # soft max函数defsoftmax(a ) : exp_a=np.exp(a ) a ) sum_exp_a=NP.sum(exp_a ), axis=1keep dims=true (y=exp _ a/sum _ exp _ areturny #损失函数) y是神经网络的输出,t是标签def cross_entropy_error(y () NP.log(yDelta ) ) classoftmaxwithloss 3360 def _ _ init _ ) self ) : softmax的输出self.t=None #监视数据# softmaxwithll t ) :self.t=tself.t=softmax(x ) self.loss=cross _ entropy _ error (self.y,self.t ) returnself.loss 注意(反向传播时传播的值除以批处理的大小,传递到上一层的是单个数据的误差batch_size=self.t.shape[0] #检索批处理数据的数量dx=(self.y - self.t ) 从计算各个数据的误差returndxclasstwize的模型初始化def_init_(self,input_size,hidden_size,output_size,weight _ init

重 self.params = {} # 获取第一层权重和偏置 self.params['W1'] = weight_init_std * np.random.randn(input_size, hidden_size) self.params['b1'] = np.zeros(hidden_size) # 获取第二层权重和偏置 self.params['W2'] = weight_init_std * np.random.randn(hidden_size, output_size) self.params['b2'] = np.zeros(output_size) # 生成层 # 将神经网络的层保存为有序字典OrderedDict self.layers = OrderedDict() # 添加第一个全连接层到有序字典中 self.layers['Linear1'] = Linear(self.params['W1'], self.params['b1']) # 激活函数层 self.layers['relu'] = Relu() # 第二个全连接层 self.layers['Linear2'] = Linear(self.params['W2'], self.params['b2']) # 将SoftmaxWithLoss类实例化为self.lastLayer self.lastLayer = SoftmaxWithLoss() # 识别函数调用每个层的向前传播的函数,并且把输出作为下一个层的输入 # 通过前向传播获取预测值 def predict(self, x): # 遍历有序字典 for layer in self.layers.values(): # 请补充代码完成神经网络层的前向传播 x = layer.forward(x) return x # x:输入数据, t:监督数据 def loss(self, x, t): # 获取预测值 y = self.predict(x) # 返回损失 return self.lastLayer.forward(y, t) # 求精度 def accuracy(self, x, t): y = self.predict(x) # 获取预测概率最大元素的索引和正确标签的索引 y = np.argmax(y, axis=1) t = np.argmax(t, axis=1) accuracy = np.sum(y == t) / float(x.shape[0]) return accuracy # 求梯度 def gradient(self, x, t): # forward self.loss(x, t) # backward dout = 1 # 求最后SoftmaxWithLoss层的反向传播输出 dout = self.lastLayer.backward(dout) # 从后往前遍历有序字典 layers = list(self.layers.values()) layers.reverse() for layer in layers: # 获取正在被遍历的层的反向传播输出 dout = layer.backward(dout) # 设定 grads = {} # 获取第一层网络参数的梯度 grads['W1'], grads['b1'] = self.layers['Linear1'].dW, self.layers['Linear1'].db # 获取第二层网络参数的梯度 grads['W2'], grads['b2'] = self.layers['Linear2'].dW, self.layers['Linear2'].db return gradsif __name__ == '__main__': # 获得MNIST数据集 (x_train, t_train), (x_test, t_test) = load_mnist(one_hot_label=True) # 定义训练循环迭代次数 iters_num = 2000 # 获取训练数据规模 train_size = x_train.shape[0] # 定义训练批次大小 batch_size = 100 # 定义学习率 learning_rate = 0.1 # 计算一个epoch所需的训练迭代次数(一个epoch定义为所有训练数据都遍历过一次所需的迭代次数) iter_per_epoch = 1 MyTwoLayerNet = TwoLayerNet(input_size=784, hidden_size=50, output_size=10) # 实例化TwoLayerNet类创建MyTwoLayerNet对象 #训练循环的代码 for i in range(iters_num): # 在每次训练迭代内部选择一个批次的数据 batch_choose = np.random.choice(train_size, batch_size) # choice()函数的作用是从train_size中随机选出batch_size个 x_batch = x_train[batch_choose] t_batch = t_train[batch_choose] # 计算梯度 grad = MyTwoLayerNet.gradient(x_batch, t_batch) # 更新参数 for params in ('W1', 'b1', 'W2', 'b2'): MyTwoLayerNet.params[params] -= learning_rate * grad[params] loss = MyTwoLayerNet.loss(x_batch, t_batch) # 判断是否完成了一个epoch,即所有训练数据都遍历完一遍 if i % iter_per_epoch == 0: train_acc = MyTwoLayerNet.accuracy(x_train, t_train) test_acc = MyTwoLayerNet.accuracy(x_test, t_test) # 输出一个epoch完成后模型分别在训练集和测试集上的预测精度以及损失值 print("iteration:{} ,train acc:{}, test acc:{} ,loss:{}".format(i, round(train_acc, 3), round(test_acc, 3), round(loss, 2))) 四、结果分析


本次实验与上次实验相比用上了反向传播算法,计算速度上快了许多,大约只用了7、8分钟就运行了2000轮;效率上也高很多,2000轮时精确度基本稳定在94%。足见方法正确的重要性。

项目目录结构

五、调试报告 第一次运行遇到的问题说mnist库的main函数无法调用,但查看解释器明明已经导入该库,对照上一次实验发现是缺少mnist.py文件。在构建网络时开始没有主要到加入第二个全连接层之前要先加入Relu激活层,对比加入前后的结果发现,同样是训练2000轮,没加激活层的网络精确度最后大约在0.92(如下图所示),加入激活层后,精确度最后大约在0.94(见“结果分析”)。
六、实验小结

收获:

学到了计算图的概念,今后在写含有复杂公式代码时可以尝试自己画确定反向传播公式的两把利剑:①链式法则 ②矩阵的形状在Relu激活层由于反向传播时对于正向输入小于0的输入要让信号停在此处(即让其为0),这里巧妙地应用了self.mask数组,先将所有正向输入小于0的设置为True,再让所有值为True的等于0。另外此次实验将不同的网络层进行了封装,再结合有序字典OrderedDict,这样做提升了代码的可维护性和可复用性,可以很轻松地搭建网络。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。