HanyNet – 卷积神经网络的初步实现

        全部代码已经发布在https://github.com/johnhany/HanyNet


        开发环境

        Windows 7 x64 Ultimate

        Visual Studio 2012 Ultimate

        OpenCV 3.1

        RapidXML 1.13


        模型

        基于经典的LeNet卷积网络模型,该网络结构如下图所示:

lenet        包含输入层,卷积层,降采样层,全连通层以及输出层。

        以手写数字为例,网络分类过程如下图所示:

mnist_1mnist_2mnist_3


        网络结构在parameters.xml文件内定义,各参数的含义如下:

        group_samples – 输入层包含的样本数。推荐人脸识别采用10;MNIST手写字体识别采用50、64等大一些的值。

        epoch_num – 训练的总迭代次数。依据样本量而定,若训练样本较少,则设为几百上千量级的值;若是MNIST这种很大的样本库,则设为10即可。

        gradient_alpha – 训练收敛速度。采用默认的1.0即可。

        sample_width – 输入样本图像的宽度。其值由网络的层数决定,如果包含2卷积层和2降采样层,则设为28;若包含3卷积层和3降采样层,则设为60。

        sample_height – 输入样本图像的高度。其值由网络的层数决定,如果包含2卷积层和2降采样层,则设为28;若包含3卷积层和3降采样层,则设为60。

        net_struct – 规定网络的结构。其中的layer定义每一层的属性,具体如下,

                type="i" – 输入层;

                type="c" – 卷积层,其中func为激活函数(可为relusigmoid),maps为卷积核的数量,size为卷积核的尺寸(最好为奇数);

                type="s" – 降采样层,其中scale为缩小的比例;

                type="o" – 输出层,其中func为激活函数(只能为softmax),classes为类别数。

        第一层必须为输入层;最后一层必须为输出层;中间隐层由一对对卷积层加降采样层构成。结构如下:

                i | c | s | c | s | o

        或

                i | c | s | … | c | s | o


       HanyNet-run.cpp文件的一些说明:

       1. 17-19行的以下三个宏只允许一个有定义:

              _HANY_NET_LOAD_MNIST – 载入MNIST训练集

              _HANY_NET_LOAD_SAMPLE_FROM_PIC – 载入图像训练集

              _HANY_NET_CAPTURE_FACE_FROM_CAMERA – 从摄像头捕捉训练集

       2. 21-24行的以下四个宏只允许一个有定义:

              _HANY_NET_PREDICT_MNIST – 载入MNIST测试集

              _HANY_NET_PREDICT_IMAGE_SERIES – 载入图像测试集

              _HANY_NET_PREDICT_VEDIO_SERIES – 将视频文件作为测试集

              _HANY_NET_PREDICT_CAMERA – 从摄像头捕捉测试集

       3. 如果每一类有单独的字符串名称,请准备好一个标签文本文件,并使第36行的label_file指向该文件,取消26行_HANY_NET_WITH_LABEL_NAMES的注释。

       4. 29行的pretrained_cnn_file指向预训练好的xml文件。

       5. 35行的sample_file_pre指向样本集目录(包含图像或者视频文件)。

       6. 42行的sample_num为每个类别包含的样本数。我们规定所有类别所包含的样本数是相同的。


       HanyNet.h文件的一些说明:

       1. 36行的_HANY_NET_TRAIN_FROM_SCRATCH有定义时,完成网络训练和测试样本分类两个步骤;_HANY_NET_TRAIN_FROM_SCRATCH未定义时,跳过训练步骤,只完成测试样本分类一个步骤。

       2. 39行的_HANY_NET_LIMIT_SAMPLE_NUM规定训练样本数量的上限,在调试代码阶段会比较有帮助。


       MNIST手写数字识别

       在这里下载MNIST数据库,并把t10k-images.idx3-ubyte, t10k-labels.idx1-ubyte, train-images.idx3-ubyte, train-labels.idx1-ubyte四个文件拷贝到HanyNet-run.cpp同一目录下。

       保持_HANY_NET_LOAD_MNIST_HANY_NET_PREDICT_MNIST有定义。


       自定义样本库

       1. 训练样本为图像。保持_HANY_NET_TRAIN_FROM_SCRATCH有定义。保持_HANY_NET_LOAD_SAMPLE_FROM_PIC有定义,设置sample_file_pre为样本目录,设置sample_num为每个类别包含的样本数。样本图像文件名称需按照a_b.jpg的格式,其中a为类别号,b为类内样本号,a和b均以0开始。

       2. 从摄像头捕捉训练样本(仅限人脸识别)。保持_HANY_NET_TRAIN_FROM_SCRATCH有定义。保持_HANY_NET_CAPTURE_FACE_FROM_CAMERA有定义。HanyNet利用Haar级联分类器从画面中检测人脸,再将检测到的人脸片元作为样本。每个人采集sample_num幅样本,采集满sample_num幅图像之后,程序暂停样本录入,将摄像头对准下一个人,按空格键开始捕捉第二个人的图像。所有人的样本录入完毕后,按ESC键开始训练网络。

       3. 测试样本为图像。保持_HANY_NET_PREDICT_IMAGE_SERIES有定义,设置sample_file_pre为样本目录,设置sample_num为每个类别包含的样本数。样本图像文件名称需按照a_b.jpg的格式,其中a为类别号,b为类内样本号,a和b均以0开始。

       4. 从视频文件捕捉测试样本(仅限人脸识别)。保持_HANY_NET_PREDICT_VEDIO_SERIES有定义。设置sample_file_pre为样本目录。样本图像文件名称需按照a.wmv的格式,其中a为类别号,以0开始。

       5. 从摄像头捕捉测试样本(仅限人脸识别)。保持_HANY_NET_PREDICT_CAMERA有定义。


       分类精度

       MNIST:采用双隐层网络,测试集精度在83~88%之间。训练耗时1546.98s(60000样本,10次迭代),测试耗时392.15s(10000样本)。

       人脸识别:4人情况下,正确率100%;10人以上正确率欠佳。

       车辆分类:4种车型(轿车,SUV,货车,客车),每种车型30个样本,正确率最高97%(客车),其余为67%(轿车),87%(SUV),73%(货车)。


       未来计划

       一个更完备的项目正在开发之中,使HanyNet支持更复杂的深度学习模型,并加入多线程支持和CUDA支持。

共有13条评论

  1. 这位道友功力深厚,注重实践,在下佩服。我有个简单的问题想请教一下,如果只是单纯的把网络的层数增多话,会对结果造成什么影响?

    1. 我也是刚刚入门,还有很多要学。按我的理解,单纯堆叠层数会很容易出现梯度在反向传播过程中逐渐缩小直至消失的情况,这样相距较远的层之间的影响微乎其微,对网络的训练是无益甚至有害的。可以参考一下ILSVRC-2015第一名的模型,用residual net来克服这个问题。链接

      1. 谢谢岳老湿的资源,兽交了。那deep learning是不是就是解决层数过多的时候网络的训练问题?

        1. 强锅!原来是你!昨天没反应过来。别瞎闹,还有孩子呢,,,

          deep learning一般统称隐层两层以上的神经网络,非常深的网络训练还要靠其他方法来辅助微调。

          1. 哈哈,有时候会到岳老湿这里来学习一下。非常♂深的网络如果训练时调整好的话,在测试时和层数较少的网络比的话效果会不会好呢?

          2. 一般应该是这个规律,如果能收敛到相同的误差,越深的网络表述能力越♂。当类别数达到成百上千时,浅层网络就应付不了了。

  2. 请问残差不收敛如何解决?迭代1000次"with error of: " << stage_loss.back()都稳定在0.25左右

      1. 我试了一下,如果迭代5000次,开始的时候大概是0.26,到2000次左右的时候下降到0.07,然后又逐步恢复到0.25。如果是只迭代1000次,则一直稳定在0.25左右

        1. 朋友的求知态度实在敬佩!我自己都没有这么详细的试验过。这里已经有了你的联系方式,方便的话,我们交流一下!

          1. 深感荣幸,我最近也在用CNN对图像进行分类,但是是用linux环境下用python完成的,希望能够交流

发表评论

电子邮件地址不会被公开。 必填项已用*标注