文章目录

  • MatConvNet简介
  • MatConvNet初学
  • 用MatConvNet来训练自己定义的网络
    • 准备数据集
    • 初始化网络的训练信息
    • 定义自己的网络结构
    • 网络权值初始化
    • 设置每一个batch的数据
    • 网络训练与测试
  • 使用AutoNN简化训练过程
  • 最后的最后
  • 参考文献

MatConvNet简介

根据MatConvNet的官网介绍,MatConvNet是一个基于适用在Matlab的卷积神经网络(CNN)的工具包,支持CPU和GPU。 事实上,这个工具包并不仅仅支持CNN,同时也支持一些其它的一些网络如RNN, LSTM等。 这个工具包包含了一些深度学习的基本操作如卷积,隔空卷积,池化,非线性激活函数等。

MatConvNet里面有两个非常重要的部件,一个是SimpleNN 另外一个是 DagNN

SimpleNN是一个简单的DNN的版本,主要适合一些简单的串行结构的也就是说一个卷积后面加上非线性激活最后pooling等。

DagNN可以实现更加复杂的网络结构,如实现两个层之间的skipping等等。 因为现在深度学习很多时候是改结构的,所以后面和 DagNN打交道会比较多。

MatConvNet也同时为我们提供了一些已经训练好的模型,比如说 AlexNet, GoogleNetVGG等等。大家可以通过 vlfeat的官网下载模型。 另外,MatConvNet 在Github上也有自己的开源主页,同时也集成可一些优秀的第三方的代码,比如说 autonn, mcnRFCN, mcnSSD等。值得推荐的是autonn, 它对MatConvNet进行了更加高级的封装,可以让大家以更加简洁的代码来实现自己的网络,具体的文档可以参照autonn 的 Tutorial。

MatConvNet初学

好了,简单地知道了MatConvNet之后,我们先开始着手玩玩一下MatConvNet。 首先我们到官网下载已经训练好的AlexNet模型。然后在Matlab中通过net=dagnn.DagNN.loadobj('imagenet-matconvnet-alex.mat') 导入这个模型。

首先我们在Matlab中输入net.layers 查看这个网络的每一层所包含的信息。得到输出结果如下:

name
inputs
outputs
params
inputIndexes
outputIndexes
paramIndexes
forwardTime
backwardTime
block

这里解释一下各个关键的几个名词的含义: name: 即网络的每一层起的名字,比如说第一层的卷积层(conv1)。 inputs 当前层的输入,对于第一层的话就是我们的数据集,对于后面的层来说是当前层的前一层。 outputs 当前层的输出,也即是下一个层的输入。 params 代表的是需要确定的参数的列表,比如说对于卷积层它的参数就是卷积核的参数如果有bias 还有bias的信息。对于relu由于没有参数,所以参数为空。 paramIndexes 训练的参数的index比如说对于卷积层的话就是卷积核的参数和一些bias的参数。

同时也可以通过输入net.vars查看各个层的变量信息。net.params查看需要确定的变量信息。可以通过net.print()查看整个网络的信息。比如说对于AlexNet它的输出如下:

   func|        conv1|relu1|  pool1|        conv2|relu2|  pool2|        conv3|relu3|        conv4|relu4|        conv5|relu5|  pool5|      fc6|relu6|      fc7|relu7|       fc8|
-------|-------------|-----|-------|-------------|-----|-------|-------------|-----|-------------|-----|-------------|-----|-------|---------|-----|---------|-----|----------|type|         Conv| ReLU|Pooling|         Conv| ReLU|Pooling|         Conv| ReLU|         Conv| ReLU|         Conv| ReLU|Pooling|     Conv| ReLU|     Conv| ReLU|      Conv|inputs|        input|   x1|     x3|           x4|   x5|     x7|           x8|   x9|          x11|  x12|          x14|  x15|    x17|      x18|  x19|      x21|  x22|       x24|
outputs|           x1|   x3|     x4|           x5|   x7|     x8|           x9|  x11|          x12|  x14|          x15|  x17|    x18|      x19|  x21|      x22|  x24|prediction|params|conv1f conv1b|     |       |conv2f conv2b|     |       |conv3f conv3b|     |conv4f conv4b|     |conv5f conv5b|     |       |fc6f fc6b|     |fc7f fc7b|     | fc8f fc8b|pad|            0|  n/a|      0|            2|  n/a|      0|            1|  n/a|            1|  n/a|            1|  n/a|      0|        0|  n/a|        0|  n/a|         0|stride|            4|  n/a|      2|            1|  n/a|      2|            1|  n/a|            1|  n/a|            1|  n/a|      2|        1|  n/a|        1|  n/a|         1|func|      prob|
-------|----------|type|   SoftMax|inputs|prediction|
outputs|      prob|params|          |pad|       n/a|stride|       n/a|params|233MB|vars|   0B|total|233MB|

说了这么多了,我们可以输入一张图像来测试一下我们的网络。主要过程如下:

  1. 读入图像。 我们就读入我们图像处理的peppers的图像,并且转换为single。im = single(imread('peppers.png'));
  2. 然后对读入的图像进行resize:im_ = imresize(im_,net.meta.normalization.imageSize(1:2));
  3. 接着减去训练集合的average image :im_ = bsxfun(@minus, im_, net.meta.normalization.averageImage) ;
  4. 接着用我们的网络对当前的输入进行评估:net.eval({'input',im_}); 这里的input和我们在第一层定义的输入变量要一一对应。
  5. 输出得到的概率数值scores = net.vars(net.getVarIndex('prob')).value ;scores = squeeze(gather(scores)) ; 同样,这里的prob也要和我们在最后一层定义的变量名称一致。
  6. 得到得分最大的类别及其对应的标记信息。[bestScore, best] = max(scores) ; figure(1) ; clf ; imagesc(im) ; title(sprintf('%s (%d), score %.3f',... net.meta.classes.description{best}, best, bestScore)) ;

至此我们就完成了一个数据的测试过程。

用MatConvNet来训练自己定义的网络

下面我们将以Mnist数据为例,来看看用MatConvNet训练自己的网络过程。

准备数据集

首先我们从祖师爷的官网上下载MNIST数据集,主要有以下四个

train-images-idx3-ubyte.gz:训练集
train-labels-idx1-ubyte.gz:训练集标签
t10k-images-idx3-ubyte.gz:测试集
t10k-labels-idx1-ubyte.gz:测试集标签

然后通过下面的代码来构造我们的数据集:

f=fopen(fullfile(dataDir,'train-images-idx3-ubyte'),'r');
x1=fread(f,inf,'uint8');
fclose(f);
x1=permute(reshape(x1(17:end),28,28,60e3),[2 1 3]);f=fopen(fullfile(dataDir,'t10k-images-idx3-ubyte'),'r');
x2=fread(f,inf,'uint8');
fclose(f);
x2=permute(reshape(x2(17:end),28,28,10e3),[2 1 3]);f=fopen(fullfile(dataDir, 'train-labels-idx1-ubyte'),'r') ;                                                  % Open training labels file for reading
y1=fread(f,inf,'uint8');                                                                                    % Read file and store
fclose(f) ;                                                                                                 % Close training labels
y1=double(y1(9:end)')+1 ;                                                                                   % Format and storef=fopen(fullfile(dataDir, 't10k-labels-idx1-ubyte'),'r') ;                                                   % Open testing labels for reading
y2=fread(f,inf,'uint8');                                                                                    % Read file and store
fclose(f) ;                                                                                                 % Close testing labels
y2=double(y2(9:end)')+1 ; set = [ones(1,numel(y1)) 3*ones(1,numel(y2))];                                                              % Assign sets to the data (Training, Validation, Testing)
data = single(reshape(cat(3, x1, x2),28,28,1,[]));                                                          % Convert to single precision and reshape
dataMean = mean(data(:,:,:,set == 1), 4);                                                                   % Zero Mean
data = bsxfun(@minus, data, dataMean) ;                                                                     % Finalize Zero Meanimdb.images.data = data ;                                                                                   % Assign IMDB images data
imdb.images.data_mean = dataMean;                                                                           % Assign IMDB data mean
imdb.images.labels = double(cat(2, y1, y2)) ;                                                               % Assign IMDB labels
imdb.images.set = set ;                                                                                     % Assign IMDB Set
imdb.meta.sets = {'train', 'val', 'test'} ;                                                                 % meta = miscellaneous, in this case set names
imdb.meta.classes = arrayfun(@(x)sprintf('%d',x),0:9,'uniformoutput',false) ;
fprintf('\n***** IMBD.mat has been created! *****\n');
save('imdb.mat', 'imdb', '-v7.3');

这里主要需要处理的有1. 计算图像的均值,并且对训练集进行归一化。 2.把数据集分成训练集,测试集和验证集三部分。3.对数据的类别标签进行统计

初始化网络的训练信息

有了我们自己的数据集之后,我们需要定义我们自己的网络结构信息主要是每一层的功能,输入输出和参数信息。同时我们也需要对优化的算法进行初始化比如说 batchsizeepochlearning rate 是否用GPU等等。

%--------------------------------------------------------------
% Initialize Parameters
%--------------------------------------------------------------opts.train.batchSize = 80;                                                  % 设置网络的batchsize:主要指明了每个随机梯度下降(SGD)的样本大小。
opts.train.numEpochs = 15 ;                                                 % % 每一个Epochs表示所有数据访问。 这里的意思是所有数据被迭代15次之后,输出网络的权重。 其实这个就可以理解为做矩阵分解收敛所需要迭代的次数。
opts.train.continue = true ;                                                % 这里主要是为了出现突然间断电等情况下,网络接着上一轮的训练继续完成。
opts.train.gpus = [1] ;                                                     % 设置是否使用GPU 1 表示使用,[]表示不用
opts.train.learningRate = 1e-3;                                             %
设置学习率,也可以对不同的Epochs设置不同的learning rate。比如说后面的Epochs的学习权值可以设置小一些。opts.train.learningRate =[0.001*ones(1,100), 0.1 *ones(1,200)];
opts.train.expDir = 'epoch_data';                                           % Directory for storing epoch files, will create if not already made
opts.train.numSubBatches = 1;                                               % Keep at 1% opts.train.weightDecay  = 3e-4;
% Weight decay value, usually set small. Default is present in cnn_train_dag.m
% opts.train.momentum = 0.9;                                                % Incorporate this, once convergence is reached, Default is present in cnn_train_dag.mbopts.useGpu = numel(opts.train.gpus) >  0 ;                                % Usually keep at 0, seems to only work with 3D data.
load('imdb.mat');                                                           % 加载我们之前所构造的数据信息。

定义自己的网络结构

有了网络的一些训练信息之后,我们就要进入重点了。这个也是很多论文的重点,毕竟有些人黑深度学习是改结构,改Loss,网络拼接嘛。

首先我们声明一个网络:

net=dagnn.DagNN();

然后初始化每一层的网络结构信息,它的基本单元包括: 卷积层(Convolution layer), 反卷积层(Convolution transpose layer), 归一化层(Normalization layer), 激活函数(Activation functions), 池化层( Pooling layer),全连接层(Fully connected layer),损失函数, ROI pooling等。

下面是我自己定义的网络结构信息:

net.addLayer('conv1', dagnn.Conv('size', [5 5 1 32], 'hasBias', true, 'stride', [1, 1], 'pad', [0 0 0 0]), {'input'}, {'conv1'},  {'conv1f'  'conv1b'});
% 一个卷积层,名字为conv1, 总共包括32个神经元每一个神经元的depth是1,大小为5X5.有bias,两个卷积之间的间隔为1X1,边缘部分补0, 输入的变量名字为input,输出的变量名字为conv1,输出的参数为conv1f:卷积核的信息, conv1b 卷积的bias信息。
net.addLayer('relu1', dagnn.ReLU(), {'conv1'}, {'relu1'}, {});
% 一个非线性激活函数Relu,只需要定义输入和输出即可
net.addLayer('pool1', dagnn.Pooling('method', 'max', 'poolSize', [2, 2], 'stride', [2 2], 'pad', [0 0 0 0]), {'relu1'}, {'pool1'}, {});
% 一个池化层。主要定义了池化的方法maxpooling, 每2x2个cell进行一次池化。 池化间隔为2x2. 边缘的填充为0. 接着就是输入和输出的变量信息。
% Block #2
net.addLayer('conv2', dagnn.Conv('size', [5 5 32 32], 'hasBias', true, 'stride', [1, 1], 'pad', [0 0 0 0]), {'pool1'}, {'conv2'},  {'conv2f'  'conv2b'});
net.addLayer('relu2', dagnn.ReLU(), {'conv2'}, {'relu2'}, {});
net.addLayer('pool2', dagnn.Pooling('method', 'max', 'poolSize', [2, 2], 'stride', [2 2], 'pad', [0 0 0 0]), {'relu2'}, {'pool2'}, {});% Block #3
net.addLayer('conv3', dagnn.Conv('size', [4 4 32 64], 'hasBias', true, 'stride', [1, 1], 'pad', [0 0 0 0]), {'pool2'}, {'conv3'},  {'conv3f'  'conv3b'}); %Fully Connected Layer
net.addLayer('fc1', dagnn.Conv('size', [1 1 64 256], 'hasBias', true, 'stride', [1, 1], 'pad', [0 0 0 0]), {'conv3'}, {'fc1'},  {'conv5f'  'conv5b'});
%一个全连接层。采用的是1x1的卷积实现
net.addLayer('relu5', dagnn.ReLU(), {'fc1'}, {'relu5'}, {});net.addLayer('classifier', dagnn.Conv('size', [1 1 256 10], 'hasBias', true, 'stride', [1, 1], 'pad', [0 0 0 0]), {'relu5'}, {'classifier'},  {'conv6f'  'conv6b'});
net.addLayer('prediction', dagnn.SoftMax(), {'classifier'}, {'prediction'}, {});% 将前面层得到的信息进行归一化转化为分类目标的概率信息。net.addLayer('objective', dagnn.Loss('loss', 'log'), {'prediction', 'label'}, {'objective'}, {});                           % 定义训练损失函数为cross entropy
net.addLayer('error', dagnn.Loss('loss', 'classerror'), {'prediction','label'}, 'error') ; % 定义在验证集上的误差函数

网络权值初始化

有了网络结构,我们需要对网络中的参数进行初始化,主要是对网络的learningRate, weightDecay 和卷积的参数进行初始化。主要代码如下:

function initNet(net, f)                                                                                                    net.initParams();                                                                                                                                                                                                                % Initalize local weight decayfor l=1:length(net.layers)                                                                                          if(strcmp(class(net.layers(l).block), 'dagnn.Conv'))                                                        f_ind = net.layers(l).paramIndexes(1);    % 得到第一层卷积层的卷积核参数                                                          b_ind = net.layers(l).paramIndexes(2);% 得到第一层bias的参数        % 初始化参数为一个高斯分布。net.params(f_ind).value = f*randn(size(net.params(f_ind).value), 'single');                                    net.params(f_ind).learningRate = 1;    %设置预防overfitting的正则化参数                                                                 net.params(f_ind).weightDecay = 1;                                                                  net.params(b_ind).value = f*randn(size(net.params(b_ind).value), 'single');                                  net.params(b_ind).learningRate = 0.5;  net.params(b_ind).weightDecay = 1;endend
end

设置每一个batch的数据

这个步骤的目的是设置每一个batch的数据和相应的label信息。主要代码如下:

function inputs = getBatch(opts, imdb, batch)                                                                               % This fucntion is what generates new mini batchimages = imdb.images.data(:,:,:,batch) ;                                                                                % Generates specified number of images labels = imdb.images.labels(1,batch) ;                                                                                  % Gets the associated labelsif opts.useGpu > 0images = gpuArray(images) ;endinputs = {'input', images, 'label', labels} ;                                                                           % Assigns images and label to inputs
end

网络训练与测试

调用MatConvNet的cnn_train_dag 函数进行网络训练。 主要需要传入的参数有:网络结构信息,数据信息,每一个batch的信息, 训练参数信息,验证集信息。最后通过saveobj对训练好的网络进行保存。

info = cnn_train_dag(net, imdb, @(i,b) getBatch(bopts,i,b), opts.train, 'val', find(imdb.images.set == 3)) ;                % MatConvNet DagNN Training FunctionmyCNN = net.saveobj();                                                                                                      % Save the DagNN trained CNN
save('myCNNdag.mat', '-struct', 'myCNN')  

至此我们就完成了一个网络的训练过程。我们可以通过上面的AlexNet的测试步骤对输入的数据进行测试。

使用AutoNN简化训练过程

从前面的过程我们发现,训练一个自己的网络太麻烦了,要自己addLayer传太多的参数了。有人开始对MatConvNet进行封装,即AutoNN。 在AutoNN中,MatConvNet中一些基本的函数被重新定义,我们不需要指定各个层的名字和层的输入和输出,而且自动给网络的参数进行初始化(当然你也可以用Param原语对网络进行初始化)。另外,AutoNN也实现了一些经典网络ResNet等的架构。使用AutoNN,上面的网络训练代码可以改为:

 images = Input('images') ;
labels = Input('labels') ;f=1/100;
%block one
x=vl_nnconv(images,'size',[5,5,1,32],'weightScale',f);
x=vl_nnrelu(x);
x=vl_nnpool(x,2,'method','max','stride',2);
%block 2
x=vl_nnpool(vl_nnrelu(vl_nnconv(x,'size',[5 5 32 32],'weightScale',f)),2,'method','max','stride',2);%block 3
x=(vl_nnconv(x,'size',[4 4 32 64],'weightScale',f));% convx=vl_nnrelu(vl_nnconv(x,'size',[1 1 64, 256],'weightScale',f));% fc+relux=vl_nnconv(x,'size',[1 1 256 10]);
output=vl_nnsoftmax(x);objective = vl_nnloss(output, labels, 'loss', 'log') ;
error = vl_nnloss(output, labels, 'loss', 'classerror') ;
Layer.workspaceNames() ;net = Net(objective, error) ;
info = cnn_train_autonn(net, imdb, @(i,b) getBatch(bopts,i,b), opts.train, 'val', find(imdb.images.set == 3)) ;                % MatConvNet DagNN Training Function
myCNN = net.saveobj();

是不是感觉代码简洁了好多了。

最后的最后

虽然MatConvNet 提供了一个用Matlab训练deep learning的方法,但是建议还是用Python的一些库如Pytorch来进行训练,因为这些网络的开源社区的人更多,出了问题也更容易查到解决方案。

参考文献

  1. http://www.vlfeat.org/matconvnet/
  2. http://shanmo.github.io/2016/05/MatConvNet3
  3. http://www.robots.ox.ac.uk/~vgg/practicals/cnn/index.html
  4. https://www.youtube.com/watch?v=gsKCFHkQ-Ik

MatConvNet训练自己的网络相关推荐

  1. Matconvnet 构建自己的网络

    前一篇文章中,我们使用已经训练好的模型,通过修改最后一层,训练最后一层实现图片分类,这种做法的好处是可以节省大量的时间,同时一会弥补数据量的不足.但是,有时候我们需要构建自己的网络来达到我们的目标,本 ...

  2. 一块GPU就能训练语义分割网络,百度PaddlePaddle是如何优化的?

    [引言]显存不足是训练语义分割网络常常遇见的问题,而显存是GPU计算中的稀缺资源.百度深度学习框架PaddlePaddle中的显存优化,不仅可以让研究人员在相同成本的计算设备上训练更大的模型,还可以在 ...

  3. Caffe实践】如何利用Caffe训练ImageNet分类网络

    Caffe实践]如何利用Caffe训练ImageNet分类网络 源文章:https://github.com/BVLC/caffe/tree/master/examples/imagenet 由于要使 ...

  4. python torch exp_Python:PyTorch 保存和加载训练过的网络 (八十)

    保存和加载模型 在这个 notebook 中,我将为你展示如何使用 Pytorch 来保存和加载模型.这个步骤十分重要,因为你一定希望能够加载预先训练好的模型来进行预测,或是根据新数据继续训练. %m ...

  5. py之textgenrnn:Python利用textgenrnn库实现训练文本生成网络

    py之textgenrnn:Python利用textgenrnn库实现训练文本生成网络 目录 输出结果 实现代码 输出结果 实现代码 #textgenrnn:利用textgenrnn实现训练文本生成网 ...

  6. FSRNet:端到端深度可训练人脸超分辨网络

    作者丨左育莘 学校丨西安电子科技大学 研究方向丨计算机视觉 这篇文章 FSRNet: End-to-End Learning Face Super-Resolution with Facial Pri ...

  7. 图卷积 节点分类_在节点分类任务上训练图卷积网络

    图卷积 节点分类 This article goes through the implementation of Graph Convolution Networks (GCN) using Spek ...

  8. 模拟数据集上训练神经网络,网络解决二分类问题练习

    #2018-06-24 395218 June Sunday the 25 week, the 175 day SZ ''' 模拟数据集上训练神经网络,网络解决二分类问题.'''import tens ...

  9. pytorch:如何从头开始训练一个CNN网络?

    文章目录 前言 一.CNN? 二.用单批量测试模型 1.引入库 2.读入数据集 3. 建造Module实例 4. 训练 总结 前言 在刚开始学习Deep Learning时,一件几乎不可能的事情就是知 ...

  10. TensorFlow2使用预训练的卷积网络(ConvNet)进行迁移学习

    本案例使用预训练的模型对猫狗数据集进行分类任务.使用预训练的模型有两种方式: 一是利用特征提取器.利用预训练模型的前几层对新数据进行特征提取,最后加入分类的层即可完成新模型的创建. 二是Fine Tu ...

最新文章

  1. 一起学设计模式 - 代理模式
  2. 手把手带你复现AI+区块链写码全过程!(附代码视频)
  3. 宝马计算机考试答案,宝马BMW旅程电脑功能键的说明与测试程序
  4. codeforces1271 D. Portals(dp or 带悔贪心)
  5. @IT老司机 6月3日,扫除技术与产品选型难题,CSDN选型智囊团来了!
  6. pic单片机汇编 c语言,PIC单片机汇编语言指令详解
  7. 抢购秒杀处理方案、分析热点数据
  8. 如何在 CentOS 7 上使用 RoundCube 管理邮箱
  9. openpyxl,重写Worksheet
  10. 滴滴新出的移动端UI组件库 Mand Mobile,提前蹭个热度
  11. 旷视科技面试——算法岗
  12. Web过滤器:Filter
  13. 统计之 - 离均差平方和
  14. python向量点乘_Python线性代数学习笔记——向量的点乘与几何意义,实现向量的点乘操作...
  15. 时间片(time-slicing)轮循调度(round-robin scheduling)
  16. JavaScript中的arguments,callee,caller,call,appy
  17. Document is missing mandatory uniqueKey field: id
  18. 拼多多成于“性价比”,困于“性价比”
  19. how2heap glibc 2.27
  20. Linux 挂载(NFS)

热门文章

  1. 编程输出字符图形C语言,字符图形的输出在C语言中的实现
  2. VB里怎样使用GetWindowRect、GetClientRect、ScreenToClient、ClientToScreen
  3. [Android 9.0][RK3399/RK3328] Settings->Factory Reset:点击恢复出场设置崩溃的问题
  4. 拼音输入法技巧-智能ABC
  5. [Ubuntu] 安装百度网盘客户端
  6. 支持所有浏览器的右键菜单
  7. OpenGL二十面体及多次细分成球体
  8. 分享 Android 识音识别 挺有想法的。
  9. 如何更改PDF文件中的字体?
  10. iphone11 android,iphone11launcher