Deep Learning学习 之 CNN代码解析(MATLAB)
Test_example_CNN
Test_example_CNN:
- 1設(shè)置CNN的基本參數(shù)規(guī)格,如卷積、降采樣層的數(shù)量,卷積核的大小、降采樣的降幅
- 2 cnnsetup函數(shù) 初始化卷積核、偏置等
- 3 cnntrain函數(shù) 訓(xùn)練cnn,把訓(xùn)練數(shù)據(jù)分成batch,然后調(diào)用?
- 3.1cnnff 完成訓(xùn)練的前向過(guò)程
- 3.2 cnnbp計(jì)算并傳遞神經(jīng)網(wǎng)絡(luò)的error,并計(jì)算梯度(權(quán)重的修改量)
- 3.3 cnnapplygrads 把計(jì)算出來(lái)的梯度加到原始模型上去
- 4 cnntest 函數(shù),測(cè)試當(dāng)前模型的準(zhǔn)確率
該模型采用的數(shù)據(jù)為mnist_uint8.mat,含有70000個(gè)手寫(xiě)數(shù)字樣本其中60000作為訓(xùn)練樣本,10000作為測(cè)試樣本。?
把數(shù)據(jù)轉(zhuǎn)成相應(yīng)的格式,并歸一化。
- 1
- 2
- 3
- 4
- 5
設(shè)置網(wǎng)絡(luò)結(jié)構(gòu)及訓(xùn)練參數(shù)
%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %% will run 1 epoch in about 200 second and get around 11% error %% with 100 epochs you' will get around 1.2% errorrand('state',0); cnn.layers = {struct('type','i') %input layerstruct('type','c','outputmaps',6,'kernelsize',5) % convolution layerstruct('type','s','scale',2) %sub sampling layerstruct('type','c','outputmaps',12,'kernelsize',5) % convolutional layerstruct('type','s','scale',2) % sub sampling layer %% 訓(xùn)練選項(xiàng),alpha學(xué)習(xí)效率(不用),batchsiaze批訓(xùn)練總樣本的數(shù)量,numepoches迭代次數(shù) opts.alpha = 1; opts.batchsize = 50; opts.numepochs = 1;- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
初始化網(wǎng)絡(luò),對(duì)數(shù)據(jù)進(jìn)行批訓(xùn)練,驗(yàn)證模型準(zhǔn)確率。
cnn = cmmsetup(cnn, train_x, train_y); cnn = cnntrain(cnn, train_x, train_y, opts); [er, bad] = cnntest(cnn, test_x, test_y);- 1
- 2
- 3
繪制均方誤差曲線
%plot mean squared error figure; plot(cnn.rL);- 1
- 2
Cnnsetup.m
該函數(shù)你用于初始化CNN的參數(shù)。?
設(shè)置各層的mapsize大小,?
初始化卷積層的卷積核、bias?
尾部單層感知機(jī)的參數(shù)設(shè)置
bias統(tǒng)一初始化為0
權(quán)重設(shè)置為:random(-1,1)/(6(輸入神經(jīng)元數(shù)量+輸出神經(jīng)元數(shù)量))??????????????????????√
對(duì)于卷積核權(quán)重,輸入輸出為fan_in, fan_out?
fan_out = net.layers{l}.outputmaps * net.layers{l}.kernelsize ^ 2;
%卷積核初始化,1層卷積為1*6個(gè)卷積核,2層卷積一共6*12=72個(gè)卷積核。對(duì)于每個(gè)卷積輸出featuremap,?
%fan_in = 表示該層的一個(gè)輸出map,所對(duì)應(yīng)的所有卷積核,包含的神經(jīng)元的總數(shù)。1*25,6*25?
fan_in = numInputmaps * net.layers{l}.kernelsize ^ 2;?
fin =1*25 or 6*25?
fout=1*6*25 or 6*12*25
net.layers{l}.k{i}{j} = (rand(net.layers{l}.kernelsize) - 0.5) * 2 * sqrt(6 / (fan_in + fan_out));
卷積降采樣的參數(shù)初始化
numInputmaps = 1; mapsize = size(squeeze(x(:, :, 1))); %[28, 28];一個(gè)行向量。x(:, :, 1)是一個(gè)訓(xùn)練樣本。 % 下面通過(guò)傳入net這個(gè)結(jié)構(gòu)體來(lái)逐層構(gòu)建CNN網(wǎng)絡(luò) for l = 1 : numel(net.layers)if strcmp(net.layers{l}.type, 's')%降采樣層sub sampling%降采樣圖的大小mapsize由28*28變?yōu)?4*14。net.layers{l}.scale = 2。mapsize = mapsize / net.layers{l}.scale;for j = 1 : numInputmaps % 一個(gè)降采樣層的所有輸入map,b初始化為0net.layers{l}.b{j} = 0;endendif strcmp(net.layers{l}.type, 'c')%如果是卷積層%得到卷積層的featuremap的size,卷積層fm的大小 為 上一層大小 - 卷積核大小 + 1(步長(zhǎng)為1的情況)mapsize = mapsize - net.layers{l}.kernelsize + 1;%fan_out該層的所有連接的數(shù)量 = 卷積核數(shù) * 卷積核size = 6*(5*5),12*(5*5)fan_out = net.layers{l}.outputmaps * net.layers{l}.kernelsioze ^ 2;%卷積核初始化,1層卷積為1*6個(gè)卷積核,2層卷積一共有6*12=72個(gè)卷積核。for j = 1 : net.layers{l}.outputmaps % output map%輸入做卷積% fan_in = 本層的一個(gè)輸出map所對(duì)應(yīng)的所有卷積核,包含的權(quán)值的總數(shù) = 1*25,6*25fan_in = numInputmaps * net,layers{l}.kernelsize ^ 2;for i = 1 : numInputmaps % input map%卷積核的初始化生成一個(gè)5*5的卷積核,值為-1~1之間的隨機(jī)數(shù)%再乘以sqrt(6/(7*25)),sqrt(6/(18*25))net.layers{l}.k{i}{j} = (rand(net.layers{l}.kernelsize) - 0.5 * 2 * sqrt(6 / (fan_in, fan_out)))end%偏置初始化為0,每個(gè)輸出map只有一個(gè)bias,并非每個(gè)filter一個(gè)biasnet.layers{l}.b{j} = 0;endnumInputmaps = net.layers{l}.outputmaps;end end- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
尾部單層感知機(jī)的參數(shù)(權(quán)重和偏量)設(shè)置
%%尾部單層感知機(jī)(全連接層)的參數(shù)設(shè)置 fvnum = prod(mapsize) * numInputmaps;%prod函數(shù)用于求數(shù)組元素的乘積,fvnum = 4*4*12 = 192,是全連接層的輸入數(shù)量 onum = size(y, 1);%輸出節(jié)點(diǎn)的數(shù)量 net.ffb = zeros(onum, 1); net.ffW = (rand(onum, fvnum) - 0.5) * 2 * sqrt(6 / (onum + fvnum));- 1
- 2
- 3
- 4
- 5
cnntrain.m
該函數(shù)用于訓(xùn)練CNN。?
生成隨機(jī)序列,每次選取一個(gè)batch(50)個(gè)樣本進(jìn)行訓(xùn)練。?
批訓(xùn)練:計(jì)算50個(gè)隨機(jī)樣本的梯度,求和之后一次性更新到模型權(quán)重中。?
在批訓(xùn)練過(guò)程中調(diào)用:?
Cnnff.m 完成前向過(guò)程?
Cnnbp.m 完成誤差傳導(dǎo)和梯度計(jì)算過(guò)程?
Cnnapplygrads.m 把計(jì)算出來(lái)的梯度加到原始模型上去
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
cnnff.m
取得CNN的輸入
numLayers = numel(net.layers); net.layers{1}.a{1} = x;%a是輸入map,時(shí)一個(gè)[28, 28, 50]的矩陣(具體情況具體定) numInputmaps = 1;- 1
- 2
- 3
兩次卷積核降采樣層處理
for l = 2 : numLayers %for each layer if strcmp(net.layers{l}.type, 'c')for j = 1 : net.layers{l}.outputmaps %for each output map% z = zeros([28,28,50]-[4,4,0]) = zeros([24,24,50]) z = zeros(size(net.layers{l一1}.a{1}) - [net.layers{l}.kernelsize — 1, net.layers{l}.kernelsize — 1, 0]);for i = 1 : numlnputmaps% for each input map z = z + convn(net.layers{l-1}.a{i}, net.layers{l}.k{i}{j}, 'valid');end %加上bias并sigmo出來(lái)理 net.layers{l}.k{i}{j} = sigm(z + net.layers{l}.b{j});end%下層輸入feacureMap的里等于本層輸出的feateMap的數(shù)量numlnputmaps = net.layers{l}.outputmaps;elseif strcmp(net.layers{l}.type,'s') %down samplefor j = 1 : numlnputmaps %這子采樣是怎么做到的?卷積一個(gè)[0.25,0,25;0.25,0,5]的卷積核,然后降采樣。這里有重復(fù)計(jì)算z = convon(net.layers{l-1}).a{j}, ones(net.layers{l}.scale) / (net.layers{l}.scale ^ 2),'valid');%這里設(shè)置scale長(zhǎng)度的步長(zhǎng),窗移一》scale,但是這里有計(jì)算浪費(fèi)net.layers{l}·a{j} = z(1 : net.layers{1}.scale : end, 1 : net.layers{l}.scale : end, :);endend end- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
尾部單層感知機(jī)的數(shù)據(jù)處理
需要把subFeatureMap2連接成為一個(gè)(4*4)*12=192的向量,但是由于采用了50樣本批訓(xùn)練的方法,subFeatureMap2被拼合成為一個(gè)192*50的特征向量fv;?
Fv作為單層感知機(jī)的輸入,全連接的方式得到輸出層
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
cnnbp.m
該函數(shù)實(shí)現(xiàn)2部分功能,計(jì)算并傳遞誤差,計(jì)算梯度
計(jì)算誤差和LossFunction
numLayers = numel(net.layers); %error net.e = net.o - y; % loss function 均方誤差 net.L = 1 / 2 * sun(net.e(:) . ^ 2 ) / size(net.e, 2);- 1
- 2
- 3
- 4
- 5
計(jì)算尾部單層感知機(jī)的誤差
net.od = net.e .* (net.o .*(1 - net.o)); %output dalta, sigmoid 誤差 %fvd, feature vector delta, 特征向里誤差,上一層收集下層誤差,size = [192*50] net.fvd = (net.ffW' * net.od); %如果MLP的前一層(特征抽取最后一層)是卷積層,卷積層的輸出經(jīng)過(guò)sigmoid函數(shù)處理,error求導(dǎo) %在數(shù)字識(shí)別這個(gè)網(wǎng)絡(luò)中不要用到 if strcmp(net.layers{numLayers}.type, 'c')%對(duì)于卷基層,它的特征向里誤差再求導(dǎo)(net.fv .* (1-net.fv))net.fvd = net.fvd .*(net.fv .* (1 - net.fv)); end- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
改變誤差矩陣形狀
把單層感知機(jī)的輸入層featureVector的誤差矩陣,恢復(fù)為subFeatureMap2的4*4二維矩陣形式
% reshape feature vector deltas into output map style sizeA = size(net.layers{numlayers}.a{1}));%size(a{1}) = [4*4*50],一共有a{1}~a{12}; fvnum = sizeA(1) * sizeA(2); %fvnum一個(gè)圖所含有的特征向量的數(shù)量,4*4 for j = 1 : numel(net.layers{numLayers}.a) %subFeatureMap2的數(shù)量,1:12%net最后一層的delta,由特征向量delta,儂次取一個(gè)featureMap大小,然后組臺(tái)成為一個(gè)featureMap的形狀 %在fvd里面亻呆存的是所有祥本的特征向量(在cnnff.m函數(shù)中用特征map拉成的);這里需要重新變換回來(lái)持征map的 形式。%net.fvd(((j - 1) * fvnum + 1) : j * fvnum, : ) ,一個(gè)featureMap的誤差d net.layers{numLayers}.d{j} = reshape(net.fvd(((j-1) * fvnum + 1);j * fvnum, :), sizeA(1), sizeA(2), sizeA(3));%size(net.layers{numLayers}.d{j}) = [4 * 4 * 50]%size(net.fvd) = [192 * 50] end- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
插播一張圖片:
誤差在特征提取網(wǎng)絡(luò)【卷積降采樣層】的傳播
如果本層是卷積層,它的誤差是從后一層(降采樣層)傳過(guò)來(lái),誤差傳播實(shí)際上是用降采樣的反向過(guò)程,也就是降采樣層的誤差復(fù)制為2*2=4份。卷積層的輸入是經(jīng)過(guò)sigmoid處理的,所以,從降采樣層擴(kuò)充來(lái)的誤差要經(jīng)過(guò)sigmoid求導(dǎo)處理。?
如果本層是降采樣層,他的誤差是從后一層(卷積層)傳過(guò)來(lái),誤差傳播實(shí)際是用卷積的反向過(guò)程,也就是卷積層的誤差,反卷積(卷積核轉(zhuǎn)180度)卷積層的誤差,原理參看插圖。
?
計(jì)算特征抽取層和尾部單層感知機(jī)的梯度
%計(jì)算特征抽取層(卷積+降采樣)的梯度 for l = 2 : numLayersif strcmp(net.layers{l}.type, 'c') %卷積層for j = 1 : numel(net.layers{l}.a) %l層的featureMap的數(shù)量for i = 1 : numel(net.layers{l - 1}.a) %l-1層的featureMap的數(shù)量%卷積核的修改量 = 輸入圖像 * 輸出圖像的deltanet.layers{l}.dk{i}{j} = convn(flipall(net.layers{l - 1}.a{i}), net.layers{l}.d{j}, 'valid') / size(net.layers{l}.d{j}, 3);end%net.layers.d{j}(:)是一個(gè)24*24*50的矩陣,db僅除于50net.layers{l}.db{j} = sum{net.layers{l}.d{j}(:)} / size(net.layers{l}.d{j}, 3);endend end %計(jì)算機(jī)尾部單層感知機(jī)的梯度 %sizeof(net.od) = [10, 50] %修改量,求和除于50(batch大小) net.dffW = net.od * (net.fv)' / size(net.od, 2); net.dffb = mean(net.od. 2);%第二維度取均值- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
cnnapplygrads.m
該函數(shù)完成權(quán)重修改,更新模型的功能?
1更新特征抽取層的權(quán)重 weight+bias?
2 更新末尾單層感知機(jī)的權(quán)重 weight+bias
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
cnntest.m
驗(yàn)證測(cè)試樣本的準(zhǔn)確率
%驗(yàn)證測(cè)試樣本的準(zhǔn)確率 function [er, bad] = cnntest(net, x, y)% feedforwardnet = cnnff(net, x);[~, h] = max(net.o);[~, a] = max(y);%find(x) FIND indices of nonzero elementsbad = find(h ~= a); %計(jì)算預(yù)測(cè)錯(cuò)誤的樣本數(shù)量er = numel(bad) / size(y, 2); % 計(jì)算錯(cuò)誤率 end總結(jié)
以上是生活随笔為你收集整理的Deep Learning学习 之 CNN代码解析(MATLAB)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 全球首个由AI鉴定保驾护航的B2B奢侈品
- 下一篇: 淮海工学院期末考试Oracle,淮海工学