matconvnet环境下训练自己的数据集及模型测试-mnist网络结构-cifar10部分数据集

摘要

  • 网络结构:mnist的LeNet结构

  • 数据集:cifar10中的batch1和batch2

  • 准确率:测试集测试51.37%

  • 我将下载好的cifar-10数据可视化为图片后,这样就可以假装是自己的数据集了,毕竟以后任何的图片数据集我都会操作了。将batch1和batch2做成和mnist的mat数据结构一样的mat结构(其实就是依样画葫芦,mnist怎么存储的我就怎么存储的,保持所有格式一致),我用batch1的10000张图片做训练集,用batch2的10000张图片做验证集。然后修改mnist网络的数据参数(conv、pooling层的参数要自己计算),这样就训练出自己数据的模型了,然后写程序测试模型的准确率。


制作数据集

  • cifar10可视化,之前说过matlab环境下的cifar10数据可视化

  • 参照mnist的数据格式:mnist的imdb.mat文件包含一个images和一个meta

    images meta

  • data中为28*28*1*70000的数据集,其中60000为训练集,10000为验证集

  • sets中是三个标签,set = 1为训练集,set = 2为测试集,set = 3为验证集

  • class中是10个类别

  • 前面说过cifar10中共20000张图片,训练验证各一半,每张大小为32*32*3,制作数据集的时候会在第四维上进行联结,所以我们的data大小为32*32*3*20000,其它不变

制作数据集代码如下:

%将cifar10的图像构建成和mnist相似的数据体格式

% 读取一个文件夹的多幅图片,如果为单通道图片则为I(:,:,k)
imgpath1 = ('E:\2-科研\2-实验\cifar-10-batches-mat\image\data_batch_1\');

di1 = dir(fullfile(imgpath1,'*.png'));
for k= 1:length(di1)
    I(:,:,:,k) = imread([imgpath1,di1(k).name]);
end
%读一张图片验证
%I1 = imread(fullfile(imgpath,'batch_label_0_116.png'));

%将其转为double型
data1 = im2double(I);

for k= 1:length(di1)
   label1(1,k) = str2num(di1(k).name(13:13));
end
% ---------------------------------------------------------------------
imgpath2 = ('E:\2-科研\2-实验\cifar-10-batches-mat\image\data_batch_2\');
di2 = dir(fullfile(imgpath1,'*.png'));
for k= 1:length(di2)
    I2(:,:,:,k) = imread([imgpath1,di2(k).name]);
end

data2 = im2double(I2);
for k= 1:length(di2)
   label2(1,k) = str2num(di2(k).name(13:13));
end

% ----------------------------------------------------------------------------
% 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需要进行泛化处理。
% --------------------------------------------------------------------

%计算出训练数据集中所有图像的均值
%set = 1 对应训练;set = 3 对应的是测试 
set = [ones(1,numel(label1)) 3*ones(1,numel(label2))];%numel返回元素的总数 
data = single(cat(4,data1,data2)); %将x1的训练数据集和x2的测试数据集的第三个维度进行拼接组成新的数据集,并且转为single型减少内存  
dataMean = mean(data1(:,:,:,:), 4);%求出训练数据集中所有的图像的均值
dataMean = single(dataMean);
data = bsxfun(@minus, data, dataMean) ; %利用bsxfun函数将数据集中的每个元素逐个减去均值  

% ---------------------------------------------------------------------
%将数据存入imdb结构中 
mycifar_batch1_2_imdb.images.data = data ;%data的大小为[32 32 3 20000]前10000训练,后10000测试
mycifar_batch1_2_imdb.images.data_mean = dataMean; %dataMean的大小为[32 32 3]  
mycifar_batch1_2_imdb.images.labels = cat(2, label1, label2) ; %拼接训练数据集和测试数据集的标签,拼接后的大小为[1 20000]  
mycifar_batch1_2_imdb.images.set = set ; %set的大小为[1 20000],unique(set) = [1 3]
mycifar_batch1_2_imdb.meta.sets = {'train', 'val', 'test'} ;  %imdb.meta.sets=1用于训练,imdb.meta.sets=2用于验证,imdb.meta.sets=3用于测试  
%读入类别
mycifar_batch1_2_imdb.meta.class = {'airplane'    'automobile'    'bird'    'cat'    'deer'    'dog'    'frog'    'horse'    'ship'    'truck'};
%imdb.meta.classes = arrayfun(@(x)sprintf('%d',x),0:9,'uniformoutput',false) ;%arrayfun函数通过应用sprintf函数得到array中从0到9的元素并且将其数字标签转化为char文字型

训练模型

  • 三个函数说明:
    • cnn_mnist_experiments_cifar_my:主函数,主要调用下一个函数,并将结果画图显示
    • cnn_mnist_cifar_my:最主要的函数,包括各种函数及训练验证的过程
    • cnn_mnist_init_cifar_my:初始化网络结构的函数,主要是网络参数的设定
1.cnn_mnist_experiments_cifar_my
% Experiment with the mycnn_mnist_fc_bnorm

[net_bn, info_bn] = cnn_mnist_cifar_my(...
  'expDir', 'data/mnist-bnorm', 'batchNormalization', true);

[net_fc, info_fc] = cnn_mnist_cifar_my(...
  'expDir', 'data/mnist-baseline', 'batchNormalization', false);

figure(1) ; clf ;
subplot(1,2,1) ;
semilogy([info_fc.val.objective]', 'o-') ; hold all ;
semilogy([info_bn.val.objective]', '+--') ;
xlabel('Training samples [x 10^3]'); ylabel('energy') ;
grid on ;
h=legend('BSLN', 'BNORM') ;
set(h,'color','none');
title('objective') ;
subplot(1,2,2) ;
plot([info_fc.val.top1err]', 'o-') ; hold all ;
plot([info_fc.val.top5err]', '*-') ;
plot([info_bn.val.top1err]', '+--') ;
plot([info_bn.val.top5err]', 'x--') ;
h=legend('BSLN-val','BSLN-val-5','BNORM-val','BNORM-val-5') ;
grid on ;
xlabel('Training samples [x 10^3]'); ylabel('error') ;
set(h,'color','none') ;
title('error') ;
drawnow ;
2.cnn_mnist_experiments_cifar_my
function [net, info] = cnn_mnist_cifar_my(varargin) 

run('E:\2-科研\MatConvNet\matconvnet-1.0-beta25\matconvnet-1.0-beta25\matlab\vl_setupnn.m') ;

opts.batchNormalization = false ;                   %选择batchNormalization的真假  
opts.network = [] ;                                 %初始化一个网络  
opts.networkType = 'simplenn' ;                     %选择网络结构 %%% simplenn %%% dagnn  

[opts, varargin] = vl_argparse(opts, varargin) ;    %调用vl_argparse函数  

sfx = opts.networkType ;                               %sfx=simplenn  
if opts.batchNormalization, sfx = [sfx '-bnorm'] ; end %这里条件为假  
opts.expDir = fullfile(vl_rootnn,'my','1025','data',['cifar10-' sfx]) ;    %选择数据存放的路径:data\cifar-baseline-simplenn  
[opts, varargin] = vl_argparse(opts, varargin) ;      %调用vl_argparse函数  

opts.dataDir = fullfile(vl_rootnn,'my','1025','data', 'cifar10') ;   
opts.mycifar_batch1_2_imdbPath = fullfile(opts.expDir, 'mycifar_batch1_2_imdb.mat');                      %选择mycifar_batch1_2_imdb结构体的路径:data\data\cifar-baseline-simplenn\mycifar_batch1_2_imdb  
%------------------------------新增加的两句
opts.whitenData = true ;  
opts.contrastNormalization = true ;  
%------------------------------------------
opts.train = struct() ;                      %选择训练集返回为struct型  
opts = vl_argparse(opts, varargin) ;         %调用vl_argparse函数  

% --------------------------------------------------------------------
%                                                         Prepare data
% --------------------------------------------------------------------
if isempty(opts.network)                    %如果原网络为空:  
  net = cnn_mnist_init_cifar_my('batchNormalization', opts.batchNormalization, ...   %   则调用cnn_cifat_init网络结构  
    'networkType', opts.networkType) ;  
else                                        %否则:  
  net = opts.network ;                      %   使用上面选择的数值带入现有网络  
  opts.network = [] ;  
end  

if exist(opts.mycifar_batch1_2_imdbPath, 'file')%如果cifar中存在mycifar_batch1_2_imdb的结构体:  
  mycifar_batch1_2_imdb = load(opts.mycifar_batch1_2_imdbPath) ; %  载入mycifar_batch1_2_imdb  
else                                                    %否则:  
  mycifar_batch1_2_imdb = getMnistmycifar_batch1_2_imdb(opts) ; %   调用getMnistmycifar_batch1_2_imdb函数得到mycifar_batch1_2_imdb并保存  
  mkdir(opts.expDir) ;                                    
  save(opts.mycifar_batch1_2_imdbPath, '-struct', 'mycifar_batch1_2_imdb') ;  
end  

%arrayfun函数通过应用sprintf函数得到array中从110的元素并且将其数字标签转化为char文字型  
net.meta.classes.name = arrayfun(@(x)sprintf('%d',x),1:10,'UniformOutput',false) ;  

% --------------------------------------------------------------------
%                                                                Train
% --------------------------------------------------------------------
switch opts.networkType                                     %选择网络类型:  
  case 'simplenn', trainfn = @cnn_train ;                   %   1.simplenn  
  case 'dagnn', trainfn = @cnn_train_dag ;                  %   2.dagnn  
end  

%调用训练函数,开始训练:find(mycifar_batch1_2_imdb.images.set == 3)为验证集的样本  
[net, info] = trainfn(net, mycifar_batch1_2_imdb, getBatch(opts), ...          
  'expDir', opts.expDir, ...  
  net.meta.trainOpts, ...  
  opts.train, ...  
  'val', find(mycifar_batch1_2_imdb.images.set == 3)) ;  


% --------------------------------------------------------------------
function fn = getBatch(opts)
%% --------------------------------------------------------------  
%   函数名:getBatch  
%   功能:  1.由opts返回函数  
%           2.从imdb结构体取出数据  
%   相对于正常数据集,如果Batch_Size过小,训练数据就会非常难收敛,从而导致underfitting。 
%   增大Batch_Size,相对处理速度加快。 
%   增大Batch_Size,所需内存容量增加(epoch的次数需要增加以达到最好结果)。 
%   这里我们发现上面两个矛盾的问题,因为当epoch增加以后同样也会导致耗时增加从而速度下降。因此我们需要寻找最好的batch_size。
%   再次重申:batchsize 的正确选择是为了在内存效率和内存容量之间寻找最佳平衡。
%%--------------------------------------------------------------------
switch lower(opts.networkType) %根据网络类型使用不同的getBatcch  
  case 'simplenn'
    fn = @(x,y) getSimpleNNBatch(x,y) ;
  case 'dagnn'
    bopts = struct('numGpus', numel(opts.train.gpus)) ;
    fn = @(x,y) getDagNNBatch(bopts,x,y) ;
end

% --------------------------------------------------------------------
function [images, labels] = getSimpleNNBatch(mycifar_batch1_2_imdb, batch)
%% --------------------------------------------------------------  
%   函数名:getSimpleNNBatch  
%   功能:  1.由SimpleNN网络的批得到函数  
%           2.batch为样本的索引值  
% ------------------------------------------------------------------------ 
images = mycifar_batch1_2_imdb.images.data(:,:,:,batch) ;
labels = mycifar_batch1_2_imdb.images.labels(1,batch) ;

% --------------------------------------------------------------------
function inputs = getDagNNBatch(opts, mycifar_batch1_2_imdb, batch)
%% --------------------------------------------------------------------
images = mycifar_batch1_2_imdb.images.data(:,:,:,batch) ;
labels = mycifar_batch1_2_imdb.images.labels(1,batch) ;
if opts.numGpus > 0
  images = gpuArray(images) ;
end
inputs = {'input', images, 'label', labels} ;


function mycifar_batch1_2_imdb = getMnistmycifar_batch1_2_imdb(opts)  
%% --------------------------------------------------------------  
%   函数名:getMnistmycifar_batch1_2_imdb  
%   功能:  1.从mnist数据集中获取data  
%           2.将得到的数据减去mean值  
%           3.将处理后的数据存放如mycifar_batch1_2_imdb结构中  
% ------------------------------------------------------------------------  
% Preapre the mycifar_batch1_2_imdb structure, returns image data with mean image subtracted   
load('E:\2-科研\2-实验\mycifar_batch1_2_imdb.mat');
3.cnn_mnist_init_cifar_my
%cifar数据集batch1和batch2 运用mnist的网络来训练
function net = cnn_mnist_init_cifar_my(varargin)
% CNN_MNIST_LENET Initialize a CNN similar for MNIST
opts.batchNormalization = true ;
opts.networkType = 'simplenn' ;
opts = vl_argparse(opts, varargin) ;

rng('default');%设置随机数发生器,重现每次运行结果?
rng(0) ;

% 开始构建网络结构,这里是LeNet5 
f=1/100 ;
net.layers = {} ;
net.layers{end+1} = struct('type', 'conv', ...
                           'weights', {{f*randn(5,5,3,32, 'single'), zeros(1, 32, 'single')}}, ...
                           'stride', 1, ...
                           'pad', 0) ;
net.layers{end+1} = struct('type', 'pool', ...
                           'method', 'max', ...
                           'pool', [2 2], ...
                           'stride', 2, ...
                           'pad', 0) ;
net.layers{end+1} = struct('type', 'conv', ...
                           'weights', {{f*randn(5,5,32,50, 'single'),zeros(1,50,'single')}}, ...
                           'stride', 1, ...
                           'pad', 0) ;
net.layers{end+1} = struct('type', 'pool', ...
                           'method', 'max', ...
                           'pool', [2 2], ...
                           'stride', 2, ...
                           'pad', 0) ;
net.layers{end+1} = struct('type', 'conv', ...
                           'weights', {{f*randn(5,5,50,500, 'single'),  zeros(1,500,'single')}}, ...
                           'stride', 1, ...
                           'pad', 0) ;
net.layers{end+1} = struct('type', 'relu') ;
net.layers{end+1} = struct('type', 'conv', ...
                           'weights', {{f*randn(1,1,500,10, 'single'), zeros(1,10,'single')}}, ...
                           'stride', 1, ...
                           'pad', 0) ;
net.layers{end+1} = struct('type', 'softmaxloss') ;

% optionally switch to batch normalization
if opts.batchNormalization %如果opts.batchNormalization为真:
  net = insertBnorm(net, 1) ; %在原网络第一层后添加Bnorm  
  net = insertBnorm(net, 4) ; %在原网络第四层后添加Bnorm 
  net = insertBnorm(net, 7) ;%在原网络第七层后添加Bnorm  
end

% Meta parameters结构元参数
net.meta.inputSize = [32 32 3] ; %大小为28*28*1的input data  
net.meta.trainOpts.learningRate = 0.001 ; %学习率为0.001 
net.meta.trainOpts.numEpochs = 2 ;  %Epoch为20  
net.meta.trainOpts.batchSize = 100 ;%批的大小为100 

% Fill in defaul values
net = vl_simplenn_tidy(net) ;%添加默认的属性值

% Switch to DagNN if requested
switch lower(opts.networkType)
  case 'simplenn'
    % done
  case 'dagnn'
    net = dagnn.DagNN.fromSimpleNN(net, 'canonicalNames', true) ;
    net.addLayer('top1err', dagnn.Loss('loss', 'classerror'), ...
      {'prediction', 'label'}, 'error') ;
    net.addLayer('top5err', dagnn.Loss('loss', 'topkerror', ...
      'opts', {'topk', 5}), {'prediction', 'label'}, 'top5err') ;
  otherwise
    assert(false) ;
end

% --------------------------------------------------------------------
function net = insertBnorm(net, l)
% --------------------------------------------------------------------

assert(isfield(net.layers{l}, 'weights')); %断言以确保第l层有权重项 
ndim = size(net.layers{l}.weights{1}, 4); %第l层的神经元的个数(卷积核个数)  
layer = struct('type', 'bnorm', ...
               'weights', {{ones(ndim, 1, 'single'), zeros(ndim, 1, 'single')}}, ...
               'learningRate', [1 1 0.05], ...
               'weightDecay', [0 0]) ;%Bnorm层的权值=上一层的神经元个数  
net.layers{l}.weights{2} = [] ;  % eliminate bias in previous conv layer
net.layers = horzcat(net.layers(1:l), layer, net.layers(l+1:end)) ;
4.测试模型的准确率
  • 这里用的是验证集的图片,accurcy = 51.37%
%% 测试所有图片
run('E:\2-科研\MatConvNet\matconvnet-1.0-beta25\matconvnet-1.0-beta25\matlab\vl_setupnn.m') ;
load('E:\2-科研\MatConvNet\matconvnet-1.0-beta25\matconvnet-1.0-beta25\my\1025\data\mnist-bnorm1\net-epoch-20.mat') ;
mycifar_batch1_2_imdb = load('E:\2-科研\MatConvNet\matconvnet-1.0-beta25\matconvnet-1.0-beta25\my\1025\data\mnist-bnorm\mycifar_batch1_2_imdb.mat');

test_index = find(mycifar_batch1_2_imdb.images.set==3);
test_data = mycifar_batch1_2_imdb.images.data(:,:,:,test_index);
test_label =mycifar_batch1_2_imdb.images.labels(test_index);

net = vl_simplenn_tidy(net) ;
net.layers{1,end}.type = 'softmax';

for i = 1:length(test_label)
    i
    im_ = test_data(:,:,:,i);
    im_ = im_ - mycifar_batch1_2_imdb.images.data_mean;
    res = vl_simplenn(net, im_,[], [], ...
                      'accumulate', 0, ...
                      'mode', 'test', ...
                      'backPropDepth', Inf, ...
                      'sync', 0, ...
                      'cudnn', 1);
    scores = squeeze(gather(res(end).x)) ;
    [bestScore, best] = max(scores) ;
    pre(i) = best;
end

% 计算准确率
accurcy = length(find(pre==test_label))/length(test_label);
disp(['accurcy = ',num2str(accurcy*100),'%']);

致谢

在这一整个网络的折腾中其实参考了很多的博客,但尤其是这两个博客的帮助最大:
深度学习12:能力提升, 一步一步的介绍如何自己构建网络和训练,利用MatConvNet
MatConvNet框架下mnist数据集测试

想说

  • 这个系列折腾了两天多,终于出成果了,虽说最后结果是51%但十分类的问题如果盲猜的准确率才10%,作为第一个自己训练的网络已经很满足很开心了!接下去会再继续努力的。

  • 接下去想探究三个问题:1.数据集的图片不是正方形该如何处理,在哪块进行改动;2.在数据集没有那么大的情况下是否能支持;3.探究其它网络结构

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值