使用Numpy训练基于MNIST数据集的深度卷积神经网络

在《Fundamentals of Deep Learning》一书中,作者将深度神经网络中的隐藏层的作用描述为"This is where most of the magic is happening when the neural net tries to solve problems";不过,从计算的角度来看,深度神经网络是一种功能强大的非线性变换,各个层的权重有着特定的处理数据的方式。然而,仅仅了解到深度神经网络的前向计算过程,是不够的;最好也能够对“雕刻”这些权重的反向传播有一定的了解。本文记录了笔者基于NumPy实现的简单深度卷积神经网络的训练方法,训练了LeNet5网络和《Python Machine Learning, 2nd》中的一个由TensorFlow改编的网络。经测试,训练的网络模型对MNIST数据集进行分类的准确度分别达到98%和96%以上。本文的代码可以在https://github.com/LinkYe/LearnDeep/tree/master/mnist-train中获得。

利用深度神经网络各层之间的相似性,笔者建立了卷积层ConvLayer、全连接层FullConLayer、池化层MaxPoolLayer和SoftMaxLayer,分别在单独的Python代码中实现。这些层有相似的Python类方法接口,即forward(...)和backward(...),这样就可以将这些层存放在列表中遍历调用,简化了前向和反向的调用过程。为了简化损失的计算,笔者将MSE作为损失函数的度量。详细的实现可参考MnistModel.py的内容。

将train-images-idx3-ubyte.gz及train-labels-idx1-ubyte.gz解压后复制到mnist-train目录下,就可以进行训练了。
训练lenet5网络的方法是在命令行执行:python3 -i MnistModel.py lenet5,一般配置中等的电脑一两个小时可以完成训练,其结果如下图:

训练另一个不知名的网络,则在命令行执行 python3 -i MnistModel.py,该网络的训练效率与lenet5相较而言,是很低的。以笔者的电脑来看,需训练一天的时间,下图是训练的过程:

由比较可知,Lenet5网络的效率、准确率要高很多,很大程度上优越于后者。这一方面是LeNet5网络权重参数更少(这样训练得越快),另一方面也是因为LeNet5网络更深了一层。还有,LeNet5的学习率(Learning Rate)为0.01,而后者的LR为0.0001。笔者曽把后者的LR设置为0.01,结果出现了浮点数溢出的问题,可见训练一个神经网络,模型参数的选择是很重要的。

最后一点重要的就是反向传播(Backpropagation)算法的实现了。在《深度学习基础》第二章有过这方面的论述,虽然只是大致的思路,且只是针对全连接层而言的,但核心的思想体现出来了,即从输出层开始对各层的输出结果计算差值(或者说,离散的微分),依次计算各层权重的微分,然后更新权重。对于卷积层的反向传播计算,论文《Notes on Convolutional Neural Networks》有详细的推导过程。这里需要注意的是,对于卷积层的计算,需要将卷积核上下、左右翻转,这一点在博客 https://grzegorzgwardys.wordpress.com/2016/04/22/8/ 中有详细的讨论。
对于输出层的softMax的求导,这里参考了 https://eli.thegreenplace.net/2016/the-softmax-function-and-its-derivative/ 的推导过程。有兴趣的可以参考代码一下这些链接和论文,加深对反向传播的理解。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章