Deep Learning学习 之 CNN代码解析(MATLAB)
Test_example_CNN
Test_example_CNN:
- 1設置CNN的基本參數規格,如卷積、降采樣層的數量,卷積核的大小、降采樣的降幅
- 2 cnnsetup函數 初始化卷積核、偏置等
- 3 cnntrain函數 訓練cnn,把訓練數據分成batch,然后調用?
- 3.1cnnff 完成訓練的前向過程
- 3.2 cnnbp計算并傳遞神經網絡的error,并計算梯度(權重的修改量)
- 3.3 cnnapplygrads 把計算出來的梯度加到原始模型上去
- 4 cnntest 函數,測試當前模型的準確率
該模型采用的數據為mnist_uint8.mat,含有70000個手寫數字樣本其中60000作為訓練樣本,10000作為測試樣本。?
把數據轉成相應的格式,并歸一化。
- 1
- 2
- 3
- 4
- 5
設置網絡結構及訓練參數
%% 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 %% 訓練選項,alpha學習效率(不用),batchsiaze批訓練總樣本的數量,numepoches迭代次數 opts.alpha = 1; opts.batchsize = 50; opts.numepochs = 1;- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
初始化網絡,對數據進行批訓練,驗證模型準確率。
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
該函數你用于初始化CNN的參數。?
設置各層的mapsize大小,?
初始化卷積層的卷積核、bias?
尾部單層感知機的參數設置
bias統一初始化為0
權重設置為:random(-1,1)/(6(輸入神經元數量+輸出神經元數量))??????????????????????√
對于卷積核權重,輸入輸出為fan_in, fan_out?
fan_out = net.layers{l}.outputmaps * net.layers{l}.kernelsize ^ 2;
%卷積核初始化,1層卷積為1*6個卷積核,2層卷積一共6*12=72個卷積核。對于每個卷積輸出featuremap,?
%fan_in = 表示該層的一個輸出map,所對應的所有卷積核,包含的神經元的總數。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));
卷積降采樣的參數初始化
numInputmaps = 1; mapsize = size(squeeze(x(:, :, 1))); %[28, 28];一個行向量。x(:, :, 1)是一個訓練樣本。 % 下面通過傳入net這個結構體來逐層構建CNN網絡 for l = 1 : numel(net.layers)if strcmp(net.layers{l}.type, 's')%降采樣層sub sampling%降采樣圖的大小mapsize由28*28變為14*14。net.layers{l}.scale = 2。mapsize = mapsize / net.layers{l}.scale;for j = 1 : numInputmaps % 一個降采樣層的所有輸入map,b初始化為0net.layers{l}.b{j} = 0;endendif strcmp(net.layers{l}.type, 'c')%如果是卷積層%得到卷積層的featuremap的size,卷積層fm的大小 為 上一層大小 - 卷積核大小 + 1(步長為1的情況)mapsize = mapsize - net.layers{l}.kernelsize + 1;%fan_out該層的所有連接的數量 = 卷積核數 * 卷積核size = 6*(5*5),12*(5*5)fan_out = net.layers{l}.outputmaps * net.layers{l}.kernelsioze ^ 2;%卷積核初始化,1層卷積為1*6個卷積核,2層卷積一共有6*12=72個卷積核。for j = 1 : net.layers{l}.outputmaps % output map%輸入做卷積% fan_in = 本層的一個輸出map所對應的所有卷積核,包含的權值的總數 = 1*25,6*25fan_in = numInputmaps * net,layers{l}.kernelsize ^ 2;for i = 1 : numInputmaps % input map%卷積核的初始化生成一個5*5的卷積核,值為-1~1之間的隨機數%再乘以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,每個輸出map只有一個bias,并非每個filter一個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
尾部單層感知機的參數(權重和偏量)設置
%%尾部單層感知機(全連接層)的參數設置 fvnum = prod(mapsize) * numInputmaps;%prod函數用于求數組元素的乘積,fvnum = 4*4*12 = 192,是全連接層的輸入數量 onum = size(y, 1);%輸出節點的數量 net.ffb = zeros(onum, 1); net.ffW = (rand(onum, fvnum) - 0.5) * 2 * sqrt(6 / (onum + fvnum));- 1
- 2
- 3
- 4
- 5
cnntrain.m
該函數用于訓練CNN。?
生成隨機序列,每次選取一個batch(50)個樣本進行訓練。?
批訓練:計算50個隨機樣本的梯度,求和之后一次性更新到模型權重中。?
在批訓練過程中調用:?
Cnnff.m 完成前向過程?
Cnnbp.m 完成誤差傳導和梯度計算過程?
Cnnapplygrads.m 把計算出來的梯度加到原始模型上去
- 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,時一個[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出來理 net.layers{l}.k{i}{j} = sigm(z + net.layers{l}.b{j});end%下層輸入feacureMap的里等于本層輸出的feateMap的數量numlnputmaps = net.layers{l}.outputmaps;elseif strcmp(net.layers{l}.type,'s') %down samplefor j = 1 : numlnputmaps %這子采樣是怎么做到的?卷積一個[0.25,0,25;0.25,0,5]的卷積核,然后降采樣。這里有重復計算z = convon(net.layers{l-1}).a{j}, ones(net.layers{l}.scale) / (net.layers{l}.scale ^ 2),'valid');%這里設置scale長度的步長,窗移一》scale,但是這里有計算浪費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
尾部單層感知機的數據處理
需要把subFeatureMap2連接成為一個(4*4)*12=192的向量,但是由于采用了50樣本批訓練的方法,subFeatureMap2被拼合成為一個192*50的特征向量fv;?
Fv作為單層感知機的輸入,全連接的方式得到輸出層
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
cnnbp.m
該函數實現2部分功能,計算并傳遞誤差,計算梯度
計算誤差和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
計算尾部單層感知機的誤差
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的前一層(特征抽取最后一層)是卷積層,卷積層的輸出經過sigmoid函數處理,error求導 %在數字識別這個網絡中不要用到 if strcmp(net.layers{numLayers}.type, 'c')%對于卷基層,它的特征向里誤差再求導(net.fv .* (1-net.fv))net.fvd = net.fvd .*(net.fv .* (1 - net.fv)); end- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
改變誤差矩陣形狀
把單層感知機的輸入層featureVector的誤差矩陣,恢復為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一個圖所含有的特征向量的數量,4*4 for j = 1 : numel(net.layers{numLayers}.a) %subFeatureMap2的數量,1:12%net最后一層的delta,由特征向量delta,儂次取一個featureMap大小,然后組臺成為一個featureMap的形狀 %在fvd里面亻呆存的是所有祥本的特征向量(在cnnff.m函數中用特征map拉成的);這里需要重新變換回來持征map的 形式。%net.fvd(((j - 1) * fvnum + 1) : j * fvnum, : ) ,一個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
插播一張圖片:
誤差在特征提取網絡【卷積降采樣層】的傳播
如果本層是卷積層,它的誤差是從后一層(降采樣層)傳過來,誤差傳播實際上是用降采樣的反向過程,也就是降采樣層的誤差復制為2*2=4份。卷積層的輸入是經過sigmoid處理的,所以,從降采樣層擴充來的誤差要經過sigmoid求導處理。?
如果本層是降采樣層,他的誤差是從后一層(卷積層)傳過來,誤差傳播實際是用卷積的反向過程,也就是卷積層的誤差,反卷積(卷積核轉180度)卷積層的誤差,原理參看插圖。
?
計算特征抽取層和尾部單層感知機的梯度
%計算特征抽取層(卷積+降采樣)的梯度 for l = 2 : numLayersif strcmp(net.layers{l}.type, 'c') %卷積層for j = 1 : numel(net.layers{l}.a) %l層的featureMap的數量for i = 1 : numel(net.layers{l - 1}.a) %l-1層的featureMap的數量%卷積核的修改量 = 輸入圖像 * 輸出圖像的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}(:)是一個24*24*50的矩陣,db僅除于50net.layers{l}.db{j} = sum{net.layers{l}.d{j}(:)} / size(net.layers{l}.d{j}, 3);endend end %計算機尾部單層感知機的梯度 %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
該函數完成權重修改,更新模型的功能?
1更新特征抽取層的權重 weight+bias?
2 更新末尾單層感知機的權重 weight+bias
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
cnntest.m
驗證測試樣本的準確率
%驗證測試樣本的準確率 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); %計算預測錯誤的樣本數量er = numel(bad) / size(y, 2); % 計算錯誤率 end總結
以上是生活随笔為你收集整理的Deep Learning学习 之 CNN代码解析(MATLAB)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 全球首个由AI鉴定保驾护航的B2B奢侈品
- 下一篇: 淮海工学院期末考试Oracle,淮海工学