欢迎光临散文网 会员登陆 & 注册

Python纯手动搭建BP神经网络(手写数字识别)

2022-02-07 18:39 作者:深度之眼官方账号  | 我要投稿


来源:投稿 作者:张宇 

编辑:学姐


实验介绍

实验要求:


实现一个手写数字识别程序,如下图所示,要求神经网络包含一个隐层,隐层的神经元个数为15。




整体思路:


主要参考西瓜书第五章神经网络部分的介绍,使用批量梯度下降对神经网络进行训练。


Tip: 整体代码及数据集

关注公众号

回复“新年快乐”领取

读取并处理数据

数据读取思路:

  • 数据集中给出的图片为28*28的灰度图,利用 plt.imread() 函数将图片读取出来后为 28x28 的数组,如果使用神经网络进行训练的话,我们可以将每一个像素视为一个特征,所以将图片利用numpy.reshape 方法将图片化为 1x784 的数组。读取全部数据并将其添加进入数据集 data 内,将对应的标签按同样的顺序添加进labels内。

  • 然后使用np.random.permutation方法将索引打乱,利用传入的测试数据所占比例test_ratio将数据划分为测试集与训练集。

  • 使用训练样本的均值和标准差对训练数据、测试数据进行标准化。标准化这一步很重要,开始忽视了标准化的环节,神经网络精度一直达不到效果。

  • 返回数据集


这部分代码如下:


OneHot编码:


由于神经网络的特性,在进行多分类任务时,每一个神经元的输出对应于一个类,所以将每一个训练样本的标签转化为OneHot形式(将0-9的数据映射在长度为10的向量中,每个样本向量对应位置的值为1其余为0)。


训练神经网络

激活函数:


激活函数使用sigmoid函数,但是使用定义式在训练过程中总是出现 overflow 警告,所以将函数进行了如下形式的转化。


损失函数:


使用均方误差损失函数。其实我感觉在这个题目里面直接使用预测精度也是可以的。


训练:


终于来到了紧张而又刺激的训练环节。神经网络从输入层通过隐层传递的输出层进而获得网络的输出叫做正向传播,而从输出层根据梯度下降的方法进行调整权重及偏置的过程叫做反向传播。


前向传播每层之间将每个结点的输出值乘对应的权重$\omega$(对应函数中 omega1 omega2 )传输给下一层结点,下一层结点将上一层所有传来的数据进行求和,并减去偏置 theta (此时数据对应函数中 h_in o_in )。最后通过激活函数输出下一层(对应函数中 h_out o_out )。在前向传播完成后计算了一次损失,方便后面进行分析。


反向传播是用梯度下降法对权重和偏置进行更新,这里是最主要的部分。根据西瓜书可以推出输出层权重的调节量为$\eta\hat{y_i}(1-\hat{y_i})(y_i - \hat{y_i})b_h$ ,其中 $\eta$ 为学习率, $y_i\space\hat{y_i}$ 分别为对应数据的真实值以及网络的输出, $b_h$ 为隐层的输出值。这里还要一个重要的地方在于如果将公式向量化的话需要重点关注输出矩阵形状以及每个矩阵数据之间的关系。代码中d2 对应于公式中$\hat{y_i}(1-\hat{y_i})(y_i - \hat{y_i})$ 这一部分,这里需要对应值相乘。最后将这一部分与$b_h$进行矩阵乘法,在乘学习率$\eta$得到权重调节量,与权重相加即可(代码中除了训练集样本个数m是因为 d2 与 h_out 的乘积将所有训练样本进行了累加,所以需要求平均)。


对于其他权重及偏置的调节方式与此类似,不做过多介绍(其实是因为明天要上课,太晚了得睡觉,有空补上这里和其他不详细的地方),详见西瓜书。


关注公众号,

回复“西瓜书”即可获取pdf版


网络测试

预测函数:


这里比较简单,前向传播的部分和前面一样,因为最后网络输出的为样本x为每一类的概率,所以仅需要利用 np.argmax 函数求出概率值最大的下标即可,下标0-9正好对应数字的值。


准确率计算: 


这里将所有测试数据 X 进行预测,计算预测标签 y-hat 与真实标签 y 一致个数的均值得出准确率。



主函数: 


在主函数中通过调用上面的函数对网络训练预测精度,并使用 loss_list acc_list 两个list保存训练过程中每一轮的精度与误差,利用 acc_max 跟踪最大精度的模型,并使用 pickle 将模型(其实就是神经网络的参数)进行保存,后面用到时可以读取。同样在训练完成时我也将 loss_listacc_list 进行了保存 (想的是可以利用训练的数据做出一点好看的图)。


最后部分将损失以及准确率随着训练次数的趋势进行了绘制。


结果如下:




可以看出,模型只是跑通了,效果并不好,训练好几个小时准确率只有91%。原因可能是因为没有对模型进行正则化、学习率没有做动态调节等。


相反使用SVM模型准确率轻松可以达到97%以上。


瑟瑟发抖~~~

最后将全部代码贴上:


获取代码及数据集

请关注公众号

回复“新年快乐”即可



一键三连「分享」、「点赞」和「在看」

点赞的情谊学姐铭记在心~

Python纯手动搭建BP神经网络(手写数字识别)的评论 (共 条)

分享到微博请遵守国家法律