学习MatConvNet,有一个很经典的例子是车牌数字字符识别。
相对于上一篇提到的利用已经训练好的模型imagenet-vgg-m-2048.mat等进行分类识别,这次我们需要利用自己的数据集对模型进行训练,然后利用图片进行测试。
这里我们用到了车牌数据集,形式如下:
1、读取图片用于训练。cnn_plate_setup_data.m
%读取相应的图片和标签,并减去均值
function imdb =cnn_plate_setup_data(datadir)
inputSize =[20,20,1];
subdir=dir(datadir);
imdb.images.data=[];
imdb.images.labels=[];
imdb.images.set = [] ;
imdb.meta.sets = {'train', 'val', 'test'} ;
image_counter=0;
trainratio=0.8;
for i=3:length(subdir)%类别路径
imgfiles=dir(fullfile(datadir,subdir(i).name));
imgpercategory_count=length(imgfiles)-2;
disp([i-2 imgpercategory_count]);
image_counter=image_counter+imgpercategory_count;
for j=3:length(imgfiles)%每个类别下的图片路径
img=imread(fullfile(datadir,subdir(i).name,imgfiles(j).name));
img=imresize(img, inputSize(1:2));
img=single(img);
[~,~,d]=size(img);
if d==3
img=rgb2gray(img);
continue;
end
imdb.images.data(:,:,:,end+1)=single(img);
imdb.images.labels(end+1)= i-2;
if j-2
2、没有预训练模型,所以,需要我们自己构建网络结构。 cnn_plate_init.m
%设计网络结构
function net =cnn_plate_init()
rng('default');%rng(‘default’)是恢复matlab启动时默认的全局随机流,至于rng函数,用来保证每次生成的随机变量是一致的。
rng(0) ;
%这里设计的结构是conv1->pool1->relu->conv2->pool2->relu->conv3->softmax
f=1/100 ;
net.layers = {};
net.layers{end+1} = struct('type', 'conv', ...
'weights', {{f*randn(3,3,1,20, 'single'), zeros(1, 20, 'single')}}, ...
'stride', 1, ...
'pad', 0) ;%其中conv1的参数设置为20个3*3大小的卷积核,偏置为20个0,步长为1,没有补零,后面的层可以一一分析。
net.layers{end+1} = struct('type', 'pool', ...
'method', 'max', ...
'pool', [2 2], ...
'stride', 2, ...
'pad', 0) ;
net.layers{end+1} = struct('type', 'relu') ;
net.layers{end+1} = struct('type', 'conv', ...
'weights', {{f*randn(3,3,20,100, 'single'),zeros(1,100,'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', 'relu') ;
net.layers{end+1} = struct('type', 'conv', ...
'weights', {{f*randn(3,3,100,1000, 'single'),zeros(1,1000,'single')}}, ...
'stride', 1, ...
'pad', 0) ;
net.layers{end+1} = struct('type', 'softmaxloss') ;
% Meta parameters
net.meta.inputSize = [20 20 1] ;
net.meta.trainOpts.learningRate = logspace(-3, -5, 100);
net.meta.trainOpts.numEpochs = 50 ;
net.meta.trainOpts.batchSize = 1000 ;
% Fill in default values
net = vl_simplenn_tidy(net) ;
end
3、把网络结果串联起来进行训练,得到学习到的模型net。
%把网络结果串联起来进行训练
function [net, info] = cnn_plate()
run(fullfile(fileparts(mfilename('fullpath')),'..\matlab', 'vl_setupnn.m')) ;
datadir='.\ann';
opts.expDir = fullfile(vl_rootnn, 'data', 'plate-baseline') ;
opts.imdbPath = fullfile(opts.expDir, 'imdb.mat');
if exist(opts.imdbPath,'file')
imdb=load(opts.imdbPath);
else
imdb=cnn_plate_setup_data(datadir);%读取图片 建立用于训练的数据集 并把结果保存为imdb.mat
mkdir(opts.expDir) ;
save(opts.imdbPath, '-struct', 'imdb') ;
end
net=cnn_plate_init();%%设计网络结构
net.meta.normalization.averageImage =imdb.images.data_mean ;
opts.train.gpus = [];%opts.train.gpus=[]表示cpu。有的话中括号里面填GPU编号,如果只有一块GPU,中括号里填1
[net, info] = cnn_train(net, imdb, getBatch(opts), ...%利用数据集训练模型
'expDir', opts.expDir, ...
net.meta.trainOpts, ...
opts.train, ...
'val', find(imdb.images.set == 3)) ;%测试集
function fn = getBatch(opts)
% --------------------------------------------------------------------
fn = @(x,y) getSimpleNNBatch(x,y) ;
end
function [images, labels] = getSimpleNNBatch(imdb, batch)
images = imdb.images.data(:,:,:,batch) ;
labels = imdb.images.labels(1,batch) ;
if opts.train.gpus > 0
images = gpuArray(images) ;
end
end
end
同时,例子中还绘制了学习过程中训练集和测试集的error情况:
随着迭代次数的增加,模型对训练集和验证集的识别效果都越来越好。
4、用第47个文件夹里的第一张图片做测试,利用学习到的模型识别这个图片中的字符是什么
addpath('../');
run(fullfile(fileparts(fileparts(mfilename('fullpath'))),...
'matlab', 'vl_setupnn.m')) ;
addpath ../data/plate-baseline;
%datadir='E:\MachineLearning\caffe\caffe-windows-master\platerecognition\data\platerecognition\chars2';
datadir='.\ann';
class=47;%%test
index=1;%%test 这里用第47个文件夹里的第一张图片做测试,利用模型识别这个图片中的字符是什么
subdir=dir(datadir);
imgfiles=dir(fullfile(datadir,subdir(class+2).name));
fprintf('这个车牌上的数字(字符)是:%s\n',subdir(class+2).name);
img=imread(fullfile(datadir,subdir(class+2).name,imgfiles(index+2).name));
imshow(img);
net=load('net-epoch-50.mat');%%取出我们的最终训练模型,这里只训练了50次
net=net.net;
im_=single(img);
im_=imresize(im_,net.meta.inputSize(1:2));
im_=im_ - net.meta.normalization.averageImage;
opts.batchNormalization = false ;
net.layers{end}.type = 'softmax';
res=vl_simplenn(net,im_);
scores=squeeze(gather(res(end).x));
[bestScore,best]=max(scores);
fprintf('利用模型识别到的这个车牌上的数字(字符)是:%s\n',subdir(best+2).name);
fprintf('score:%d\n',bestScore);
可以看出,学习到的模型的识别结果是正确的。