MatConvNet的简单介绍和手写识别运用

来源:互联网 发布:怎么搜索微博域名 编辑:程序博客网 时间:2024/05/21 17:30

1.MatConvNet的简介

MatConvNet是一个实现卷积神经网络(CNN)的MATLAB工具箱,用于计算机视觉应用。 它简单,高效,并且可以运行和学习最先进的CNN。 许多用于图像分类,分割,人脸识别和文本检测的预训练CNN都有提供。

2.配置过程

首先从官网下载matconvnet(点击官网首页的Download)
接着运行根目录中matlab文件夹下的vl_compilenn.m。这其实是一个编译文件,因为工具箱中有一部分代码是用c\c++写的,所以要把他们编译成matlab可以执行的mex文件。
编译完成后,命令窗口会出现下列信息,如果全是successfully就可以进行下一步了。理论上不会出现什么错误的,至少我没有碰到,如果出现错误了再具体问题具体分析了。
这里写图片描述
配置过程就是这么简单,接下来我们运行它的一个例子,并给出手写识别的demo。
注:默认情况下是无GPU版本的,如果需要GPU则需要修改vl_compilenn.m相应的参数。

3.运行minist数据集

在examples目录下有个minist文件,这是一个著名的手写识别项目,也比较基础,正好适合作为入门。
这里写图片描述
直接运行里面的cnn_minist_experiments,就开始训练数据了,接下来就看到命令行里面显示出了当前迭代训练的结果,看起来很带感。运行完成后会有一张图片展现训练结果:
这里写图片描述
我们尝试简单分析下里面的文件怎么写的, 方便我们以后训练自己的数据集:
首先先看下,cnn_mnist_experiments.m

[net_bn, info_bn] = cnn_mnist(...  'expDir', 'data/mnist-bnorm', 'batchNormalization', true);[net_fc, info_fc] = cnn_mnist(...  '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 ;

我们可以看到其实这个函数就是调用了两次cnn_mnist.m,并传入不同的参数进行训练,最后将结果画出。所以训练的重点是在cnn_mnist.m,我们接下来看看这个函数。

function [net, info] = cnn_mnist(varargin)%CNN_MNIST  Demonstrates MatConvNet on MNIST%% 训练参数的设置,以及建立权值存储的位置run(fullfile(fileparts(mfilename('fullpath')),...  '..', '..', 'matlab', 'vl_setupnn.m')) ;%检查是否配置成功,如果没有配置好则会弹出警告,配置完成后可以把这句话删了。opts.batchNormalization = false ;opts.network = [] ;opts.networkType = 'simplenn' ;[opts, varargin] = vl_argparse(opts, varargin) ;sfx = opts.networkType ;if opts.batchNormalization, sfx = [sfx '-bnorm'] ; endopts.expDir = fullfile(vl_rootnn, 'data', ['mnist-baseline-' sfx]) ;[opts, varargin] = vl_argparse(opts, varargin) ;opts.dataDir = fullfile(vl_rootnn, 'data', 'mnist') ;opts.imdbPath = fullfile(opts.expDir, 'imdb.mat');opts.train = struct() ;opts = vl_argparse(opts, varargin) ;if ~isfield(opts.train, 'gpus'), opts.train.gpus = []; end;% --------------------------------------------------------------------%                                                         Prepare data% --------------------------------------------------------------------%% 初始化神经网络if isempty(opts.network)  net = cnn_mnist_init('batchNormalization', opts.batchNormalization, ...    'networkType', opts.networkType) ;else  net = opts.network ;  opts.network = [] ;end%% 下载数据if exist(opts.imdbPath, 'file')  imdb = load(opts.imdbPath) ;else  imdb = getMnistImdb(opts) ;  mkdir(opts.expDir) ;  save(opts.imdbPath, '-struct', 'imdb') ;endnet.meta.classes.name = arrayfun(@(x)sprintf('%d',x),1:10,'UniformOutput',false) ;% --------------------------------------------------------------------%                                                                Train% --------------------------------------------------------------------switch opts.networkType  case 'simplenn', trainfn = @cnn_train ;  case 'dagnn', trainfn = @cnn_train_dag ;end%% 开始训练,并将结果保存[net, info] = trainfn(net, imdb, getBatch(opts), ...  'expDir', opts.expDir, ...  net.meta.trainOpts, ...  opts.train, ...  'val', find(imdb.images.set == 3)) ;% --------------------------------------------------------------------function fn = getBatch(opts)% --------------------------------------------------------------------switch lower(opts.networkType)  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(imdb, batch)% --------------------------------------------------------------------images = imdb.images.data(:,:,:,batch) ;labels = imdb.images.labels(1,batch) ;% --------------------------------------------------------------------function inputs = getDagNNBatch(opts, imdb, batch)% --------------------------------------------------------------------images = imdb.images.data(:,:,:,batch) ;labels = imdb.images.labels(1,batch) ;if opts.numGpus > 0  images = gpuArray(images) ;endinputs = {'input', images, 'label', labels} ;% --------------------------------------------------------------------function imdb = getMnistImdb(opts)% --------------------------------------------------------------------% Preapre the imdb structure, returns image data with mean image subtractedfiles = {'train-images-idx3-ubyte', ...         'train-labels-idx1-ubyte', ...         't10k-images-idx3-ubyte', ...         't10k-labels-idx1-ubyte'} ;if ~exist(opts.dataDir, 'dir')  mkdir(opts.dataDir) ;endfor i=1:4  if ~exist(fullfile(opts.dataDir, files{i}), 'file')    url = sprintf('http://yann.lecun.com/exdb/mnist/%s.gz',files{i}) ;    fprintf('downloading %s\n', url) ;    gunzip(url, opts.dataDir) ;  endendf=fopen(fullfile(opts.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(opts.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(opts.dataDir, 'train-labels-idx1-ubyte'),'r') ;y1=fread(f,inf,'uint8');fclose(f) ;y1=double(y1(9:end)')+1 ;f=fopen(fullfile(opts.dataDir, 't10k-labels-idx1-ubyte'),'r') ;y2=fread(f,inf,'uint8');fclose(f) ;y2=double(y2(9:end)')+1 ;set = [ones(1,numel(y1)) 3*ones(1,numel(y2))];data = single(reshape(cat(3, x1, x2),28,28,1,[]));dataMean = mean(data(:,:,:,set == 1), 4);data = bsxfun(@minus, data, dataMean) ;imdb.images.data = data ;imdb.images.data_mean = dataMean;imdb.images.labels = cat(2, y1, y2) ;imdb.images.set = set ;imdb.meta.sets = {'train', 'val', 'test'} ;imdb.meta.classes = arrayfun(@(x)sprintf('%d',x),0:9,'uniformoutput',false) ;

我们这个函数大体分成了四部分:
1.训练参数的设置,以及建立权值存储的位置
根据传入的参数确定部分网络参数,接着在minist文件夹下创建了data文件夹,存储网络训练后的权重,以及样本矩阵。
2.下载数据
判断你是否下载了minist数据集,如果没有则调用getMnistImdb这个子函数下载,并生成样本矩阵imdb(样本进行了减均值处理)。
3.初始化神经网络
初始化操作是在cnn_mnist_init中进行的,如果要修改网络参数可以对这个函数中进行修改。
4.训练神经网络
训练神经网络,并将每次迭代的权值进行保存。
接下来看看cnn_mnist_init.m函数

function net = cnn_mnist_init(varargin)% CNN_MNIST_LENET Initialize a CNN similar for MNISTopts.batchNormalization = true ;opts.networkType = 'simplenn' ;opts = vl_argparse(opts, varargin) ;rng('default');rng(0) ;%网络结构的定义f=1/100 ;net.layers = {} ;net.layers{end+1} = struct('type', 'conv', ...                           'weights', {{f*randn(5,5,1,20, 'single'), zeros(1, 20, '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,20,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(4,4,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%是否加入batchNorm层,一般在卷积层后加if opts.batchNormalization  net = insertBnorm(net, 1) ;  net = insertBnorm(net, 4) ;  net = insertBnorm(net, 7) ;end% Meta parametersnet.meta.inputSize = [28 28 1] ;%输入图像的大小net.meta.trainOpts.learningRate = 0.001 ;%学习率net.meta.trainOpts.numEpochs = 20 ;%迭代次数net.meta.trainOpts.batchSize = 100 ;%批大小,即一次梯度下降所用的样本数% Fill in defaul valuesnet = vl_simplenn_tidy(net) ;% Switch to DagNN if requestedswitch 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'));ndim = size(net.layers{l}.weights{1}, 4);layer = struct('type', 'bnorm', ...               'weights', {{ones(ndim, 1, 'single'), zeros(ndim, 1, 'single')}}, ...               'learningRate', [1 1 0.05], ...               'weightDecay', [0 0]) ;net.layers{l}.weights{2} = [] ;  % eliminate bias in previous conv layernet.layers = horzcat(net.layers(1:l), layer, net.layers(l+1:end)) ;

这个函数定义了网络的结构,初始化网络的参数。根据函数的初始化,这个网络并不完全和Lenet一样。
所以对于初学者来说,如果想用这个工具箱对自己的数据进行训练,只需要以minist这个例子为基础,然后修改由训练和测试样本生成的矩阵imdb,以及cnn_mnist_init.m中的参数,就可以简单、高效地得到结果。

4.手写识别demo

接下来,我们根据训练得到的权值,来生成一个手写识别的GUI。界面与我之前写过的KNN没有什么变化,算法由KNN变成了CNN。效果如下:
这里写图片描述
这里写图片描述
可以看到,算法具有较强的鲁棒性,体验要远远好于之前的写的KNN识别,源码下载。

0 0
原创粉丝点击