模式識別hw2-------基於matconvnet,用CNN實現人臉圖片性別識別
主要來源模式識別課程大作業,本文首先感謝當初的助教和一起完成作業的隊友
matconvnet在matlab下封裝了CNN常見演算法,網址http://www.vlfeat.org/matconvnet/,本文采用matconvnet-1.0-beta16.tar.gz
第一題: 運用matconvet提供的mnist網路結構,
通過train資料夾中人臉圖片訓練網路(訓練集),通過val資料夾調整網路結構(驗證集),最後通過test資料夾測試網路效能(測試集)
第一題: 設計一個神經網路,並與第一題比較
第一題
1.利用train和val資料夾進行訓練和調參:
利用matconvnet工具包中對mnist手寫數字體設計的cnn結構,識別人臉性別。主程式為“cnn_mnist.m”,而cnn結構初始化在“cnn_mnist_init.m”中完成,網路結構不需要重新設計,只需要在cnn_mnist.m中更改資料的輸入,在cnn_mnist_init.m更改網路的輸出。
對於本題資料集,“train”中圖片為訓練集,“val”中為驗證集,“test”中為測試集。首先利用“train”和“val”中人臉圖片訓練cnn網路權重,最後對訓練好的網路用“test”中資料進行測試。
本題主程式所在M檔案為“cnn_mnist_new.m”;網路結構檔案為“cnn_mnist_init_new.m”;“test_p1.m”為對訓練好的網路進行測試的主程式。
網路啟用函式,在預設情況下,預設為“sigmoid”。
首先在“cnn_mnist_init_new.m”中先拷貝“cnn_mnist.m”中程式碼,然後主要更改其中“getMnistImdb”函式。由於mnist資料集中的影像資料28*28 ,而本次實驗中,所用圖片大小為100*100 ,因此,需要把這些數字影像壓縮為28*28 。
函式“getMnistImdb”中變數“x1”儲存訓練集中的圖片,男性和女性的人臉圖片給300張,其前300維儲存男性,後300維儲存女性;而變數“y1”儲存訓練集對應的標籤,也是其前300維儲存男性,後300維儲存女性,這裡需要注意的是,matconvnet不能把類別標籤設定為“0”,否則對其他一些類別不能再識別;而本次作業為二分類問題,這裡,男性對應於標籤“1”,女性對應於標籤“2”。同理,“x2”和“y2”對應於驗證集中的資料,其中男性和女性圖片各80張。
作為說明,這裡只給出讀取訓練集資料中女性的示例程式碼:
%x1(:,:,1:300) stores female images in the train set
%x1(:,:,301:600) stores male images in the train set
x1=zeros(28,28,600);
%y1(1:300) stores female labels(1) in the train set
%y1(301:600) stores male labels(2) in the train set
y1=cat(2,ones(1,300),ones(1,300)+1);
%讀取訓練集圖片-female
img_file_path=fullfile(vl_rootnn,'examples\mnist\image\image\new\train\female');
img_dir=dir(img_file_path);
for i=1:length(img_dir)-2 filename=sprintf('%s\\%s\\fy.bmp',img_file_path,img_dir(i+2).name);
I=imread(filename);
I=imresize(I,[28,28]); %將圖片壓縮為28*28大小
x1(:,:,i)=I;
end
另外,為了防止過擬合,“cnn_mnist_init_new.m”中加入dropout,所謂“dropout”就是在訓練過程中,隨機讓一些節點不參與計算,加入方式為:
net.layers{end+1} = struct('type', 'dropout', 'rate', 0.5);
並且迭代次數設定為300,最重要的是,要把“softmaxloss”前一全連線層中神經元輸出節點改2,即:
net.layers{end+1} = struct('type', 'conv', ...
'weights', {{f*randn(1,1,500,2, 'single'), zeros(1,2,'single')}}, ...
'stride', 1, ...
'pad', 0) ;
執行“cnn_mnist_init_new.m”可以得到如下結果:
其中,“energy”訓練過程中訓練集和和驗證集的總的誤差能量之和;而“error”分別對應訓練集和驗證機的錯誤率,“top1err”是“softmax”層輸出過程中最高得分項對應錯誤率,而由於是二分類問題,“top5err”(前5項得分最高項對應錯誤率)是沒有意義的。
這裡需要說明一下,由於是二分類問題,最後分類器一般“logistic regression”,而“softmax”是“logistic regression”升級版,支援多分類問題。由於,我們網路最後是全連線到2個神經元上,其中“1”代表女性,“2”代表男性(需要注意的是,運用“softmax”,matconvnet類別標籤是不支援0的),並且通過“softmax”進行分類。2.利用 test資料夾測試:
“test_p1.m”是對已經訓練好的網路測試“test”資料夾下資料的主程式。測試集共265張圖片,其中男性56張,女性209張。讀取資料過程和“cnn_mnist_new.m”相似,這裡不再贅述。而載入網路主要過程:
train_imdb_path=fullfile(vl_rootnn,'\examples\mnist\problem1\problem-1-net-epoch\imdb.mat');
load(net_path);
net.layers{end}.type = 'softmax';
其中,“net_path”為網路所在檔案路徑,並且要主要載入網路之後,要把原來的“softmaxloss”改為“softmax”。並且處理測試集資料時候,要把測試集的資料減去訓練集的均值(因為訓練時候,預處理過程含有去均值的過程),其中,均值儲存在訓練集中的“imdb”結構體中,
示例程式碼如下:
test_set=single(test_set);
train_imdb_path=fullfile(vl_rootnn,'\examples\mnist\problem1\problem-1-net-epoch\imdb.mat');
train_imdb=load(train_imdb_path);
train_data_mean=train_imdb.images.data_mean;
test_set=bsxfun(@minus,test_set,train_data_mean);
而這個前向過程的輸出主要利用函式“vl_simplenn”,示例如下:
err_cnt=0;
best_scores=zeros(1,female_num+male_num);
err_id=zeros(1,female_num+male_num);
for i=1:(female_num+male_num)
res=vl_simplenn(net,test_set(:,:,i));
scores=squeeze(gather(res(end).x));
[best_score, best_id] = max(scores);
best_scores(i)=best_score;
if abs(str2double(net.meta.classes.name{best_id})-test_label(i))>1e-1;
err_cnt=err_cnt+1;
err_id(i)=1;
end
end
err_rate=err_cnt/(female_num+male_num);
執行test_p1.m檔案對網路進行測試。本檔案共重複10次實驗,實驗結果分佈如上所示。其中平均錯誤率為8.26%,最低錯誤率為6.79%。
第二題
1.利用train和val資料夾進行訓練和調參:
與第一題類似,“my_cnn.m”是訓練過程的主程式,“my_cnn_init.m”對應網路結構,“test_my_cnn.m” 為對訓練好的網路進行測試的主程式。讀取圖片資料與第一題類似,這裡不再贅述。
而“my_cnn_init.m”中網路結構對應為:
該網路通過卷積和池化降低維度,並且網路最後全連線到兩個神經元上,通過“softmax”進行分類。然後“relu”作為啟用函式,訓練時候一般需要"batch normalization"
核心程式碼如下:net.layers = {} ; %得到96*96 net.layers{end+1} = struct('type', 'conv', ... 'weights', {{f*randn(5,5,1,20, 'single'), zeros(1, 20, 'single')}}, ... 'stride', 1, ... 'pad', 0) ; net.layers{end+1} = struct('type', 'relu') ; %得到48*48 net.layers{end+1} = struct('type', 'pool', ... 'method', 'avg', ... 'pool', [2 2], ... 'stride', 1, ... 'pad', 0) ; net.layers{end+1} = struct('type', 'dropout', 'rate', 0.2); %得到44*44 net.layers{end+1} = struct('type', 'conv', ... 'weights', {{f*randn(5,5,10,20, 'single'),zeros(1,20,'single')}}, ... 'stride', 1, ... 'pad', 0) ; %得到22*22 net.layers{end+1} = struct('type', 'pool', ... 'method', 'avg', ... 'pool', [2 2], ... 'stride', 1, ... 'pad', 0) ; net.layers{end+1} = struct('type', 'dropout', 'rate', 0.2); %得到18*18 net.layers{end+1} = struct('type', 'conv', ... 'weights', {{f*randn(5,5,20,40, 'single'),zeros(1,40,'single')}}, ... 'stride', 1, ... 'pad', 0) ; net.layers{end+1} = struct('type', 'dropout', 'rate', 0.2); %得到9*9 net.layers{end+1} = struct('type', 'conv', ... 'weights', {{f*randn(5,5,40,100, 'single'), zeros(1,100,'single')}}, ... 'stride', 1, ... 'pad', 0) ; net.layers{end+1} = struct('type', 'relu') ; %得到5*5 net.layers{end+1} = struct('type', 'conv', ... 'weights', {{f*randn(5,5,100,100, 'single'), zeros(1,100,'single')}}, ... 'stride', 1, ... 'pad', 0) ; net.layers{end+1} = struct('type', 'relu') ; %得到1*1 net.layers{end+1} = struct('type', 'conv', ... 'weights', {{f*randn(5,5,100,2, 'single'), zeros(1,2,'single')}}, ... 'stride', 1, ... 'pad', 0) ; net.layers{end+1} = struct('type', 'softmaxloss') ;
執行“my_cnn.m”可以得到如下結果:
觀察上圖可知,當訓練次數為第222次時,該網路對val集達到了最低預測錯誤率,大約為7%。其後有細微的上升趨勢。故在下文中選擇第222次網路結果進行test集的測試。
2.利用 test資料夾測試:
“test_p2.m”是對已經訓練好的網路測試“test”資料夾下資料的主程式。測試集共265張圖片,其中男性56張,女性209張。載入網路主要過程:
train_imdb_path=fullfile(vl_rootnn,'\examples\mnist\problem2\problem-2-net-epoch\imdb.mat');
train_imdb=load(train_imdb_path);
net_path=fullfile(vl_rootnn, '\examples\mnist\problem2\problem-2-net-epoch\','net-epoch-222.mat') ;
load(net_path);
net.layers{end}.type = 'softmax';
利用函式“vl_simplenn”進行預測,本部分同問題一,故不再複述。
執行test_p2.m檔案對網路進行測試。本檔案共重複10次實驗,實驗結果分佈如上所示。其中平均錯誤率為7.85%,最低錯誤率為4.53%。
一些思考:
在完成第一題的時候,除了利用imresize函式對影像進行縮放外,我們還試圖對影像進行分塊處理,如將100*100的影像分割為16張28*28的子圖,如下所示:
然後再對子圖進行cnn訓練,但是效果並不理想,甚至訓練過程都不收斂:
分析這個現象的原因,我們認為,人臉影像並不能分割為子塊。當分割為子塊時,人臉不再是人臉,而只是各個部分離散的多張圖片,其中男女影像各個部分高度相似。甚至我們人類在判別的時候也不能分清一個子圖屬於男還是屬於女。如下圖第1排的第1張圖片,我們很難判斷該子圖屬於女性。
影像的分割,造成了資訊的丟失,部分之和再也不能代替整體!
為何28*28與100*100的精度近似相等
觀察下圖,左為第一題訓練結果,右為第二題訓練結果。可以看到,28*28與100*100大小的圖片經過cnn訓練後,對男女性別的判斷,在精度上近似相等。
究其原因,我們認為,圖片大小的改變對人類來說,並不影響判斷結果,丟失的資訊不足以影響二值化判斷。
相關文章
- 如何用Excel 9步實現CNN人臉識別ExcelCNN
- 基於Android平臺實現人臉識別Android
- [OpenCV實戰]1 基於深度學習識別人臉性別和年齡OpenCV深度學習
- TensorFlow2.0 + CNN + keras + 人臉識別CNNKeras
- opencv 人臉識別OpenCV
- OpenCV — 人臉識別OpenCV
- 【基於PCA的人臉識別演算法】從QR分解到PCA,再到人臉識別PCA演算法
- 【嚴肅臉】使用caffe實現色情圖片的識別
- 純前端實現人臉識別-提取-合成前端
- React 實現圖片識別AppReactAPP
- matlab實現人臉識別(數學基礎原理)Matlab
- 人臉識別技術應用
- 機器學習實戰-SVM模型實現人臉識別機器學習模型
- 基於深度學習的人臉識別系統系列(Caffe+OpenCV+Dlib)——【六】設計人臉識別的識別類深度學習OpenCV
- 趣圖:臉部識別最快的實現
- 中國人臉識別產業鏈全景圖產業
- 人臉識別和手勢識別應用(face++)開發
- 人臉識別與人體動作識別技術及應用pdf
- 如何理解並實現一個簡單的人臉識別演算法(下):人臉識別演算法
- 圖片文字識別怎麼實現
- 基於mtcnn/facenet/tensorflow實現人臉識別登入系統CNN
- 人臉識別之人臉檢測的重要性
- 基於開源模型搭建實時人臉識別系統(五):人臉跟蹤模型
- 基於開源模型搭建實時人臉識別系統(四):人臉質量模型
- 2.CNN圖片多標籤分類(基於TensorFlow實現驗證碼識別OCR)CNN
- C#人臉識別入門篇-STEP BY STEP人臉識別--入門篇C#
- 智慧人臉識別門禁系統開發,人臉識別開鎖流程
- 基於二哈實現多人人臉學習和識別
- Java 基於ArcFace人臉識別2.0 服務端DemoJava服務端
- 【專案】Python人臉識別(GUI介面)—— 基於pyopencvPythonGUIOpenCV
- 人臉檢測識別,人臉檢測,人臉識別,離線檢測,C#原始碼C#原始碼
- 妙招:使用Python實現圖片在人臉識別並顯示Python
- 開箱即用的JAVA AI平臺AI合集包含旦不僅限於(人臉識別、車牌識別、安全帽識別、開門關門、常用類物識別等) 圖片和影片識別JavaAI
- 人臉識別技術,讓科幻成為現實
- 如何免費識別圖片文字?圖片文字識別軟體怎麼用
- AI大模型實現圖片OCR識別AI大模型
- FS2K人臉素描屬性識別
- 手把手教你用 1 行命令實現人臉識別