概述
1.MatConvNet的简介
MatConvNet是一个实现卷积神经网络(CNN)的MATLAB工具箱,用于计算机视觉应用。 它简单,高效,并且可以运行和学习最先进的CNN。 许多用于图像分类,分割,人脸识别和文本检测的预训练CNN都有提供。
2.配置过程
首先从官网下载matconvnet(点击官网首页的Download)
接着运行根目录中matlab文件夹下的vl_compilenn.m。这其实是一个编译文件,因为工具箱中有一部分代码是用cc++写的,所以要把他们编译成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'] ; end
opts.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') ;
end
net.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) ;
end
inputs = {'input', images, 'label', labels} ;
% --------------------------------------------------------------------
function imdb = getMnistImdb(opts)
% --------------------------------------------------------------------
% Preapre the imdb structure, returns image data with mean image subtracted
files = {'train-images-idx3-ubyte', ...
'train-labels-idx1-ubyte', ...
't10k-images-idx3-ubyte', ...
't10k-labels-idx1-ubyte'} ;
if ~exist(opts.dataDir, 'dir')
mkdir(opts.dataDir) ;
end
for 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 %sn', url) ;
gunzip(url, opts.dataDir) ;
end
end
f=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 MNIST
opts.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 parameters
net.meta.inputSize = [28 28 1] ;%输入图像的大小
net.meta.trainOpts.learningRate = 0.001 ;%学习率
net.meta.trainOpts.numEpochs = 20 ;%迭代次数
net.meta.trainOpts.batchSize = 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'));
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 layer
net.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识别,源码下载。
最后
以上就是义气星月为你收集整理的MatConvNet的简单介绍和手写识别运用的全部内容,希望文章能够帮你解决MatConvNet的简单介绍和手写识别运用所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复