深度学习12:能力提升, 一步一步的介绍如何自己构建网络和训练,利用MatConvNet

深度学习12:能力提升, 一步一步的介绍如何自己构建网络和训练,利用MatConvNet

本文为原创文章转载必须注明本文出处以及附上 本文地址超链接  以及 博主博客地址:http://blog.csdn.NET/qq_20259459  和 作者邮箱( jinweizhi93@gmai.com )。

(如果喜欢本文,欢迎大家关注我的博客或者动手点个赞,有需要可以邮件联系我)

 

在上一篇文章中我们已经介绍了自带的cifar-10的code。下面我将非常详细的一步一步的介绍如何训练自己的数据。

 

前期工作:下载安装matlab和下载MatConvNet以及下载GPU相关文件和配置GPU。
具体请参见我之前的文章:
1. 深度学习 2. MatConvNet(CNN)的配置和相关实验结果,CNN学习使用(本人project作业) :
http://blog.csdn.net/qq_20259459/article/details/54092277
2. 深度学习 3. MatConvNet (CNN)的介绍和下载以及CPU和GPU的安装配置,Matlab2016 :
http://blog.csdn.net/qq_20259459/article/details/54093550


准备工作:
1. 打开Matlab,配置相关文件的路径(http://blog.csdn.net/qq_20259459/article/details/54092277
2. 输入 mex -setup cpp
3. 输入 vl_compilenn
4. 输入 compileGPU
没有报错则配置完成。

 

开始,新建编辑页 cnn_cifar_my :

这是外层调参和构建imdb结构体的code。

关于调参我会在后面单取一篇来介绍。

函数相互调用顺序:主函数 function [net, info] = cnn_cifar_my(varargin) :

1. 首先初始化网络如下:

 

[plain] view plain copy
 
  1. opts.batchNormalization = false ;                   %选择batchNormalization的真假  
  2. opts.network = [] ;                                 %初始化一个网络  
  3. opts.networkType = 'simplenn' ;                     %选择网络结构 %%% simplenn %%% dagnn  
  4. [opts, varargin] = vl_argparse(opts, varargin) ;    %调用vl_argparse函数  
  5.   
  6. sfx = opts.networkType ;                                                %sfx=simplenn  
  7. if opts.batchNormalization, sfx = [sfx '-bnorm'] ; end                  %这里条件为假  
  8. opts.expDir = fullfile(vl_rootnn, 'data', ['cifar10-' sfx]) ;    %选择数据存放的路径:data\cifar-baseline-simplenn  
  9. [opts, varargin] = vl_argparse(opts, varargin) ;                        %调用vl_argparse函数  
  10.   
  11. opts.dataDir = fullfile(vl_rootnn, 'data', 'cifar10') ;                   %选择数据读取的路径:data\matconvnet-1.0-beta23\data\cifar  
  12. opts.imdbPath = fullfile(opts.expDir, 'imdb.mat');                      %选择imdb结构体的路径:data\data\cifar-baseline-simplenn\imdb  
  13. opts.whitenData = true ;  
  14. opts.contrastNormalization = true ;  
  15. opts.train = struct() ;                                                 %选择训练集返回为struct型  
  16. opts = vl_argparse(opts, varargin) ;                                    %调用vl_argparse函数  
  17.   
  18. %选择是否使用GPU,使用opts.train.gpus = 1,不使用:opts.train.gpus = []。  
  19. %有关GPU的安装配置请看我的博客:http://blog.csdn.net/qq_20259459/article/details/54093550  
  20. if ~isfield(opts.train, 'gpus'), opts.train.gpus = [1]; end;                

2. 调用网络结构函数 cnn_cifar_init_my (这个函数用于构造自己的网络结构) :

 

 

[plain] view plain copy
 
  1. if isempty(opts.network)                                                    %如果原网络为空:  
  2.   net = cnn_cifar_init_my('batchNormalization', opts.batchNormalization, ...   %   则调用cnn_cifat_init网络结构  
  3.     'networkType', opts.networkType) ;  
  4. else                                                                        %否则:  
  5.   net = opts.network ;                                                      %   使用上面选择的数值带入现有网络  
  6.   opts.network = [] ;  
  7. end  

 

 

3. 接下来将调用得到imdb的相关函数(用于训练的数据集):

 

[plain] view plain copy
 
  1. if exist(opts.imdbPath, 'file')                         %如果cifar中存在imdb的结构体:  
  2.   imdb = load(opts.imdbPath) ;                          %   载入imdb  
  3. else                                                    %否则:  
  4.   imdb = getMnistImdb(opts) ;                           %   调用getMnistImdb函数得到imdb并保存  
  5.   mkdir(opts.expDir) ;                                    
  6.   save(opts.imdbPath, '-struct', 'imdb') ;  
  7. end  
[plain] view plain copy
 
  1. %arrayfun函数通过应用sprintf函数得到array中从1到10的元素并且将其数字标签转化为char文字型  
  2. net.meta.classes.name = arrayfun(@(x)sprintf('%d',x),1:10,'UniformOutput',false) ;  

4. 然后调用网络类型(simplenn,dagnn):

 

 

[plain] view plain copy
 
  1. switch opts.networkType                                     %选择网络类型:  
  2.   case 'simplenn', trainfn = @cnn_train ;                   %   1.simplenn  
  3.   case 'dagnn', trainfn = @cnn_train_dag ;                  %   2.dagnn  
  4. end  
  5.   
  6. %调用训练函数,开始训练:find(imdb.images.set == 3)为验证集的样本  
  7. [net, info] = trainfn(net, imdb, getBatch(opts), ...          
  8.   'expDir', opts.expDir, ...  
  9.   net.meta.trainOpts, ...  
  10.   opts.train, ...  
  11.   'val', find(imdb.images.set == 3)) ;  

综上所述,我们的流程是:1. 输入网络和参数的初始值。2. 构建训练网络结构。3. 建立训练数据集。4. 选择训练网络的类型。

 

注:
imdb结构体:
1. 这是用于cnn_train中的结构体,也就是实际训练的部分。
2. 该结构体内共有4个部分,由data,label,set,class组成。
  data:包含了train data和test data。
  label:包含了train label和test label。
  set:set的个数个label的个数是相等的,set=1表示这个数据是train data,set=3则表示这个数据是test data。   以此方法用于计算机自己判断的标准。
  class:于数据中的class完全一样。
3. imdb构造时遵循train在上层,test在下层的顺序。
4. 相关的data需要进行泛化处理。

下面以我自己的数据为例构建一个自己的imdb:

 

[plain] view plain copy
 
  1. function imdb = getMnistImdb(opts)  
  2. %% --------------------------------------------------------------  
  3. %   函数名:getMnistImdb  
  4. %   功能:  1.从mnist数据集中获取data  
  5. %           2.将得到的数据减去mean值  
  6. %           3.将处理后的数据存放如imdb结构中  
  7. % ------------------------------------------------------------------------  
  8. % Preapre the imdb structure, returns image data with mean image subtracted  
  9.   
  10. load('TR.mat');   
  11. load('TT.mat');  
  12. load('TRL.mat');  
  13. load('TTL.mat');  
  14.   
  15. x1 = TR;  
  16. x2 = TT;  
  17. y1 = TRL;  
  18. y2 = TTL;  
  19.   
  20. %set = 1 对应训练;set = 3 对应的是测试  
  21. set = [ones(1,numel(y1)) 3*ones(1,numel(y2))];              %numel返回元素的总数  
  22. data = single(reshape(cat(3, x1, x2),128,256,1,[]));          %将x1的训练数据集和x2的测试数据集的第三个维度进行拼接组成新的数据集,并且转为single型减少内存  
  23. dataMean = mean(data(:,:,:,set == 1), 4);                   %求出训练数据集中所有的图像的均值  
  24. data = bsxfun(@minus, data, dataMean) ;                     %利用bsxfun函数将数据集中的每个元素逐个减去均值  
  25.   
  26. %将数据存入imdb结构中  
  27. imdb.images.data = data ;                                   %data的大小为[128 256 1 70000]。 (60000+10000) 这里主要看上面的data的size。  
  28. imdb.images.data_mean = dataMean;                           %dataMean的大小为[128 256]  
  29. imdb.images.labels = cat(2, y1', y2') ;                       %拼接训练数据集和测试数据集的标签,拼接后的大小为[1 70000]  
  30. imdb.images.set = set ;                                     %set的大小为[1 70000],unique(set) = [1 3]  
  31. imdb.meta.sets = {'train', 'val', 'test'} ;                 %imdb.meta.sets=1用于训练,imdb.meta.sets=2用于验证,imdb.meta.sets=3用于测试  
  32.   
  33. %arrayfun函数通过应用sprintf函数得到array中从0到9的元素并且将其数字标签转化为char文字型  
  34. imdb.meta.classes = arrayfun(@(x)sprintf('%d',x),0:9,'uniformoutput',false) ;  

注:

 

1. data = single(reshape(cat(3, x1, x2),128,256,1,[]));  这里[128,256,1]是我的数据的size。如果你是三维的数据,比如是cifar则需要将这里的1变为3。且cat的3需要变为4。
2. 针对三维数据切勿轻易使用reshape函数,尽可能的用cat函数组建,因为reshape是基于纵向来构造的。

 

下面我将为大家介绍如何构建自己的网络:

1. Conv.layer:

 

[plain] view plain copy
 
  1. net.layers{end+1} = struct('type', 'conv', ...          %卷积层C,randn函数产生4维标准正态分布矩阵,设置偏置有20个  
  2.                            'weights', {{0.05*randn(3,3,1,32, 'single'), ...  
  3.                            zeros(1, 32, 'single')}}, ...  %filter大小是3*3*1  
  4.                            'learningRate', lr, ...  
  5.                            'stride', 1, ...             %stride = 1  
  6.                            'pad', 0) ;            

 

注:
一、weights既是filter。这里的3*3为filter的大小(长和宽),1是input的图片的厚度(如果图片是rgb则这里将是3),32是此层filter的个数。
二、stride等于该filter的移动步伐。
三、当filter的size等于1*1的时候,表示为fully connection.

 

2. Rule.layer:

 

[plain] view plain copy
 
  1. net.layers{end+1} = struct('type', 'relu') ;   

3. maxPooling.layer:

 

 

[plain] view plain copy
 
  1. net.layers{end+1} = struct('type', 'pool', ...          %池化层P  
  2.                            'method', 'max', ...  
  3.                            'pool', [2 2], ...           %池化核大小为2*2  
  4.                            'stride', 2, ...  
  5.                            'pad', 0) ;  

4. dropout.layer:

 

 

[plain] view plain copy
 
  1. net.layers{end+1} = struct('type', 'dropout', 'name', 'dropout2', 'rate', 0.5) ;  
注:这里我们给的drop rate 是0.5 。

 

5. softmax.layer:

 

[plain] view plain copy
 
  1. net.layers{end+1} = struct('type', 'softmaxloss') ;     %softmax层  

 

 

下面我将说明网络构建的思路:
1. 一般来说作为最原始的lenet的网络结构,我们最好的构造是C-R-C-R-P为一个block。
2. C层之后一定要加上R层,这是构建原理之一,linear的C加上nonlinear的R,相信学过NN的或者能用的这个人都会知道吧。
3. softmax的input必须为1*1的size。为了实现这个就必须计算整体网络的构造,我的建议是画图,自己先在纸上画好自己的网络结构,计算好最后为1*1。
4. 关于图片缩小的计算公式:
一、Conv.layer: [(N-F)/stride]+1
   这里N是input的size,F是filter的size。
二、Pooling.layer: 一般说来pooling层是不用改变的,都是缩小2分之1。
5. 如果data的size过小,而希望增加C层来进行深度的网络构造,那么我们就需要用到padding。
  公式:padding size = (F-stride)/2 这里F是filter的size。这样我们的C层就不会减小图片,从而进行构造深度网络。

 

关于网络参数的设置和调整我将在后面为大家介绍。虽然说了很多但是还是不能说尽所有。

 

本文为原创文章转载必须注明本文出处以及附上 本文地址超链接  以及 博主博客地址:http://blog.csdn.NET/qq_20259459  和 作者邮箱( jinweizhi93@gmai.com )。

(如果喜欢本文,欢迎大家关注我的博客或者动手点个赞,有需要可以邮件联系我)

版权声明:本文为博主原创文章,转载必须注明是转载文章和原文超链接以及作者信息。 https://blog.csdn.net/qq_20259459/article/details/65633407

 

posted @ 2018-04-02 11:06  菜鸡一枚  阅读(775)  评论(0)    收藏  举报