主页:http://www.vlfeat.org/matconvnet/
教程:http://www.robots.ox.ac.uk/~vgg/practicals/cnn/index.html
注意:需要下载新版的MatConvNet替换掉教程中工具包中的matconvnet:http://www.vlfeat.org/matconvnet/download/matconvnet-1.0-beta12.tar.gz
本文程序和excise3效果一致,但使用了MatConvNet的examples中类似的网络结构进行定义,可以使用cnn_train函数进行训练。
内容:
- 演示了自定义网络层、自定义误差函数的方法
- 演示了自定义errorFunction的方法
- 演示了对于不同参数分别设置learning rate和weight decay 的方法
不多说,上代码,注释很详细:
function LC_Ex3_usingNetStructure clc % ------------------------------------------------------------------------- % Part 3: Learning a simple CNN 改为了使用网络定义 % ------------------------------------------------------------------------- % 改写http://www.robots.ox.ac.uk/~vgg/practicals/cnn/index.htm 的 exercise 3为一个网络 % 注意:MatConvNet工具包已经替换为新版:http://www.vlfeat.org/matconvnet/download/matconvnet-1.0-beta12.tar.gz setup ; %% doSmooth=false; subMean=false; doSmooth=true; subMean=true; wSize=9; % ------------------------------------------------------------------------- % Part 3.1: Load an example image and generate its labels % ------------------------------------------------------------------------- %% % Load an image im = rgb2gray(im2single(imread('data/dots.jpg'))) ; % Compute the location of black blobs in the image [pos,neg] = extractBlackBlobs(im) ; %% % ------------------------------------------------------------------------- % Part 3.2: Image preprocessing % ------------------------------------------------------------------------- % Pre-smooth the image if(doSmooth) im = vl_imsmooth(im,3) ; end %% % Subtract median value if(subMean) im = im - median(im(:)) ; end %% Create pixel-level labels to compute the loss y = zeros(size(pos),'single') ; y(pos) = +1 ; y(neg) = -1 ; %% 转换为imdb格式 imdb.images.data = {im} ; imdb.images.labels = {y} ; %labels的数据结构完全由自己决定,与getBatch函数以及误差层的backward函数兼容即可(在backward函数中以layer.class形式出现,layer.class等于getBatch函数的返回值labels);对于分类问题,一般为[1,1,2,2]等类别信息 imdb.images.set = [1];% 样本类型,1为训练样本,2为validation样本,3为测试样本,,但是cnn_train函数只会对训练样本和测试样本进行计算 imdb.meta.sets = {'train', 'val', 'test'} ;%集合名称,即1代表训练集,2代表val集(validation) imdb.meta.classes ={'1'}; %类别名称 %% ------------------------------------------------------------------------- % Part 3.3: Learning with stochastic gradient descent % ------------------------------------------------------------------------- trainOpts.batchSize = 1 ; trainOpts.numEpochs = 500 ; %运行多少轮 trainOpts.continue = false ;%如果trainOpts.expDir已经有对应epoch的网络,是否直接载入 trainOpts.gpus=[]; %gpu下标,不使用GPU则设为[],,如果有两个GPU可以设为 [1 2] trainOpts.learningRate =.5 ; trainOpts.expDir = 'data/ex3-experiment' ; %输出的网络结果、实验结果图存在哪儿 trainOpts.momentum=0.9; trainOpts.weightDecay = 0.0001 ; trainOpts.errorFunction=@error_ErrPixels; %用于显示误差的自定义函数 trainOpts.errorLabels ={'错误率'}; net=LC_CNN_Ex3('wSize',wSize); %将pos,neg均传给网络,记录到输出层的结构中,便于根据之前的公式计算误差 trainOpts.val= imdb.images.set==1; %验证集下标,,必须有验证集,否则报错。。。只好把训练集当成验证集了 [net, info] = cnn_train(net, imdb, @getBatch, ... trainOpts) ; end %只有一幅图片,直接返回就行了 function [im, labels]=getBatch(imdb,batch) im= imdb.images.data{1}; im=reshape(im,[size(im) 1]); labels=imdb.images.labels{1}; end %绘图用,用于检测不同epoch下网络的性能,这里返回的指标为分类错误率 function err = error_ErrPixels(opts, labels, res) % ------------------------------------------------------------------------- resX=res(end-1).x; y=labels; fp = resX >0 & y < 0 ; fn = resX < 1 & y > 0 ; tn = resX <= 0 & y < 0 ; tp = resX >= 1 & y > 0 ; % err=[fp;fn;tn;tp]; %可以设置多个指标,对应的trainOpts.errorLabels 也要改为多个标签 err=100*(1-sum(sum(tp|tn))/sum(sum(fp|fn|tp|tn))); end
function net=LC_CNN_Ex3(varargin) % 改写http://www.robots.ox.ac.uk/~vgg/practicals/cnn/index.html 的 exercise 3为一个网络 opts.wSize=3; opts=vl_argparse(opts,varargin); net.layers = {} ; lr=ones(1,10); weightDecay=[1 0]; w = 10 * randn(opts.wSize,opts.wSize, 1) ; %最后一个表示输出只有一个通道 w = single(w - mean(w(:))) ; b = single(0) ; pad1 = ([size(w,1) size(w,1) size(w,2) size(w,2)] - 1) / 2 ; net.layers{end+1}= struct('type', 'conv', ... 'weights', {{w, b}}, ... 'learningRate', [1 2], ... %自定义learning rate相对于全局的learning rate 的比率,[1 2] 表示w的学习率与全局学习率一致,而偏置b的学习率则为全局学习率的两倍 'weightDecay',weightDecay,...;%自定义weightDecay相对于全局的weightDecay的比率,[1 0]表示只对w矩阵进行weight decay,而不对偏置b进行weight decay 'stride', 1, ... 'pad', pad1) ; rho2 = 3 ; pad2 = (rho2 - 1) / 2 ; net.layers{end+1}= struct('type', 'pool', ... 'method', 'max', ... 'pool', rho2, ... 'stride', 1, ... 'pad', pad2) ; %% 自定义的误差函数层 net.layers{end+1}= struct('type', 'custom', ... 'forward', @forwardFunc , ... % 'backward', @backwardFunc) ; end function resIp1= forwardFunc(layer, resI, resIp1) % 计算数据项误差 pos=layer.class==1; neg=layer.class==-1; resIp1.x= mean(max(0, 1 - resI.x(pos))) + ... mean(max(0, resI.x(neg))); end %后向传播,,求导;;;注意layer.class为该batch内图片的labels。 function resI = backwardFunc(layer, resI, resIp1) %计算导数 pos=layer.class==1; neg=layer.class==-1; resI.dzdx=- single(resI.x < 1 & pos) / sum(pos(:)) + ... + single(resI.x > 0 & neg) / sum(neg(:)) ; end