matconvnet是matlab上进行CNN的框架。本文介绍windows下如何安装以及使用它对pre-trained的网络进行finetuning. 这里以win10为例,cuda版本为7.5,cudnn的版本为v3.fine tune的网络VGG-19.
一.matconvnet 安装
1.Precondition: 如果是编译cpu版本的,只需要matlab安装了mex就可以(c与matlab的混编 ,在matlab的commander里输入mex -setup C++搞定)。
如果是编译GPU的话,首先是需要GPU(其实所有独立显卡都可以),然后安装好cuda用于cu文件的编译;如果想使用nvidia正对CNN的加速需要下载cudnn。
2.安装
下载完自己需要的matconvnet版本之后就可以在matlab编译安装了。这里只介绍GPU的安装。
2.1编译:
以matconvnet的目录作为当前目录,添加matlab路径到查找目录,然后将cudnn文件夹复制到当前目录,整个目录结构如下:
其中finetune目录是我后面finetune用到的,这里主要注意把cudnn(图中是cuda)复制到当前目录。
然后既可以按照官网的命令进行编译:
gpuDevice()可以查看你的显卡信息,同时可以看cuda toolkit的版本。
vl_compilenn('enableGpu',true,'cudaMethod','nvcc','cudaRoot','C:\ProgramFiles\NVIDIA GPU Computing Toolkit\CUDA\v7.5','enableCudnn',true,'cudnnRoot','cuda')
这里需要把cudaRoot后面的路径换做你自己安装的cuda 路径,cudnnRoot后的路径换为你cudnn的路径。同时不用cudnn的话将后面两项去掉即可。如果在编译cudnn版本的时候提示找不到cudnn.h文件,那多数是路径不对,此时一个有效的办法是将cudnn里面的子目录的文件copy到cuda安装路径(上条命令中的cudaRoot参数)下的对应目录下。
下面就可以进行测试了:
vl_testnn(‘gpu’,true)
这里有个问题就是编译的时候可能会出其他错误,如果是说某个函数的参数不对(too few arguments)这种错误,很有可能是版本问题引起的,建议更换了cudnn版本后重新编译。或者先不用cudnn看是否编译成功。
还遇到一个问题,类似与error using mex cc: unsupported gpu architecture ‘compute_52’,这是因为这个值只能取10倍数,在vl_compilenn里面的cudaArch函数里面将arch_code固定为你自己的GPU的计算能力即可(取最接近的10的倍数,要用字符格式),如下:
function cudaArch = get_cuda_arch(opts)
% --------------------------------------------------------------------
opts.verbose && fprintf('%s:\tCUDA: determining GPU compute capability (use the ''CudaArch'' option to override)\n', mfilename);
try
gpu_device = gpuDevice();
arch_code = strrep(gpu_device.ComputeCapability, '.', '');
arch_code = '50'%自己添加的
cudaArch = ...
sprintf('-gencode=arch=compute_%s,code=\\\"sm_%s,compute_%s\\\" ', ...
arch_code, arch_code, arch_code) ;
catch
opts.verbose && fprintf(['%s:\tCUDA: cannot determine the capabilities of the installed GPU;' ...
'falling back to default\n'], mfilename);
cudaArch = opts.defCudaArch;
end
二 fine tune CNN
如果上面的步骤训练,下面就可以用matconvnet工具包了。examples目录下面有许多很好的例子,墙裂推荐。这里以对VGG-19网络fine tune为例,也就是使用pre-trianed网络,然后用自己的数据进行fine tune,得到针对自己数据集的网络。主要步骤分为:参数设定;准备数据;准备网络;训练网络;部署网络;
run(fullfile(fileparts(mfilename('fullpath')), ...
'..', 'matlab', 'vl_setupnn.m')) ;
%------------------------------
%parameter setting
%------------------------------
%数据
opts.dataDir = 'YourDataPath' ;
opts.expDir = 'YourOutputPath';
% 导入预训练的model
opts.modelPath = fullfile('YourModelPath','imagenet-vgg-verydeep-19.mat');
opts.train = struct() ;
opts.train.gpus = [1];%使用GPU
opts.train.batchSize = 40;%每个batch的样本数
opts.train.numSubBatches = 4 ;%每个batch分成多少个subbatch
opts.contrastNormalization = true;
opts.lite = false ;
if ~isfield(opts.train, 'gpus'), opts.train.gpus = []; end;
opts = vl_argparse(opts, varargin) ;
acc_list = [];
%opts.numFetchThreads = 12 ;
modelPath = ['PATHTOSAVEMODEL'.mat'];%保存model的路径
imdbname = ['imdb.mat'];
opts.imdbPath = fullfile(opts.expDir, imdbname);%读取imdb数据的路径
%-------------------------
%prepare data
%-------------------------
if exist(opts.imdbPath,'file')
imdb = load(opts.imdbPath) ;
else
imdb = getEggImdb(opts) ;
end
%------------------------------
%prepare model
%------------------------------
%load net
net = load(opts.modelPath);
%adjust net
net.layers = net.layers(1:end-2);%去掉原来的softmax层以及fc8层
%set learning rate
lr = [0.005 0.002];%每层的网络学习率
for i = 1:size(net.layers,2)
if(strcmp(net.layers{i}.type,'conv'))
net.layers{i}.learningRate = lr;
end
end
net.layers{end+1} = struct('name','fc8_egg','type', 'conv', ...
'weights', {{0.05*randn(1,1,4096,YOURCLASSNUM, 'single'), zeros(1,YOURCLASSNUM,'single')}}, ...
'learningRate',[0.005 0.002], ...
'stride', [1 1], ...
'pad', [0 0 0 0], ...
'opts',{cell(0,0)}) ;%添加新的fc8层,'weights'后面的YOURCLASSNUM为你分类的类别数
net.layers{end+1} = struct('type','softmaxloss','opts',{cell(0,0)});%重新添加softmaxloss层用于训练
%-----------------------------------------------------------
% Learn
% ----------------------------------------------------------
opts.train.train = find(imdb.images.set==1) ;%训练集
opts.train.val = find(imdb.images.set==3) ;%测试集
[net, info] = cnn_train(net, imdb,opts.iband, @getBatch, ...
'expDir', opts.expDir, ...
opts.train);
%------------------------------------------
% deploy
%------------------------------------------
net = cnn_deploy(net);
save(modelPath, '-struct', 'net') ;
acc_list(end+1) = test_val_data(modelPath,iband);
% --------------------------------------------------------------------
function [im, labels] = getBatch(imdb, batch)
% --------------------------------------------------------------------
im = imdb.images.data(:,:,:,batch) ;
labels = imdb.images.labels(1,batch) ;
if rand > 0.5, im=fliplr(im) ; end
需要注意的是每层的learning rate也是我们可以根据效果调的地方,里面的有几个函数需要自己修改:getEggImdb是根据自己的数据集建立imdb的函数;cnn_deploy是对网络进行部署的函数,也很重要,因为fine tune后的网络不能直接用于测试。这几个文件应该在matconvnet里面都给出来了,可以照着更改,我也把自己的放到github上了。
很多细节没来得及深究,多多指点。
Reference:
[1]http://www.vlfeat.org/matconvnet/
[2]http://blog.csdn.net/on2way/article/details/52959344
[3]http://blog.csdn.net/anysky___/article/details/51356158