MATLAB深度学习CNN包的代码详解补充及各变量参数说明

来源:互联网 发布:知乎 风扇灯什么牌子好 编辑:程序博客网 时间:2024/05/21 10:04

最近在做卷积神经网络,看了MATLAB版本的CNN包的实现,同时看了网上许多大神对此包的详细代码解释,感觉醍醐灌顶,同时感觉代码研究过程中仍有许多疑问,在这里针对MATLAB深度学习包的卷积神经网络包的训练说明,分别对程序运行过程中出现的变量以及其对应的意义做出说明。

首先,看此文章之前,请先了解以下前置内容:

Deep Learning(深度学习)学习笔记整理系列之(三) - zouxy09的专栏 - 博客频道 - CSDN.NET

http://blog.csdn.net/zouxy09/article/details/8775518

BP算法——别跟我说看完这个你还不懂 - Hungryof的专栏 - 博客频道 - CSDN.NET

http://blog.csdn.net/hungryof/article/details/50436231

卷积神经网络的详解 http://www.dataguru.cn/article-10638-1.html

详细解释CNN卷积神经网络各层的参数和链接个数的计算http://blog.csdn.net/dcxhun3/article/details/46878999

Deep Learning论文笔记之(四)CNN卷积神经网络bp算法推导和实现 http://blog.csdn.net/zouxy09/article/details/9993371/

Deep learning:五十一(CNN的反向求导及练习) - tornadomeet - 博客园

http://www.cnblogs.com/tornadomeet/p/3468450.html

cnn公式推导 - alexanderkun - 博客园

http://www.cnblogs.com/alexanderkun/p/4863691.html

 

然后,对于程序的详细源代码解释,参照此博客,本文是对此博客中一些遗漏的地方做些补充和说明:http://blog.csdn.net/zouxy09/article/details/9993743/

首先,在test_example_CNN.m中,各个变量的说明:

  • loadmnist_uint8;

mnist_uint8.mat:手写数字原始数据集,包括以下四个变量:

train_x60000幅大小为784的输入图像,train_y60000幅大小为10train_x图像对应的分类结果。这两个矩阵用来训练神经网络。

test_x10000幅大小为784的输入图像,test_y10000test_x图像应该输出的、正确的分类结果(softmax回归,结果由长度为10的向量组成,如[x1,x2,…,x10],x1x10分别有0~1的值代表该图像对应数字是1~10的概率,最大的那个xi既是分类结果)。用test_x去训练神经网络,得到结果后与test_y比较,从而输出错误率。

  • train_x = double(reshape(train_x',28,28,60000))/255;

    test_x = double(reshape(test_x',28,28,10000))/255;

    train_y = double(train_y');

    test_y = double(test_y');

对于这四行语句,是分别对上面说的四个矩阵进行变形操作,转换成double类型后求平均值。

train_x,先把60000x784的矩阵通过转置(')和reshape操作,转换成28x28x60000的图像,然后转换成double255(原始输入数据为0~255的值,这里需要压缩成0~1),即得到了6000028x28的手写数字输入图像。

train_y,直接转置(')然后转换成double,即得到了10x60000的矩阵,即60000train_x对应图像的分类结果。

test_xtest_y同上。

  • 来看optopt是训练过程中的训练参数,有这么三行:

    opts.alpha = 1;

    opts.batchsize = 50;

    opts.numepochs = 1;

    意义分别是系统调整权值时候的学习率α,每次训练的时候使用的一个样本的大小,以及训练次数。

  • cnn.layers = {

struct('type','i')%input layer

struct('type','c','outputmaps', 6, 'kernelsize', 5)%convolution layer

struct('type','s','scale', 2) %sub sampling layer

struct('type','c','outputmaps', 12, 'kernelsize', 5)%convolution layer

struct('type','s','scale', 2) %subsampling layer

};

由于cnn变量贯穿整个程序代码,这里分析当执行完cnn = cnntrain(cnn, train_x, train_y, opts);这句代码时,cnn结构的内容。

执行完上述代码,cnn结构如下:

首先,分析该神经网络的构建,是这样构建的:

此图由LENet-5改编,但有不同。

首先来看除了layers之外的其他变量,这些变量都是上图OUTPUT层的东西:

  • ffb1x10的向量矩阵,出现在cnnsetup.m即神经网络初始化过程的最后,代表神经网络输出层(10个神经元,代表数字1~10出现的概率)的输入偏置值b。由于最后两层神经元是全连接关系,即普通神经网络,则b是普通神经中的b

  • 同理,ffW是上式中的W,即输出层的每个神经元每条边上权值W的矩阵,大小为10x192,10代表输出的10个神经元,192代表每个神经元输入有192条边(通俗理解),192的原因是上图S4层与OUTPUT层是全连接关系,则S4层一共12张特征图,每张大小4x4,共12x4x4=192个神经元。
  • rL变量是每次训练完后的输出误差,代码在cnntrain.m的最后,最终要画出误差图像,公式如下:

    其中,Loss即是此变量,出现在cnnbp.m文件开头,是神经网络的均方误差函数:

% error

net.e = net.o - y;

% loss function

net.L = 1/2* sum(net.e(:) .^ 2) / size(net.e, 2);

其中,o即是,即CNN的最终输出,大小为10x50,50组输出,之所以是50是因为训练过程中是以50为一个样本来训练的(opt中的batchsize定义的);y是输入的已知正确的训练结果,则相减结果即是两个差值即e,最后L即是一个简单的均方误差公式,算出来他的均方误差即可,注意这里由于1个样本有50组图片组成,所以最终结果要除以50size(net.e, 2))。

  • 来看o向量的计算方式,即简单的普通神经网络的计算方式:

    则需要我们已经说过的ffW矩阵(W),ffb矩阵(b)以及S4层的x(输入值)矩阵,即fv,在cnnff.m的最后:

net.fv = [net.fv; reshape(net.layers{n}.a{j}, sa(1) * sa(2), sa(3))]

其中,net.layers{n}.aS4层的输出矩阵,大小为12x4x4(待会讲)。

fv向量是192x50的中间向量,他负责保存S4层的每个神经元的输出,由于S4层要与OUTPUT层全连接,所以把12x4x4三维输出矩阵拉成了192的一维向量作为最后一层的输入,同时由于存在50幅图像,因此大小为192x50

  • od变量为反向传播时输出层的残差,公式为:

    cnnbp.m的开头,大小为10x50,与输出o大小相同。

    fvd变量S4层的残差,由于S4层与OUTPUT层是全连接关系,所以S4层残差的计算方式是普通bp算法非最后一层敏感度的计算方式:,代码与od离得很近,大小为192x50,与S4层输出相同。

  • 最后两个变量,dffWdffb是反向传播算法bp算出来的要更新的梯度,是OUTPUT层的,公式为:

    代码在cnnbp.m的最后,同时用在cnnapplygrad.m中用梯度下降法来更新梯度:

    大小分别为10x1921x10,分别用来更新最后一层的WdffW)和bdffb)的值。

    至此,最后一层的参数全部解释完毕,接下来解释layers块的内容。

  • layers块分五层,分别对应下图的INPUT,C1,S2,C3,S4层。

    首先,对于INPUT层,就是一个类型说明加上一个INPUT层的输出矩阵a

    ,其中输出矩阵a大小为28x28x50,代表输入的28x28x50的样本值,即这一层输出就是原始的数据,用于给下一层卷积用的。

  • layers的第二层,即C1层,是卷积层,包括以下内容:

    typec类型说明符。

    outputmaps6,标记输出的特征map个数。

    kernelsize5,标记本层用的卷积核的大小为5x5

    首先分析该层的运算公式:

    其中,f用的是sigmoid公式,kij即是与input层输入x相对应卷积核,bj是每个特征MAP的偏置值。

  • k卷积核,大小为1x1,后面的1表示卷积图像数为1,即输入层只有一副特征图像,展开之后有一个1x6cell,表示对第一幅图像的6种卷积核,每一种大小为5x5

    其中解释:layers{2,1}代表第2层,k后面的{1,1}代表INPUT层的第一幅图像MAP{1,2}代表第二个卷积核,即k{1,1}{1,2}代表第一幅图像的第二个卷积核。

  • b1x6cell,代表C1层的6幅卷积MAP对应的偏置b
  • a:1x6cell,每个cell大小为24x24x50,即图中的特征MAP,本层的输出,下一层的输入。
  • d:1x6cellC1层的敏感值,大小自然和a相同,24x24x50,计算方法:

    这里,f'sigmoid的倒数,即f1-f),up为上采样操作(把下采样层缩小的map放大成原来的值,参考其他文献),S2层,即下采样层计算时用的权值,一会分析我们知道这里值为1,即此程序没有考虑这个值。

    代码详见cnnbp.m

  • dkdb是对卷积核(上文中的k变量)的梯度以及对每一层权值b(上文中的b变量)的梯度,大小自然与kb相同,计算公式:

    代码详见cnnbp.m,注意db计算过程中要把50幅图像敏感值全加起来然后除以50,而dk计算过程中需要把敏感值卷积核先旋转180,最终结果再旋转180度,即:

    原因详见:http://blog.csdn.net/qq_20028731/article/details/69831650

    这样,C1层分析完毕,接下来分析layers{3},即S2层。

  • 分析变量会发现这层东西很少,只有类型types,缩放比率scale2(代表在C1层每2x2map区域通过平均池化合并成一个区域)以及输出a,敏感值d,特征MAP的偏置b,没有梯度和权值,原因是什么?

    我们首先看标准CNN的下采样层的计算公式:

    即应该有输出Xj(在程序里用a表示),权值,下采样函数down,偏置bj以及最后的激活函数f,但通过分析cnnsetup.m以及cnnff.m发现,此程序在下采样层没有用到f,以及,虽然给了偏置b但是也没有用,恒为0,那我们也可以这样理解:

    在此程序中,到的偏置b=0=1,激活函数ff(x) = x,f'(x) = 1,即公式变成了:

    ,这就解释了为什么cnnff.m文件中对C层进行下采样操作的时候,只用了mean-pooling(平均池化)了。

    则在反向传导过程中的公式:

    由于f'(x)=1,则变成了:

    ,这就解释了为什么cnnbp.m文件中对S层求敏感度操作的时候,没有相乘导数的问题了。

    为什么要旋转180参照:http://blog.csdn.net/zy3381/article/details/44409535

    且由于偏置b恒为0,权值恒为1,就不用计算梯度了,也就用不着db之类的变量了。

    这样,S2层的变量解释完毕。

  • C3层和S4层变量和C1层与S2层完全相同,这里不做过多叙述,需要注意的地方:
  1. C3层的卷积核个数一共有12x6=72个,实际上在此程序中C3层每一个特征MAP都对S2层的6幅图像进行了卷积操作,换句话说,C312幅卷积特征map的每一幅都是用6个不同卷积核与S2层的6幅图像进行卷积,然后结果相加得到的map,且每一幅map6个卷积核都不同,这样才会有72种卷积核的存在,而在Lenet-5中,并不是每一幅map都会与上一层的所有图像卷积,怎么选择可以参照《Notes on Convolutional Neural Networks》的最后一部分。
  2. 程序训练的次数是test_example_CNN.mopt.numepochs定义的,而每次训练的时候都会把60000个样本随机打乱(参照cnntrain.m文件),然后以opt.batchsize一个样本,即上文一直提到的50幅图像为1个样本进行训练,最后求偏置平均的时候不要忘了去除50,训练样本数自然是60000/50=1200个训练样本。
  3. CNN包还带了一个检查梯度计算是否正确的cnnnumgradcheck.m文件,用来检查代码实现过程中公式是否有错误,他的原理参考:http://ufldl.stanford.edu/wiki/index.php/%E6%A2%AF%E5%BA%A6%E6%A3%80%E9%AA%8C%E4%B8%8E%E9%AB%98%E7%BA%A7%E4%BC%98%E5%8C%96
  4. 此深度学习包显示已经过时,作者也推荐大家使用新的框架例如caffeTensorFlowTheano等,因此此文章只是对那些刚接触深度学习的同学作为解答疑难用的,根据前面的分析大家也可以看出这个卷积神经网络实现的非常简单,错误率也在11%左右,不是很准确,因此只适用于初学者学习。同时笔者也刚接触这块内容,如有错误和侵权之处,尽请指出,笔者一定会第一时间改正。
0 0
原创粉丝点击