引言
本文主要以O(shè)RL_64x64人臉數(shù)據(jù)庫識(shí)別為例衔峰,介紹如何使用基于matlab的CDBN工具箱炕婶。至于卷積深度置信網(wǎng)絡(luò)(CDBN,Convolutional Deep Belief Network)的理論知識(shí),只給出筆者整理的一些學(xué)習(xí)資源申窘。
卷積深度置信網(wǎng)絡(luò)理論知識(shí)
參考以下學(xué)習(xí)資料
- CSDN博客---受限玻爾茲曼機(jī)(RBM)學(xué)習(xí)筆記
- CSDN博客---深度信念網(wǎng)絡(luò)(Deep Belief Network)
- 知乎---卷積神經(jīng)網(wǎng)絡(luò)工作原理直觀的解釋
- 量子位公眾號(hào)---一文了解各種卷積結(jié)構(gòu)原理及優(yōu)劣
- 中國知網(wǎng)博碩論文---基于卷積深度置信網(wǎng)絡(luò)的歌手識(shí)別
- CDBN paper(全英)
CDBN工具箱簡介
據(jù)筆者了解砸泛,目前十籍,比較流行的深度學(xué)習(xí)框架,如TensorFlow唇礁、DeepLearning4j等不支持CDBN勾栗。GitHub上有基于Matlab的CDBN工具箱:CDBN工具箱下載鏈接
下面簡要介紹該工具箱。
從GitHub上下載的壓縮包解壓后再打開盏筐,文件目錄如下:
其中围俘,最為重要的肯定是toolbox。toolbox里面有三個(gè)lib,分別是CDBN琢融,DBN界牡,Softmax庫。本文將用到CDBN和Softmax兩個(gè)庫漾抬。
需要注意的是宿亡,由于這個(gè)工具箱不是官方版的,因此可能存在某些bug纳令,后面會(huì)涉及到筆者使用工具箱過程中的一些經(jīng)驗(yàn)挽荠。
神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)
介紹一下本文搭建的進(jìn)行人臉識(shí)別的卷積深度置信網(wǎng)絡(luò)的結(jié)構(gòu)克胳。
主體結(jié)構(gòu):兩個(gè)卷積受限玻爾茲曼機(jī)(CRBM,Convolutional Restricted Boltzmann Machine)堆疊(每個(gè)CRBM后都接有池化層)圈匆,頂層采用Softmax漠另,實(shí)現(xiàn)分類。
第一個(gè)CRBM:
- 第二個(gè)CRBM:
Softmax層
神經(jīng)元個(gè)數(shù)40個(gè)臭脓,最大迭代次數(shù)maxIter=1000酗钞,代價(jià)函數(shù)為交叉熵代價(jià)函數(shù)(Cross-Entropy Error)其他參數(shù)
其他諸如學(xué)習(xí)速率等的參數(shù)使用CDBN-master\toolbox\CDBNLIB\default_layer2D.m中的默認(rèn)值。
編程
以下講解編程步驟来累。
步驟一:安裝工具箱
只需運(yùn)行setup_toolbox.m即可砚作。
安裝工具箱其實(shí)只是把用到的一些函數(shù)添加到matlab的搜索路徑,因此你完全可以把工具箱內(nèi)所有的文件都復(fù)制到你當(dāng)前的路徑下嘹锁,不過肯定麻煩啦葫录!步驟二:加載和矩陣化數(shù)據(jù)
%load data
dataFortrain=load('ORL_64x64\StTrainFile1.txt');%注意修改路徑
train_data=dataFortrain(:,1:end-1)';%訓(xùn)練樣本
train_data=reshape(train_data,[64,64,1,360]);%矩陣化訓(xùn)練樣本
trainL=dataFortrain(:,end);%訓(xùn)練樣本標(biāo)簽
dataFortest=load('ORL_64x64\StTestFile1.txt');%注意修改路徑
test_data=dataFortest(:,1:end-1)';%測(cè)試樣本
test_data=reshape(test_data,[64,64,1,40]);%注意修改路徑
testL=dataFortest(:,end);%測(cè)試樣本標(biāo)簽
重點(diǎn)講一下第四行。
StTrainFile1.txt中有360行领猾,4097列米同。每一行是一幅人臉圖像(像素為64X64=4096)的4096個(gè)灰度值,最后一列是該幅人臉圖像的標(biāo)簽(1-40)摔竿,表明其屬于哪個(gè)人的(共40人面粮,即分類數(shù)目為40)。由此可見继低,一幅二維圖像(矩陣)被拉成了向量進(jìn)行存儲(chǔ)熬苍,因此在數(shù)據(jù)輸入CDBN前,我們要對(duì)向量進(jìn)行矩陣化袁翁,調(diào)用matlab的reshape方法柴底,最終生成一個(gè)4維的矩陣,四個(gè)維度分別是64,64,1,360(樣本數(shù))粱胜。倒數(shù)第二行同理柄驻。
- 步驟三:定義層參數(shù)
工具箱把一層layer定義為一個(gè)struct對(duì)象。
%INITIALIZE THE PARAMETERS OF THE NETWORK
%first layer setting
layer{1} = default_layer2D();
layer{1}.inputdata=train_data;%輸入訓(xùn)練樣本
layer{1}.n_map_v=1;
layer{1}.n_map_h=9;
layer{1}.s_filter=[7 7];
layer{1}.stride=[1 1];
layer{1}.s_pool=[2 2];
layer{1}.batchsize=90;
layer{1}.n_epoch=1;
%second layer setting
layer{2} = default_layer2D();
layer{2}.n_map_v=9;
layer{2}.n_map_h=16;
layer{2}.s_filter=[5 5];
layer{2}.stride=[1 1];
layer{2}.s_pool=[2 2];
layer{2}.batchsize=10;
layer{2}.n_epoch=1;
需要注意的是焙压,layer{i}=default_layer2D()這條語句是必須的鸿脓,且必須位于所有層參數(shù)定義語句的最前面。原因:如果layer{i}=default_layer2D()這條語句不位于最前面的話涯曲,在這條語句前面的參數(shù)賦值語句實(shí)質(zhì)不起作用答憔,這些參數(shù)還是取默認(rèn)值。特別是對(duì)于第一層掀抹,因?yàn)閐efault_layer2D()方法中是沒有定義inputdata字段的虐拓,如果layer{1}.inputdata=train_data這條語句位于layer{1}=default_layer2D()前面,則會(huì)出現(xiàn)“使用未定義字段”的錯(cuò)誤傲武。
補(bǔ)充:要注意根據(jù)自己使用的數(shù)據(jù)集的情況設(shè)定層的輸入類型蓉驹,對(duì)[0,1]之間的數(shù)據(jù)集城榛,應(yīng)該使用二值神經(jīng)網(wǎng)絡(luò),設(shè)定 layer{i}.type_input = 'Binary'(程序默認(rèn));其他數(shù)據(jù)集态兴,應(yīng)該設(shè)為layer{i}.type_input = 'Gaussian';至于二者的區(qū)別狠持,自行百度,這里不展開了瞻润。
- 步驟四:訓(xùn)練CDBN網(wǎng)絡(luò)
這個(gè)過程是無監(jiān)督學(xué)習(xí)喘垂,只需調(diào)用cdbn2D方法即可。
在調(diào)用cdbn2D方法之前绍撞,CDBN-master\toolbox\CDBNLIB\mex中的crbm_forward2D_batch_mex.c要先用mex命令編譯生成crbm_forward2D_batch_mex.mexw64文件才能供matlab調(diào)用
mex crbm_forward2D_batch_mex.c
在編譯前正勒,crbm_forward2D_batch_mex.c要先修改:128行的out_id要改成在最開始的位置定義,否則編譯時(shí)會(huì)出現(xiàn)“缺少:在類型前面’”的報(bào)錯(cuò)信息(PS:第一次遇到這么奇葩的報(bào)錯(cuò)傻铣,當(dāng)時(shí)懷疑C語言是不是白學(xué)了)章贞,原因:VS2010的C編譯器只支持C89標(biāo)準(zhǔn),對(duì)C99標(biāo)準(zhǔn)支持不完全非洲,而在C89標(biāo)準(zhǔn)中鸭限,變量需要放到函數(shù)體的前面聲明,先聲明再使用两踏。
%% ----------- GO TO 2D CONVOLUTIONAL DEEP BELIEF NETWORKS ------------------%%
tic;
[model,layer] = cdbn2D(layer);
save('model_parameter','model','layer');
toc;
trainD = model{1}.output;%訓(xùn)練樣本的第一個(gè)CRBM的輸出败京,是一個(gè)4維矩陣
trainD1 = model{2}.output;%訓(xùn)練樣本的第二個(gè)CRBM的輸出,是一個(gè)4維矩陣
我們來比較一下train_data梦染、trainD喧枷、trainD1的大小
現(xiàn)在再看看卷積神經(jīng)網(wǎng)絡(luò)的圖示,是不是很好理解了呢车荔?
- 步驟五:將測(cè)試樣本輸入訓(xùn)練好的CDBN網(wǎng)絡(luò)渡冻,提取高維特征
這段代碼可以直接copy,修改好變量名即可忧便!
%% ------------ TESTDATA FORWARD MODEL WITH THE PARAMETERS ------------------ %%
% FORWARD MODEL OF NETWORKS
H = length(layer);
layer{1}.inputdata = test_data;
fprintf('output the testdata features:>>...\n');
tic;
if H >= 2
% PREPROCESSS INPUTDATA TO BE SUITABLE FOR TRAIN
layer{1} = preprocess_train_data2D(layer{1});
model{1}.output = crbm_forward2D_batch_mex(model{1},layer{1},layer{1}.inputdata);
for i = 2:H
layer{i}.inputdata = model{i-1}.output;
layer{i} = preprocess_train_data2D(layer{i});
model{i}.output = crbm_forward2D_batch_mex(model{i},layer{i},layer{i}.inputdata);
end
else
layer{1} = preprocess_train_data2D(layer{1});
model{1}.output = crbm_forward2D_batch_mex(model{1},layer{1},layer{1}.inputdata);
end
testD = model{1}.output;%訓(xùn)練樣本的第一個(gè)CRBM的輸出族吻,是一個(gè)4維矩陣
testD1 = model{2}.output;%訓(xùn)練樣本的第二個(gè)CRBM的輸出,是一個(gè)4維矩陣
toc;
同樣的寇窑,我們來看一下test_data钠糊、testD补胚、testD1的大小:
- 步驟六:訓(xùn)練Softmax分類器凝垛,同時(shí)進(jìn)行識(shí)別
這里我們用到 softmaxExercise(inputData,labels,inputData_t,labels_t)這個(gè)函數(shù)
參數(shù)說明:
- inputdata:訓(xùn)練樣本的CDBN輸出懊悯,要求是二維矩陣
-labels:訓(xùn)練樣本的標(biāo)簽
-inputData_t:測(cè)試樣本的CDBN輸出蜓谋,要求是二維矩陣
-labels_t:測(cè)試樣本的標(biāo)簽
由于CDBN的輸出是4維矩陣,因此在訓(xùn)練Softmax分類器前炭分,需要把矩陣?yán)上蛄浚ê椭暗倪^程相反)桃焕。代碼如下,可直接copy捧毛,修改變量名即可观堂!
%% ------------------------------- Softmax ---------------------------------- %%
fprintf('train the softmax:>>...\n');
tic;
% TRANSLATE THE OUTPUT TO ONE VECTOR
trainDa = [];
trainLa=trainL;
for i= 1:size(trainD,4)
a1 = [];
a2 = [];
a3 = [];
for j = 1:size(trainD,3)
a1 = [a1;reshape(trainD(:,:,j,i),size(trainD,2)*size(trainD,1),1)];
end
for j = 1:size(trainD1,3)
a2 = [a2;reshape(trainD1(:,:,j,i),size(trainD1,2)*size(trainD1,1),1)];
end
a3 = [a3;a1;a2];
trainDa = [trainDa,a3];
end
testDa = [];
testLa=testL;
for i= 1:size(testD,4)
b1 = [];
b2 = [];
b3 = [];
for j = 1:size(testD,3)
b1 = [b1;reshape(testD(:,:,j,i),size(testD,2)*size(testD,1),1)];
end
for j =1:size(testD1,3)
b2 = [b2;reshape(testD1(:,:,j,i),size(testD1,2)*size(testD1,1),1)];
end
b3 = [b3;b1;b2];
testDa = [testDa,b3];
end
我們來看一下拉成向量后的trainDa以及testDa的大小
對(duì)比一下,train_data和test_data在矩陣化之前的大醒接恰:
可見师痕,CDBN作為特征提取器,將4096維特征映射到了9873維特征荐虐,提高了Softmax的分類能力七兜!
softmaxExercise.m中有這樣一段注釋:
因此在調(diào)用softmaxExercise方法前,要做以下4個(gè)工作:
- 修改softmaxExercise.m第22行的numClasses福扬,如本文改為40
- 修改softmaxExercise.m第96行的maxIter腕铸,本文取1000
PS:個(gè)人覺得softmaxExercise方法應(yīng)該增加兩個(gè)入口參數(shù),即numClasses和maxIter铛碑,如此才能更好體現(xiàn)封裝的思想狠裹。
- softmaxCost.m中定義需要的損失函數(shù),只需要改第90行
cost = -(1. / numCases) * sum(sum(groundTruth .* log(p))) + (lambda / 2.) * sum(sum(theta.^2));
這條語句即可汽烦,原文件使用的是交叉熵代價(jià)函數(shù)涛菠。
- 有必要的話可以修改 softmaxPredict.m中內(nèi)容,個(gè)人覺得完全沒必要撇吞,保留即可俗冻。
最后調(diào)用softmaxExercise方法
softmaxExercise(trainDa,trainLa,testDa,testLa);
toc;
完整代碼
FaceRecognitionDemo.m
clear;
%load data
dataFortrain=load('ORL_64x64\StTrainFile1.txt');
train_data=dataFortrain(:,1:end-1)';
train_data=reshape(train_data,[64,64,1,360]);
trainL=dataFortrain(:,end);
dataFortest=load('ORL_64x64\StTestFile1.txt');
test_data=dataFortest(:,1:end-1)';
test_data=reshape(test_data,[64,64,1,40]);
testL=dataFortest(:,end);
%INITIALIZE THE PARAMETERS OF THE NETWORK
%first layer setting
layer{1} = default_layer2D();
layer{1}.inputdata=train_data;
layer{1}.n_map_v=1;
layer{1}.n_map_h=9;
layer{1}.s_filter=[7 7];
layer{1}.stride=[1 1];
layer{1}.s_pool=[2 2];
layer{1}.batchsize=90;
layer{1}.n_epoch=1;
%second layer setting
layer{2} = default_layer2D();
layer{2}.n_map_v=9;
layer{2}.n_map_h=16;
layer{2}.s_filter=[5 5];
layer{2}.stride=[1 1];
layer{2}.s_pool=[2 2];
layer{2}.batchsize=10;
layer{2}.n_epoch=1;
%% ----------- GO TO 2D CONVOLUTIONAL DEEP BELIEF NETWORKS ------------------ %%
tic;
[model,layer] = cdbn2D(layer);
save('model_parameter','model','layer');
toc;
trainD = model{1}.output;
trainD1 = model{2}.output;
%% ------------ TESTDATA FORWARD MODEL WITH THE PARAMETERS ------------------ %%
% FORWARD MODEL OF NETWORKS
H = length(layer);
layer{1}.inputdata = test_data;
fprintf('output the testdata features:>>...\n');
tic;
if H >= 2
% PREPROCESSS INPUTDATA TO BE SUITABLE FOR TRAIN
layer{1} = preprocess_train_data2D(layer{1});
model{1}.output = crbm_forward2D_batch_mex(model{1},layer{1},layer{1}.inputdata);
for i = 2:H
layer{i}.inputdata = model{i-1}.output;
layer{i} = preprocess_train_data2D(layer{i});
model{i}.output = crbm_forward2D_batch_mex(model{i},layer{i},layer{i}.inputdata);
end
else
layer{1} = preprocess_train_data2D(layer{1});
model{1}.output = crbm_forward2D_batch_mex(model{1},layer{1},layer{1}.inputdata);
end
testD = model{1}.output;
testD1 = model{2}.output;
toc;
%% ------------------------------- Softmax ---------------------------------- %%
fprintf('train the softmax:>>...\n');
tic;
% TRANSLATE THE OUTPUT TO ONE VECTOR
trainDa = [];
trainLa=trainL;
for i= 1:size(trainD,4)
a1 = [];
a2 = [];
a3 = [];
for j = 1:size(trainD,3)
a1 = [a1;reshape(trainD(:,:,j,i),size(trainD,2)*size(trainD,1),1)];
end
for j = 1:size(trainD1,3)
a2 = [a2;reshape(trainD1(:,:,j,i),size(trainD1,2)*size(trainD1,1),1)];
end
a3 = [a3;a1;a2];
trainDa = [trainDa,a3];
end
testDa = [];
testLa=testL;
for i= 1:size(testD,4)
b1 = [];
b2 = [];
b3 = [];
for j = 1:size(testD,3)
b1 = [b1;reshape(testD(:,:,j,i),size(testD,2)*size(testD,1),1)];
end
for j =1:size(testD1,3)
b2 = [b2;reshape(testD1(:,:,j,i),size(testD1,2)*size(testD1,1),1)];
end
b3 = [b3;b1;b2];
testDa = [testDa,b3];
end
softmaxExercise(trainDa,trainLa,testDa,testLa);
toc;
運(yùn)行截圖及準(zhǔn)確率
97.5%的識(shí)別率,還是可以接受的牍颈,一方面是數(shù)據(jù)集好迄薄,另一方面是搭建得網(wǎng)絡(luò)好。
讀者可以試一試調(diào)整CDBN網(wǎng)絡(luò)的參數(shù)煮岁,比如增大epoch(本文取1)讥蔽,看能否獲得更高的識(shí)別率。
為了方便讀者研究画机,附上所有文件冶伞。
本Demo文件匯總下載鏈接(原鏈接失效,此為新版連接),提取碼:7f6i
以下是使用此工具箱的幾點(diǎn)提示:
- 原始工具箱只在LINUX系統(tǒng)測(cè)試過步氏,由于LINUX系統(tǒng)和WINDOWS系統(tǒng)的文件分隔符不同响禽,
因此DemoCDBN_Binary_2D.m的第83行、
cdbn2D.m的第15、24行金抡、 setup_toolbox.m的文件分隔符要修改瀑焦。 - 源程序存在bug,即若樣本個(gè)數(shù)不是batchsize的整數(shù)倍的話梗肝,會(huì)出錯(cuò)榛瓮,因此在此bug排除前,應(yīng)將batchsize設(shè)置為樣本數(shù)目的因數(shù)
- 類別標(biāo)簽不要用負(fù)數(shù)或0巫击,比如進(jìn)行二分類禀晓,標(biāo)簽不要設(shè)為-1和1,可以設(shè)為1和2坝锰,這是因?yàn)閟oftmaxCost.m文件中的第18行建立稀疏矩陣時(shí)會(huì)以標(biāo)簽作為矩陣的索引粹懒,如果設(shè)為0或負(fù)數(shù),肯定會(huì)報(bào)錯(cuò):矩陣索引必須為正數(shù)