深度學(xué)習(xí)Matlab工具箱DeepLearnToolbox代碼注釋(轉(zhuǎn))

2017-01-16  by:CAE仿真在線  來(lái)源:互聯(lián)網(wǎng)

深度學(xué)習(xí)Matlab工具箱DeepLearnToolbox代碼注釋

----轉(zhuǎn)自csdn“陳俊嶺的程序員之路”

%%=========================================================================

% 主要功能:在mnist數(shù)據(jù)庫(kù)上做實(shí)驗(yàn),驗(yàn)證工具箱的有效性

% 算法流程:1)載入訓(xùn)練樣本和測(cè)試樣本

% 2)設(shè)置CNN參數(shù),并進(jìn)行訓(xùn)練

% 3)進(jìn)行檢測(cè)cnntest()

% 注意事項(xiàng):1)由于直接將所有測(cè)試樣本輸入會(huì)導(dǎo)致內(nèi)存溢出,故采用一次只測(cè)試一個(gè)訓(xùn)練樣本的測(cè)試方法

%%=========================================================================

%%

%%%%%%%%%%%%%%%%%%%%加載數(shù)據(jù)集%%%%%%%%%%%%%%%%%%%%

load mnist_uint8;

train_x = double(reshape(train_x',28,28,60000))/255;

test_x = double(reshape(test_x',28,28,10000))/255;

train_y = double(train_y');

test_y = double(test_y');

%%

%%=========================================================================

%%%%%%%%%%%%%%%%%%%%設(shè)置卷積神經(jīng)網(wǎng)絡(luò)參數(shù)%%%%%%%%%%%%%%%%%%%%

% 主要功能:訓(xùn)練一個(gè)6c-2s-12c-2s形式的卷積神經(jīng)網(wǎng)絡(luò),預(yù)期性能如下:

% 1)迭代一次需要200秒左右,錯(cuò)誤率大約為11%

% 2)迭代一百次后錯(cuò)誤率大約為1.2%

% 算法流程:1)構(gòu)建神經(jīng)網(wǎng)絡(luò)并進(jìn)行訓(xùn)練,以CNN結(jié)構(gòu)體的形式保存

% 2)用已知的訓(xùn)練樣本進(jìn)行測(cè)試

% 注意事項(xiàng):1)之前在測(cè)試的時(shí)候提示內(nèi)存溢出,后來(lái)莫名其妙的又不溢出了,估計(jì)到了系統(tǒng)的內(nèi)存臨界值

%%=========================================================================

rand('state',0)

cnn.layers = {

struct('type', 'i') %輸入層

struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %卷積層

struct('type', 's', 'scale', 2) %下采樣層

struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %卷積層

struct('type', 's', 'scale', 2) %下采樣層

};

cnn = cnnsetup(cnn, train_x, train_y);

opts.alpha = 1;

opts.batchsize = 50;

opts.numepochs = 5;

cnn = cnntrain(cnn, train_x, train_y, opts);

save CNN_5 cnn;

load CNN_5;

[er, bad] = cnntest(cnn, test_x, test_y);

figure; plot(cnn.rL);

assert(er<0.12, 'Too big error');

深度學(xué)習(xí)Matlab工具箱代碼注釋——cnnsetup.m

%%=========================================================================

% 函數(shù)名稱:cnnsetup

% 輸入?yún)?shù):net,待設(shè)置的卷積神經(jīng)網(wǎng)絡(luò);x,訓(xùn)練樣本;y,訓(xùn)練樣本對(duì)應(yīng)標(biāo)簽;

% 輸出參數(shù):net,初始化完成的卷積神經(jīng)網(wǎng)絡(luò)

% 主要功能:對(duì)CNN的結(jié)構(gòu)進(jìn)行初始化

% 算法流程:1)

% 注意事項(xiàng):1)isOctave這個(gè)語(yǔ)句是為了拋出一個(gè)程序在Octave平臺(tái)上運(yùn)行時(shí)的一個(gè)BUG,在matlab平臺(tái)上可以直接注釋掉

% 2)net.layers中有五個(gè)struct類型的元素,實(shí)際上就表示CNN共有五層,這里范圍的是5

%%=========================================================================

function net = cnnsetup(net, x, y)

assert(~isOctave() || compare_versions(OCTAVE_VERSION, '3.8.0', '>='), ['Octave 3.8.0 or greater is required for CNNs as there is a bug in convolution in previous versions. See http://savannah.gnu.org/bugs/?39314. Your version is ' myOctaveVersion]);

inputmaps = 1; %初始化網(wǎng)絡(luò)輸入層數(shù)為1層

%%=========================================================================

% 主要功能:得到輸入圖像的行數(shù)和列數(shù)

% 注意事項(xiàng):1)B=squeeze(A) 返回和矩陣A相同元素但所有單一維都移除的矩陣B,單一維是滿足size(A,dim)=1的維。

% train_x中圖像的存放方式是三維的reshape(train_x',28,28,60000),前面兩維表示圖像的行與列,

% 第三維就表示有多少個(gè)圖像。這樣squeeze(x(:, :, 1))就相當(dāng)于取第一個(gè)圖像樣本后,再把第三維

% 移除,就變成了28x28的矩陣,也就是得到一幅圖像,再size一下就得到了訓(xùn)練樣本圖像的行數(shù)與列數(shù)了

%%=========================================================================

mapsize = size(squeeze(x(:, :, 1)));

%%%%%%%%%%%%%%%%%%%%下面通過(guò)傳入net這個(gè)結(jié)構(gòu)體來(lái)逐層構(gòu)建CNN網(wǎng)絡(luò)%%%%%%%%%%%%%%%%%%%%

for l = 1 : numel(net.layers) %對(duì)于每一層

if strcmp(net.layers{l}.type, 's') %如果當(dāng)前層是下采樣層

%%=========================================================================

% 主要功能:獲取下采樣之后特征map的尺寸

% 注意事項(xiàng):1)subsampling層的mapsize,最開(kāi)始mapsize是每張圖的大小28*28

% 這里除以scale=2,就是pooling之后圖的大小,pooling域之間沒(méi)有重疊,所以pooling后的圖像為14*14

% 注意這里的右邊的mapsize保存的都是上一層每張?zhí)卣鱩ap的大小,它會(huì)隨著循環(huán)進(jìn)行不斷更新

%%=========================================================================

mapsize = mapsize / net.layers{l}.scale;

assert(all(floor(mapsize)==mapsize), ['Layer ' num2str(l) ' size must be integer. Actual: ' num2str(mapsize)]);

for j = 1 : inputmaps %對(duì)于上一層的每個(gè)特征圖

net.layers{l}.b{j} = 0; %將偏置初始化為零

end

end

if strcmp(net.layers{l}.type, 'c') %如果當(dāng)前層是卷基層

%%=========================================================================

% 主要功能:獲取卷積后的特征map尺寸以及當(dāng)前層待學(xué)習(xí)的卷積核的參數(shù)數(shù)量

% 注意事項(xiàng):1)舊的mapsize保存的是上一層的特征map的大小,那么如果卷積核的移動(dòng)步長(zhǎng)是1,那用

% kernelsize*kernelsize大小的卷積核卷積上一層的特征map后,得到的新的map的大小就是下面這樣

% 2)fan_out代表該層需要學(xué)習(xí)的參數(shù)個(gè)數(shù)。每張?zhí)卣鱩ap是一個(gè)(后層特征圖數(shù)量)*(用來(lái)卷積的patch圖的大小)

% 因?yàn)槭峭ㄟ^(guò)用一個(gè)核窗口在上一個(gè)特征map層中移動(dòng)(核窗口每次移動(dòng)1個(gè)像素),遍歷上一個(gè)特征map

% 層的每個(gè)神經(jīng)元。核窗口由kernelsize*kernelsize個(gè)元素組成,每個(gè)元素是一個(gè)獨(dú)立的權(quán)值,所以

% 就有kernelsize*kernelsize個(gè)需要學(xué)習(xí)的權(quán)值,再加一個(gè)偏置值。另外,由于是權(quán)值共享,也就是

% 說(shuō)同一個(gè)特征map層是用同一個(gè)具有相同權(quán)值元素的kernelsize*kernelsize的核窗口去感受輸入上一

% 個(gè)特征map層的每個(gè)神經(jīng)元得到的,所以同一個(gè)特征map,它的權(quán)值是一樣的,共享的,權(quán)值只取決于

% 核窗口。然后,不同的特征map提取輸入上一個(gè)特征map層不同的特征,所以采用的核窗口不一樣,也

% 就是權(quán)值不一樣,所以outputmaps個(gè)特征map就有(kernelsize*kernelsize+1)* outputmaps那么多的權(quán)值了

% 但這里fan_out只保存卷積核的權(quán)值W,偏置b在下面獨(dú)立保存

%%=========================================================================

mapsize = mapsize - net.layers{l}.kernelsize + 1;

fan_out = net.layers{l}.outputmaps * net.layers{l}.kernelsize ^ 2;

for j = 1 : net.layers{l}.outputmaps %對(duì)于卷積層的每一個(gè)輸出map

%%=========================================================================

% 主要功能:獲取卷積層與前一層輸出map之間需要鏈接的參數(shù)鏈個(gè)數(shù)

% 注意事項(xiàng):1)fan_out保存的是對(duì)于上一層的一張?zhí)卣鱩ap,我在這一層需要對(duì)這一張?zhí)卣鱩ap提取outputmaps種特征,

% 提取每種特征用到的卷積核不同,所以fan_out保存的是這一層輸出新的特征需要學(xué)習(xí)的參數(shù)個(gè)數(shù)

% 而,fan_in保存的是,我在這一層,要連接到上一層中所有的特征map,然后用fan_out保存的提取特征

% 的權(quán)值來(lái)提取他們的特征。也即是對(duì)于每一個(gè)當(dāng)前層特征圖,有多少個(gè)參數(shù)鏈到前層

%%=========================================================================

fan_in = inputmaps * net.layers{l}.kernelsize ^ 2;

for i = 1 : inputmaps %對(duì)于上一層的每一個(gè)輸出特征map(本層的輸入map)

%%=========================================================================

% 主要功能:隨機(jī)初始化卷積核的權(quán)值,再將偏置均初始化為零

% 注意事項(xiàng):1)隨機(jī)初始化權(quán)值,也就是共有outputmaps個(gè)卷積核,對(duì)上層的每個(gè)特征map,都需要用這么多個(gè)卷積核去卷積提取特征。

% rand(n)是產(chǎn)生n×n的 0-1之間均勻取值的數(shù)值的矩陣,再減去0.5就相當(dāng)于產(chǎn)生-0.5到0.5之間的隨機(jī)數(shù)

% 再 *2 就放大到 [-1, 1]。然后再乘以后面那一數(shù),why?

% 反正就是將卷積核每個(gè)元素初始化為[-sqrt(6 / (fan_in + fan_out)), sqrt(6 / (fan_in + fan_out))]

% 之間的隨機(jī)數(shù)。因?yàn)檫@里是權(quán)值共享的,也就是對(duì)于一張?zhí)卣鱩ap,所有感受野位置的卷積核都是一樣的

% 所以只需要保存的是 inputmaps * outputmaps 個(gè)卷積核。

% 2)為什么這里是inputmaps * outputmaps個(gè)卷積核?

%%=========================================================================

net.layers{l}.k{i}{j} = (rand(net.layers{l}.kernelsize) - 0.5) * 2 * sqrt(6 / (fan_in + fan_out));

end

net.layers{l}.b{j} = 0;

end

inputmaps = net.layers{l}.outputmaps; %在卷積層會(huì)更新每層網(wǎng)絡(luò)的輸出map數(shù)量

end

end

%%=========================================================================

% 主要功能:初始化最后一層,也就是輸出層的參數(shù)值

% 算法流程:1)fvnum 是輸出層的前面一層的神經(jīng)元個(gè)數(shù)。這一層的上一層是經(jīng)過(guò)pooling后的層,包含有inputmaps個(gè)

% 特征map。每個(gè)特征map的大小是mapsize,所以,該層的神經(jīng)元個(gè)數(shù)是 inputmaps * (每個(gè)特征map的大小)

% 2)onum 是標(biāo)簽的個(gè)數(shù),也就是輸出層神經(jīng)元的個(gè)數(shù)。你要分多少個(gè)類,自然就有多少個(gè)輸出神經(jīng)元

% 3)net.ffb和net.ffW為最后一層(全連接層)的偏置和權(quán)重

%%=========================================================================

fvnum = prod(mapsize) * inputmaps;

onum = size(y, 1);

net.ffb = zeros(onum, 1);

net.ffW = (rand(onum, fvnum) - 0.5) * 2 * sqrt(6 / (onum + fvnum));

end

深度學(xué)習(xí)Matlab工具箱代碼注釋——cnntrain.m

%%=========================================================================

%函數(shù)名稱:cnntrain()

%輸入?yún)?shù):net,神經(jīng)網(wǎng)絡(luò);x,訓(xùn)練數(shù)據(jù)矩陣;y,訓(xùn)練數(shù)據(jù)的標(biāo)簽矩陣;opts,神經(jīng)網(wǎng)絡(luò)的相關(guān)訓(xùn)練參數(shù)

%輸出參數(shù):net,訓(xùn)練完成的卷積神經(jīng)網(wǎng)絡(luò)

%算法流程:1)將樣本打亂,隨機(jī)選擇進(jìn)行訓(xùn)練;

% 2)取出樣本,通過(guò)cnnff2()函數(shù)計(jì)算當(dāng)前網(wǎng)絡(luò)權(quán)值和網(wǎng)絡(luò)輸入下網(wǎng)絡(luò)的輸出

% 3)通過(guò)BP算法計(jì)算誤差對(duì)網(wǎng)絡(luò)權(quán)值的導(dǎo)數(shù)

% 4)得到誤差對(duì)權(quán)值的導(dǎo)數(shù)后,就通過(guò)權(quán)值更新方法去更新權(quán)值

%注意事項(xiàng):1)使用BP算法計(jì)算梯度

%%=========================================================================

function net = cnntrain(net, x, y, opts)

m = size(x, 3); %m保存的是訓(xùn)練樣本個(gè)數(shù)

disp(['樣本總個(gè)數(shù)=' num2str(m)]);

numbatches = m / opts.batchsize; %numbatches表示每次迭代中所選取的訓(xùn)練樣本數(shù)

if rem(numbatches, 1) ~= 0 %如果numbatches不是整數(shù),則程序發(fā)生錯(cuò)誤

error('numbatches not integer');

end

%%=====================================================================

%主要功能:CNN網(wǎng)絡(luò)的迭代訓(xùn)練

%實(shí)現(xiàn)步驟:1)通過(guò)randperm()函數(shù)將原來(lái)的樣本順序打亂,再挑出一些樣本來(lái)進(jìn)行訓(xùn)練

% 2)取出樣本,通過(guò)cnnff2()函數(shù)計(jì)算當(dāng)前網(wǎng)絡(luò)權(quán)值和網(wǎng)絡(luò)輸入下網(wǎng)絡(luò)的輸出

% 3)通過(guò)BP算法計(jì)算誤差對(duì)網(wǎng)絡(luò)權(quán)值的導(dǎo)數(shù)

% 4)得到誤差對(duì)權(quán)值的導(dǎo)數(shù)后,就通過(guò)權(quán)值更新方法去更新權(quán)值

%注意事項(xiàng):1)P = randperm(N),返回[1, N]之間所有整數(shù)的一個(gè)隨機(jī)的序列,相當(dāng)于把原來(lái)的樣本排列打亂,

% 再挑出一些樣本來(lái)訓(xùn)練

% 2)采用累積誤差的計(jì)算方式來(lái)評(píng)估當(dāng)前網(wǎng)絡(luò)性能,即當(dāng)前誤差 = 以前誤差 * 0.99 + 本次誤差 * 0.01

% 使得網(wǎng)絡(luò)盡可能收斂到全局最優(yōu)

%%=====================================================================

net.rL = []; %代價(jià)函數(shù)值,也就是誤差值

for i = 1 : opts.numepochs %對(duì)于每次迭代

disp(['epoch ' num2str(i) '/' num2str(opts.numepochs)]);

tic; %使用tic和toc來(lái)統(tǒng)計(jì)程序運(yùn)行時(shí)間

%%%%%%%%%%%%%%%%%%%%取出打亂順序后的batchsize個(gè)樣本和對(duì)應(yīng)的標(biāo)簽 %%%%%%%%%%%%%%%%%%%%

kk = randperm(m);

for l = 1 : numbatches

batch_x = x(:, :, kk((l - 1) * opts.batchsize + 1 : l * opts.batchsize));

batch_y = y(:, kk((l - 1) * opts.batchsize + 1 : l * opts.batchsize));

%%%%%%%%%%%%%%%%%%%%在當(dāng)前的網(wǎng)絡(luò)權(quán)值和網(wǎng)絡(luò)輸入下計(jì)算網(wǎng)絡(luò)的輸出(特征向量)%%%%%%%%%%%%%%%%%%%%

net = cnnff(net, batch_x); %卷積神經(jīng)網(wǎng)絡(luò)的前饋運(yùn)算

%%%%%%%%%%%%%%%%%%%%通過(guò)對(duì)應(yīng)的樣本標(biāo)簽用bp算法來(lái)得到誤差對(duì)網(wǎng)絡(luò)權(quán)值的導(dǎo)數(shù)%%%%%%%%%%%%%%%%%%%%

net = cnnbp(net, batch_y); %卷積神經(jīng)網(wǎng)絡(luò)的BP算法

%%%%%%%%%%%%%%%%%%%%通過(guò)權(quán)值更新方法去更新權(quán)值%%%%%%%%%%%%%%%%%%%%

net = cnnapplygrads(net, opts);

if isempty(net.rL)

net.rL(1) = net.L; %代價(jià)函數(shù)值,也就是均方誤差值 ,在cnnbp.m中計(jì)算初始值 net.L = 1/2* sum(net.e(:) .^ 2) / size(net.e, 2);

end

net.rL(end + 1) = 0.99 * net.rL(end) + 0.01 * net.L; %采用累積的方式計(jì)算累積誤差

end

toc;

end

end

深度學(xué)習(xí)Matlab工具箱代碼注釋——cnnff.m

%%=========================================================================

%函數(shù)名稱:cnnff()

%輸入?yún)?shù):net,神經(jīng)網(wǎng)絡(luò);x,訓(xùn)練數(shù)據(jù)矩陣;

%輸出參數(shù):net,訓(xùn)練完成的卷積神經(jīng)網(wǎng)絡(luò)

%主要功能:使用當(dāng)前的神經(jīng)網(wǎng)絡(luò)對(duì)輸入的向量進(jìn)行預(yù)測(cè)

%算法流程:1)將樣本打亂,隨機(jī)選擇進(jìn)行訓(xùn)練;

% 2)講樣本輸入網(wǎng)絡(luò),層層映射得到預(yù)測(cè)值

%注意事項(xiàng):1)使用BP算法計(jì)算梯度

%%=========================================================================

function net = cnnff(net, x)

n = numel(net.layers); %層數(shù)

net.layers{1}.a{1} = x; %網(wǎng)絡(luò)的第一層就是輸入,但這里的輸入包含了多個(gè)訓(xùn)練圖像

inputmaps = 1; %輸入層只有一個(gè)特征map,也就是原始的輸入圖像

for l = 2 : n %對(duì)于每層(第一層是輸入層,循環(huán)時(shí)先忽略掉)

if strcmp(net.layers{l}.type, 'c') %如果當(dāng)前是卷積層

for j = 1 : net.layers{l}.outputmaps %對(duì)每一個(gè)輸入map,需要用outputmaps個(gè)不同的卷積核去卷積圖像

%%=========================================================================

%主要功能:創(chuàng)建outmap的中間變量,即特征矩陣

%實(shí)現(xiàn)步驟:用這個(gè)公式生成一個(gè)零矩陣,作為特征map

%注意事項(xiàng):1)對(duì)于上一層的每一張?zhí)卣鱩ap,卷積后的特征map的大小是:(輸入map寬 - 卷積核的寬 + 1)* (輸入map高 - 卷積核高 + 1)

% 2)由于每層都包含多張?zhí)卣鱩ap,則對(duì)應(yīng)的索引則保存在每層map的第三維,及變量Z中

%%=========================================================================

z = zeros(size(net.layers{l - 1}.a{1}) - [net.layers{l}.kernelsize - 1 net.layers{l}.kernelsize - 1 0]);

for i = 1 : inputmaps %對(duì)于輸入的每個(gè)特征map

%%=========================================================================

%主要功能:將上一層的每一個(gè)特征map(也就是這層的輸入map)與該層的卷積核進(jìn)行卷積

%實(shí)現(xiàn)步驟:1)進(jìn)行卷積

% 2)加上對(duì)應(yīng)位置的基b,然后再用sigmoid函數(shù)算出特征map中每個(gè)位置的激活值,作為該層輸出特征map

%注意事項(xiàng):1)當(dāng)前層的一張?zhí)卣鱩ap,是用一種卷積核去卷積上一層中所有的特征map,然后所有特征map對(duì)應(yīng)位置的卷積值的和

% 2)有些論文或者實(shí)際應(yīng)用中,并不是與全部的特征map鏈接的,有可能只與其中的某幾個(gè)連接

%%=========================================================================

z = z + convn(net.layers{l - 1}.a{i}, net.layers{l}.k{i}{j}, 'valid');

end

net.layers{l}.a{j} = sigm(z + net.layers{l}.b{j}); %加基(加上加性偏置b)

end

inputmaps = net.layers{l}.outputmaps; %更新當(dāng)前層的map數(shù)量;

elseif strcmp(net.layers{l}.type, 's') %如果當(dāng)前層是下采樣層

for j = 1 : inputmaps

%%=========================================================================

%主要功能:對(duì)特征map進(jìn)行下采樣

%實(shí)現(xiàn)步驟:1)進(jìn)行卷積

% 2)最終pooling的結(jié)果需要從上面得到的卷積結(jié)果中以scale=2為步長(zhǎng),跳著把mean pooling的值讀出來(lái)

%注意事項(xiàng):1)例如我們要在scale=2的域上面執(zhí)行mean pooling,那么可以卷積大小為2*2,每個(gè)元素都是1/4的卷積核

% 2)因?yàn)閏onvn函數(shù)的默認(rèn)卷積步長(zhǎng)為1,而pooling操作的域是沒(méi)有重疊的,所以對(duì)于上面的卷積結(jié)果

% 3)是利用卷積的方法實(shí)現(xiàn)下采樣

%%=========================================================================

z = convn(net.layers{l - 1}.a{j}, ones(net.layers{l}.scale) / (net.layers{l}.scale ^ 2), 'valid');

net.layers{l}.a{j} = z(1 : net.layers{l}.scale : end, 1 : net.layers{l}.scale : end, :); %跳讀mean pooling的值

end

end

end

%%=========================================================================

%主要功能:輸出層,將最后一層得到的特征變成一條向量,作為最終提取得到的特征向量

%實(shí)現(xiàn)步驟:1)獲取倒數(shù)第二層中每個(gè)特征map的尺寸

% 2)用reshape函數(shù)將map轉(zhuǎn)換為向量的形式

% 3)使用sigmoid(W*X + b)函數(shù)計(jì)算樣本輸出值,放到net成員o中

%注意事項(xiàng):1)在使用sigmoid()函數(shù)是,是同時(shí)計(jì)算了batchsize個(gè)樣本的輸出值

%%=========================================================================

net.fv = []; %net.fv為神經(jīng)網(wǎng)絡(luò)倒數(shù)第二層的輸出map

for j = 1 : numel(net.layers{n}.a) %最后一層的特征map的個(gè)數(shù)

sa = size(net.layers{n}.a{j}); %第j個(gè)特征map的大小

net.fv = [net.fv; reshape(net.layers{n}.a{j}, sa(1) * sa(2), sa(3))];

end

net.o = sigm(net.ffW * net.fv + repmat(net.ffb, 1, size(net.fv, 2))); %通過(guò)全連接層的映射得到網(wǎng)絡(luò)的最終預(yù)測(cè)結(jié)果輸出

end

深度學(xué)習(xí)Matlab工具箱代碼注釋——cnnbp.m

%%=========================================================================

%函數(shù)名稱:cnnbp()

%輸入?yún)?shù):net,呆訓(xùn)練的神經(jīng)網(wǎng)絡(luò);y,訓(xùn)練樣本的標(biāo)簽,即期望輸出

%輸出參數(shù):net,經(jīng)過(guò)BP算法訓(xùn)練得到的神經(jīng)網(wǎng)絡(luò)

%主要功能:通過(guò)BP算法訓(xùn)練神經(jīng)網(wǎng)絡(luò)參數(shù)

%實(shí)現(xiàn)步驟:1)將輸出的殘差擴(kuò)展成與最后一層的特征map相同的尺寸形式

% 2)如果是卷積層,則進(jìn)行上采樣

% 3)如果是下采樣層,則進(jìn)行下采樣

% 4)采用誤差傳遞公式對(duì)靈敏度進(jìn)行反向傳遞

%注意事項(xiàng):1)從最后一層的error倒推回來(lái)deltas,和神經(jīng)網(wǎng)絡(luò)的BP十分相似,可以參考“UFLDL的反向傳導(dǎo)算法”的說(shuō)明

% 2)在fvd里面保存的是所有樣本的特征向量(在cnnff.m函數(shù)中用特征map拉成的),所以這里需要重新?lián)Q回來(lái)特征map的形式,

% d保存的是delta,也就是靈敏度或者殘差

% 3)net.o .* (1 - net.o))代表輸出層附加的非線性函數(shù)的導(dǎo)數(shù),即sigm函數(shù)的導(dǎo)數(shù)

%%=========================================================================

function net = cnnbp(net, y)

n = numel(net.layers); %網(wǎng)絡(luò)層數(shù)

net.e = net.o - y; %實(shí)際輸出與期望輸出之間的誤差

net.L = 1/2* sum(net.e(:) .^ 2) / size(net.e, 2); %代價(jià)函數(shù),采用均方誤差函數(shù)作為代價(jià)函數(shù)

net.od = net.e .* (net.o .* (1 - net.o)); %輸出層的靈敏度或者殘差,(net.o .* (1 - net.o))代表輸出層的激活函數(shù)的導(dǎo)數(shù)

net.fvd = (net.ffW' * net.od); %殘差反向傳播回前一層,net.fvd保存的是殘差

if strcmp(net.layers{n}.type, 'c') %只有卷積層采用sigm函數(shù)

net.fvd = net.fvd .* (net.fv .* (1 - net.fv)); %net.fv是前一層的輸出(未經(jīng)過(guò)simg函數(shù)),作為輸出層的輸入

end

%%%%%%%%%%%%%%%%%%%%將輸出的殘差擴(kuò)展成與最后一層的特征map相同的尺寸形式%%%%%%%%%%%%%%%%%%%%

sa = size(net.layers{n}.a{1}); %最后一層特征map的大小。這里的最后一層都是指輸出層的前一層

fvnum = sa(1) * sa(2); %因?yàn)槭菍⒆詈笠粚犹卣鱩ap拉成一條向量,所以對(duì)于一個(gè)樣本來(lái)說(shuō),特征維數(shù)是這樣

for j = 1 : numel(net.layers{n}.a) %最后一層的特征map的個(gè)數(shù)

net.layers{n}.d{j} = reshape(net.fvd(((j - 1) * fvnum + 1) : j * fvnum, :), sa(1), sa(2), sa(3));

end

for l = (n - 1) : -1 : 1 %對(duì)于輸出層前面的層(與輸出層計(jì)算殘差的方式不同)

if strcmp(net.layers{l}.type, 'c') %如果是卷積層,則進(jìn)行上采樣

for j = 1 : numel(net.layers{l}.a) %該層特征map的個(gè)數(shù)

%%=========================================================================

%主要功能:卷積層的靈敏度誤差傳遞

%注意事項(xiàng):1)net.layers{l}.d{j} 保存的是 第l層 的 第j個(gè) map 的 靈敏度map。 也就是每個(gè)神經(jīng)元節(jié)點(diǎn)的delta的值

% expand的操作相當(dāng)于對(duì)l+1層的靈敏度map進(jìn)行上采樣。然后前面的操作相當(dāng)于對(duì)該層的輸入a進(jìn)行sigmoid求導(dǎo)

% 這條公式請(qǐng)參考 Notes on Convolutional Neural Networks

%%=========================================================================

net.layers{l}.d{j} = net.layers{l}.a{j} .* (1 - net.layers{l}.a{j}) .* (expand(net.layers{l + 1}.d{j}, [net.layers{l + 1}.scale net.layers{l + 1}.scale 1]) / net.layers{l + 1}.scale ^ 2);

end

elseif strcmp(net.layers{l}.type, 's') %如果是下采樣層,則進(jìn)行下采樣

%%=========================================================================

%主要功能:下采樣層的靈敏度誤差傳遞

%注意事項(xiàng):1)這條公式請(qǐng)參考 Notes on Convolutional Neural Networks

%%=========================================================================

for i = 1 : numel(net.layers{l}.a) %第i層特征map的個(gè)數(shù)

z = zeros(size(net.layers{l}.a{1}));

for j = 1 : numel(net.layers{l + 1}.a) %第l+1層特征map的個(gè)數(shù)

z = z + convn(net.layers{l + 1}.d{j}, rot180(net.layers{l + 1}.k{i}{j}), 'full');

end

net.layers{l}.d{i} = z;

end

end

end

%%=========================================================================

%主要功能:計(jì)算梯度

%實(shí)現(xiàn)步驟:

%注意事項(xiàng):1)這里與Notes on Convolutional Neural Networks中不同,這里的子采樣層沒(méi)有參數(shù),也沒(méi)有

% 激活函數(shù),所以在子采樣層是沒(méi)有需要求解的參數(shù)的

%%=========================================================================

for l = 2 : n

if strcmp(net.layers{l}.type, 'c')

for j = 1 : numel(net.layers{l}.a)

for i = 1 : numel(net.layers{l - 1}.a)

%%%%%%%%%%%%%%%%%%%%dk保存的是誤差對(duì)卷積核的導(dǎo)數(shù)%%%%%%%%%%%%%%%%%%%%

net.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

%%%%%%%%%%%%%%%%%%%?保存的是誤差對(duì)于bias基的導(dǎo)數(shù)%%%%%%%%%%%%%%%%%%%%

net.layers{l}.db{j} = sum(net.layers{l}.d{j}(:)) / size(net.layers{l}.d{j}, 3);

end

end

end

%%%%%%%%%%%%%%%%%%%%最后一層perceptron的gradient的計(jì)算%%%%%%%%%%%%%%%%%%%%

net.dffW = net.od * (net.fv)' / size(net.od, 2);

net.dffb = mean(net.od, 2);

function X = rot180(X)

X = flipdim(flipdim(X, 1), 2);

end

end

深度學(xué)習(xí)Matlab工具箱代碼注釋——cnnapplygrads.m

%%=========================================================================

%函數(shù)名稱:cnnapplygrads(),權(quán)值更新函數(shù)

%輸入?yún)?shù):net,權(quán)值待更新的卷積神經(jīng)網(wǎng)絡(luò);opts,神經(jīng)網(wǎng)絡(luò)訓(xùn)練的相關(guān)參數(shù)

%輸出參數(shù):

%算法流程:先更新卷積層的參數(shù),再更新全連接層參數(shù)

%注意事項(xiàng):

%%=========================================================================

function net = cnnapplygrads(net, opts)

for l = 2 : numel(net.layers)

if strcmp(net.layers{l}.type, 'c')

for j = 1 : numel(net.layers{l}.a)

for ii = 1 : numel(net.layers{l - 1}.a)

%這里沒(méi)什么好說(shuō)的,就是普通的權(quán)值更新的公式:W_new = W_old - alpha * de/dW(誤差對(duì)權(quán)值導(dǎo)數(shù))

net.layers{l}.k{ii}{j} = net.layers{l}.k{ii}{j} - opts.alpha * net.layers{l}.dk{ii}{j};

end

net.layers{l}.b{j} = net.layers{l}.b{j} - opts.alpha * net.layers{l}.db{j};

end

end

end

net.ffW = net.ffW - opts.alpha * net.dffW;

net.ffb = net.ffb - opts.alpha * net.dffb;

end

%%=========================================================================

% 主要功能:在mnist數(shù)據(jù)庫(kù)上做實(shí)驗(yàn),驗(yàn)證工具箱的有效性

% 算法流程:1)載入訓(xùn)練樣本和測(cè)試樣本

% 2)設(shè)置CNN參數(shù),并進(jìn)行訓(xùn)練

% 3)進(jìn)行檢測(cè)cnntest()

% 注意事項(xiàng):1)由于直接將所有測(cè)試樣本輸入會(huì)導(dǎo)致內(nèi)存溢出,故采用一次只測(cè)試一個(gè)訓(xùn)練樣本的測(cè)試方法

%%=========================================================================

%%

%%%%%%%%%%%%%%%%%%%%加載數(shù)據(jù)集%%%%%%%%%%%%%%%%%%%%

load mnist_uint8;

train_x = double(reshape(train_x',28,28,60000))/255;

test_x = double(reshape(test_x',28,28,10000))/255;

train_y = double(train_y');

test_y = double(test_y');

%%

%%=========================================================================

%%%%%%%%%%%%%%%%%%%%設(shè)置卷積神經(jīng)網(wǎng)絡(luò)參數(shù)%%%%%%%%%%%%%%%%%%%%

% 主要功能:訓(xùn)練一個(gè)6c-2s-12c-2s形式的卷積神經(jīng)網(wǎng)絡(luò),預(yù)期性能如下:

% 1)迭代一次需要200秒左右,錯(cuò)誤率大約為11%

% 2)迭代一百次后錯(cuò)誤率大約為1.2%

% 算法流程:1)構(gòu)建神經(jīng)網(wǎng)絡(luò)并進(jìn)行訓(xùn)練,以CNN結(jié)構(gòu)體的形式保存

% 2)用已知的訓(xùn)練樣本進(jìn)行測(cè)試

% 注意事項(xiàng):1)之前在測(cè)試的時(shí)候提示內(nèi)存溢出,后來(lái)莫名其妙的又不溢出了,估計(jì)到了系統(tǒng)的內(nèi)存臨界值

%%=========================================================================

rand('state',0)

cnn.layers = {

struct('type', 'i') %輸入層

struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %卷積層

struct('type', 's', 'scale', 2) %下采樣層

struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %卷積層

struct('type', 's', 'scale', 2) %下采樣層

};

cnn = cnnsetup(cnn, train_x, train_y);

opts.alpha = 1;

opts.batchsize = 50;

opts.numepochs = 5;

cnn = cnntrain(cnn, train_x, train_y, opts);

save CNN_5 cnn;

load CNN_5;

[er, bad] = cnntest(cnn, test_x, test_y);

figure; plot(cnn.rL);

assert(er<0.12, 'Too big error');



開(kāi)放分享:優(yōu)質(zhì)有限元技術(shù)文章,助你自學(xué)成才

相關(guān)標(biāo)簽搜索:深度學(xué)習(xí)Matlab工具箱DeepLearnToolbox代碼注釋(轉(zhuǎn)) MatLab培訓(xùn) MatLab培訓(xùn)課程 MatLab在線視頻教程 MatLab技術(shù)學(xué)習(xí)教程 MatLab軟件教程 MatLab資料下載 MatLab代做 MatLab基礎(chǔ)知識(shí) Fluent、CFX流體分析 HFSS電磁分析 Ansys培訓(xùn) Abaqus培訓(xùn) 

編輯
在線報(bào)名:
  • 客服在線請(qǐng)直接聯(lián)系我們的客服,您也可以通過(guò)下面的方式進(jìn)行在線報(bào)名,我們會(huì)及時(shí)給您回復(fù)電話,謝謝!
驗(yàn)證碼

全國(guó)服務(wù)熱線

1358-032-9919

廣州公司:
廣州市環(huán)市中路306號(hào)金鷹大廈3800
電話:13580329919
          135-8032-9919
培訓(xùn)QQ咨詢:點(diǎn)擊咨詢 點(diǎn)擊咨詢
項(xiàng)目QQ咨詢:點(diǎn)擊咨詢
email:kf@1cae.com