卷積深度置信網(wǎng)絡(luò)工具箱的使用---人臉識(shí)別

引言

本文主要以O(shè)RL_64x64人臉數(shù)據(jù)庫(kù)識(shí)別為例,介紹如何使用基于matlab的CDBN工具箱。至于卷積深度置信網(wǎng)絡(luò)(CDBN,Convolutional Deep Belief Network)的理論知識(shí),只給出筆者整理的一些學(xué)習(xí)資源。

卷積深度置信網(wǎng)絡(luò)理論知識(shí)

參考以下學(xué)習(xí)資料

CDBN工具箱簡(jiǎn)介

據(jù)筆者了解,目前,比較流行的深度學(xué)習(xí)框架,如TensorFlow、DeepLearning4j等不支持CDBN。GitHub上有基于Matlab的CDBN工具箱:CDBN工具箱下載鏈接
下面簡(jiǎn)要介紹該工具箱。
從GitHub上下載的壓縮包解壓后再打開(kāi),文件目錄如下:

CDBN工具箱的文件目錄

其中,最為重要的肯定是toolbox。toolbox里面有三個(gè)lib,分別是CDBN,DBN,Softmax庫(kù)。本文將用到CDBN和Softmax兩個(gè)庫(kù)。

toolbox下的三個(gè)lib

需要注意的是,由于這個(gè)工具箱不是官方版的,因此可能存在某些bug,后面會(huì)涉及到筆者使用工具箱過(guò)程中的一些經(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參數(shù)
  • 第二個(gè)CRBM:
第二個(gè)CRBM參數(shù)
  • 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)前的路徑下,不過(guò)肯定麻煩啦!

  • 步驟二:加載和矩陣化數(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)。由此可見(jiàn),一幅二維圖像(矩陣)被拉成了向量進(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()這條語(yǔ)句是必須的,且必須位于所有層參數(shù)定義語(yǔ)句的最前面。原因:如果layer{i}=default_layer2D()這條語(yǔ)句不位于最前面的話,在這條語(yǔ)句前面的參數(shù)賦值語(yǔ)句實(shí)質(zhì)不起作用,這些參數(shù)還是取默認(rèn)值。特別是對(duì)于第一層,因?yàn)閐efault_layer2D()方法中是沒(méi)有定義inputdata字段的,如果layer{1}.inputdata=train_data這條語(yǔ)句位于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ū)別,自行百度,這里不展開(kāi)了。

  • 步驟四:訓(xùn)練CDBN網(wǎng)絡(luò)
    這個(gè)過(guò)程是無(wú)監(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要改成在最開(kāi)始的位置定義,否則編譯時(shí)會(huì)出現(xiàn)“缺少:在類型前面’”的報(bào)錯(cuò)信息(PS:第一次遇到這么奇葩的報(bào)錯(cuò),當(dāng)時(shí)懷疑C語(yǔ)言是不是白學(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維矩陣

我們來(lái)比較一下train_data、trainD、trainD1的大小

train_data、trainD、trainD1

現(xiàn)在再看看卷積神經(jīng)網(wǎng)絡(luò)的圖示,是不是很好理解了呢?

卷積神經(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;

同樣的,我們來(lái)看一下test_data、testD、testD1的大?。?/p>

test_data、testD、testD1的大小比較
  • 步驟六:訓(xùn)練Softmax分類器,同時(shí)進(jìn)行識(shí)別
    這里我們用到 softmaxExercise(inputData,labels,inputData_t,labels_t)這個(gè)函數(shù)
    參數(shù)說(shuō)明:
    - 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)上蛄浚ê椭暗倪^(guò)程相反)。代碼如下,可直接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

我們來(lái)看一下拉成向量后的trainDa以及testDa的大小

拉成向量后的trainDa以及testDa的大小

對(duì)比一下,train_data和test_data在矩陣化之前的大小:

train_data和test_data在矩陣化之前的大小

可見(jiàn),CDBN作為特征提取器,將4096維特征映射到了9873維特征,提高了Softmax的分類能力!

softmaxExercise.m中有這樣一段注釋:

softmaxExercise.m中的注釋

因此在調(diào)用softmaxExercise方法前,要做以下4個(gè)工作:

  • 修改softmaxExercise.m第22行的numClasses,如本文改為40
  • 修改softmaxExercise.m第96行的maxIter,本文取1000

PS:個(gè)人覺(jué)得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));

這條語(yǔ)句即可,原文件使用的是交叉熵代價(jià)函數(shù)。

  • 有必要的話可以修改 softmaxPredict.m中內(nèi)容,個(gè)人覺(jué)得完全沒(méi)必要,保留即可。

最后調(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)確率

運(yùn)行截圖1
運(yùn)行截圖2
運(yùn)行截圖3

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è)試過(guò),由于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ù)

over,接觸機(jī)器學(xué)習(xí)時(shí)間不是很長(zhǎng),文章有什么錯(cuò)誤,歡迎留言指正,謝謝!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容