基於支持向量機(SVM)的人臉識別

下定決心開始寫博客,希望能在寫博客的過程中,總結思路,加深理解。在這裏分享心得體會,共同進步。如有不足之處望批評指正。

本博客包含本人學習SVM和PCA的筆記,簡要的說明其原理和方法步奏,人臉識別程序的解釋說明,一併奉上完整的Matlab代碼和相關的學習資料。

感覺自己在這上面花了不少時間但停留在一個較淺層次的瞭解上,希望後面學習SVM的朋友們能少走彎路。本人才疏學淺,博客難免有錯漏,請見諒。如有轉載請註明出處。
廢話不多說,開始正文。

一. 支持向量機(SVM)

1.基本原理

給定訓練樣本集,在特徵空間上找到一個分離超平面,將樣本點分到不同的類。其中當且存在唯一的分類超平面,使得樣本點距離分類超平面的距離最大。其中,距離超平面最近的點爲該超平面的支持向量。

找到超平面後,對於待測點,通過計算該點相對於超平面的位置進行分類。其中,一個點距離分離超平面的距離越大,表示分類預測的確信程度越高。
線性可分的二類問題尋找間隔最大分離超平面
SVM的數學推導非常繁瑣,我個人瞭解得還不夠透徹,推薦去看李航編寫的《統計學習方法》,裏面的數學理論推導非常詳細。還有斯坦福大學的公開課《機器學習》,對這部分講解得深入淺出,非常推薦。

2.懲罰參數C

懲罰參數表示對誤分類點的懲罰權重。 如下圖所示,懲罰參數的設置相當與在訓練集的誤差和間隔平面的距離上做一個折衷選擇。當懲罰參數過大,如(a)易出現過擬合的情況,預測時,易導致誤分情況。減小懲罰參數,開始容忍樣本點落入間隔平面之內。過小會導致訓練集的樣本點對結果影響變小分類功能喪失。因此,選擇合適的懲罰參數,會大大提高分類器的性能,非常關鍵。 實際運用過程中,採用交叉驗證的方法選擇合適的參數C。

在這裏簡要的提一下交叉驗證(Cross Validation)的思想:即將所有的樣本分成:訓練集(train set),驗證集(validation set)和測試集(test set),合適的劃分比例如(3:3:4),使用不同的參數訓練樣本,在驗證集上驗證表現性能,得到一組最佳參數再應用在測試集上計算最終精度。此方法可大大減少因設置參數花費的時間。
懲罰參數C的應用示意圖

3.核函數

實際的訓練集通常是線性不可分的,這就需要運用到核技巧將原空間中的點映射到線性可分的高維空間。
支持向量機核函數的使用原理
常用的核函數有:線性核函數、多項式核函數、高斯核函數(RBF核函數),sigmoid核函數。
核函數的選擇對分類器的影響較大,但是怎樣選擇我還是隻能試,如果有核函數選擇的經驗,歡迎分享交流。

4.多分類支持向量機

實際分類通常涉及多類問題的區分,而SVM的理論是二類問題的區分,解決多類問題通常的方法如下,前兩種方法最常見:

  • 一對多(one-vs-rest)
    構造k個SVM,分類時將未知樣本分類爲具有最大分類值的那類。
  • 一對一(one-vs-one)
    任意兩個樣本之間設計一個SVM共n(n-1)/2,分類時爲得票最多的類。
  • 層次分類(H-SVMs)
    分層:所有類別分成子類,子類再分,循環得到單獨的類。

5.libsvm工具箱

libsvm是臺灣大學林智仁教授開發設計的一個簡單、快速有效的SVM模式識別和迴歸的軟件包,可在C、Java、Matlab、C#、Ruby、Python、R、Perl、Common LISP、Labview等數十種語言裏實現。提供了很多默認參數,使用起來非常方便。下面附上的SVM人臉識別程序在matlab上運行時要提前安裝好這個工具包,大大簡化程序。

下載地址: https://www.csie.ntu.edu.tw/~cjlin/libsvm/
libsvm的安裝教程:http://blog.csdn.net/loadstar_kun/article/details/7712308
注意:請確保先安裝好VS,推薦安裝VS2010 VS2012,並且Matlab的版本不能太低,如果先不匹配出現一些奇奇怪怪的原因導致安裝不成功,我曾經在這上面耗費很多時間最後只好放棄那臺電腦了。

二.主成分分析(PCA)

Principle Component Analysis,用於簡化數據的複雜性,極大的保留原始數據的特徵(差異大的特徵),用於降維處理,便於後續進一步計算和操作。
包含如下步驟:

  1. 去除平均值(中心化樣本)

    CenteredMatrix = OriginalMatrix-repmat(mean(OriginalMatrix),numPic,1);

  2. 計算協方差矩陣

    CovMatrix = CenteredMatrix’*CenteredMatrix;

  3. 計算協方差矩陣的特徵值和特徵向量

    [V,D]=eigs(CovMatrix,kdimension);
    (通常原始特徵維數可能比較高,爲避免協方差矩陣過於龐大的情況,協方差矩陣的特徵向量通過計算CenteredMatrix*CenteredMatrix’的特徵值和特徵向量來間接獲得)

  4. 將特徵值從大到小排序,保留前N個特徵向量(作爲新的低維空間的基)

  5. 將數據轉換到上述N個向量構成的新空間

    pcaMatrix = CenteredMatrix*V;

三. 人臉識別程序

本程序主要參考了博文:http://blog.csdn.net/yb536/article/details/40586695,並對其做了一些改動。

1. FaceRecognition.m主程序

將人臉圖像生成用於訓練和測試的矩陣,並分別生成相對的類別標籤矩陣,使用libsvm工具箱操作。

  • svmtrain
    model = svmtrain(train_label,train_data,option);
    option的可選項:

    1. -s svm類型:
      SVM設置類型(默認0) 0 – C-SVC 1 –v-SVC 2 – 一類SVM 3 – e -SVR 4 – v-SVR
      1. -t 核函數類型:核函數設置類型(默認2) 0 – 線性:u’v 1 – 多項式:(r*u’v + coef0)^degree 2 – RBF函數:exp(-r|u-v|^2) 3 –sigmoid:tanh(r*u’v + coef0)
      2. -d degree:核函數中的degree設置(默認3)
      3. -g r(gama):核函數中的函數設置(默認1/ k)
      4. -r coef0:核函數中的coef0設置(默認0)
      5. -c cost:設置C-SVC, -SVR和-SVR的參數(默認1)
      6. -n nu:設置-SVC,一類SVM和- SVR的參數(默認0.5)
      7. -p e:設置 -SVR 中損失函數的值(默認0.1)
      8. -m cachesize:設置cache內存大小,以MB爲單位(默認40)
      9. -e :設置允許的終止判據(默認0.001)
      10. -h shrinking:是否使用啓發式,0或1(默認1)
      11. -wi weight:設置第幾類的參數C爲weightC(C-SVC中的C)(默認1)
      12. -v n: n-fold交互檢驗模式,n爲折數,>2
  • svmpredict
    [predict_label,accuracy/mse,dec_value]=svmpredict(test_facelabel,scaled_testface,model);

說明:主程序運行後來註釋掉了交叉驗證那部分的代碼,以爲交叉驗證主要用於選取參數,通常遍歷可選範圍選取最優解,非常耗時。開始時運行那部分代碼,得到較好的參數後註釋掉,再把直接寫入svmtrain可節省實驗預測時間。

clc,clear  
npersons=40;%選取40個人的臉  
%%
%讀取訓練數據 
global picn; %picn存放隨機選擇的人臉號的索引
picn = randperm(10); %隨機從每個人的10張照片抽取p張作爲訓練集
disp('讀取訓練數據...')  
[f_matrix,train_label]=ReadFace(npersons,0);%讀取訓練數據  
nfaces=size(f_matrix,1);%樣本人臉的數量  
disp('.................................................')  
%低維空間的圖像是(nperson*5)*k的矩陣,每行代表一個主成分臉,每個臉k維特徵  
%對訓練集進行降維處理
%計算訓練時間
tic;
disp('訓練數據PCA特徵提取...')  
mA=mean(f_matrix);  
global k
k=35; %降維至 10 15 25 35 50 70 100維  
[train_pcaface,V]=fastPCA(f_matrix,k,mA);%主成分分析法特徵提取  
disp('.................................................')  
%顯示主成分臉,即特徵臉,低維的基
disp('顯示主成分臉...')  
%visualize(V)%顯示主分量臉  ,即特徵臉
disp('.................................................')  
%低維訓練集歸一化
disp('訓練特徵數據歸一化...')  
disp('.................................................')  
lowvec=min(train_pcaface);  
upvec=max(train_pcaface);  
train_scaledface = scaling( train_pcaface,lowvec,upvec);  

%SVM樣本訓練
disp('SVM樣本訓練...')  
disp('.................................................')  
%交叉驗證選擇合適的參數
%[bestacc,bestc,bestg] = SVMcgForClass(train_label,train_scaledface,-2,4,-2,2,3,0.25,0.25,0.5);
%選擇線性核函數,懲罰參數設置爲0.5 0.7 1 1.2 1.5 2.0
model = svmtrain(train_label,train_scaledface,'-s 0 -t 0 -c 1.2');
toc;
disp('讀取測試數據...')  
disp('.................................................')  
[test_facedata,test_facelabel]=ReadFace(npersons,1);  
%測試數據降維
disp('測試數據特徵降維...')  
disp('.................................................')  
m=size(test_facedata,1);  
for i=1:m  
    test_facedata(i,:)=test_facedata(i,:)-mA;  
end  
test_pcatestface=test_facedata*V;  
disp('測試特徵數據歸一化...')  
disp('.................................................')  
scaled_testface = scaling( test_pcatestface,lowvec,upvec);  
%利用訓練集建立的模型,對測試集進行分類
disp('SVM樣本分類...')  
disp('.................................................')  
[predict_label,accuracy,decision_values]=svmpredict(test_facelabel,scaled_testface,model); %輸出預測結果計算分類精度

2.ReadFace.m函數

這裏使用的是Orl的人臉庫,共40個人,每個人10張臉共400張樣本圖。

function [f_matrix,realclass]=ReadFace(n_persons,flag)
global picn;
imgrow=112;
imgcol=92;   %輸入人臉圖片的尺寸
np = 5;   %np=3,4,5作爲測試集
if flag==0
    nn=np;
else
    nn=10-np;
end
realclass=zeros(n_persons*nn,1);
f_matrix=zeros(n_persons*nn,imgrow*imgcol);
for i=1:n_persons
    %路徑設置
    %函數num2str(i)說明:將數字轉化爲字符
    %路徑因不同情況而定
    facepath=strcat('E:\Program\imageData\faceImage\orlData\',num2str(i),'\');  
    cachepath=facepath;
    for j=1:nn
        facepath=cachepath;
        if flag==0
            %前np個樣本作爲訓練集
            facepath=strcat(facepath,num2str(picn(j)));
        else
            %後10-np個樣本作爲測試集
            facepath=strcat(facepath,num2str(picn(j+np)));
        end
        realclass((i-1)*nn+j)=i;
        facepath=strcat(facepath,'.pgm');
        %函數imread說明:讀取輸入路徑的圖片,將每個像素灰度值保存在輸出的矩陣中
        img=imread(facepath);
        f_matrix((i-1)*nn+j,:)=img(:)';
    end
end
end

3.fastPCA.m函數

function [ pcaA,V] = fastPCA( A,k,mA)  
m=size(A,1);  %m爲讀取圖片的張數
Z=(A-repmat(mA,m,1));  %中心化樣本矩陣
%一般用中心化的矩陣代替原矩陣。將數據集的均值歸零(預處理),保留數據之間的變化信息,便於找到區分。
T=Z*Z';  
[V1,D]=eigs(T,k);%計算T的最大的k個特徵值和特徵向量  
V=Z'*V1;         %協方差矩陣的特徵向量  
for i=1:k       %特徵向量單位化  
    l=norm(V(:,i));  
    V(:,i)=V(:,i)/l;  
end  
%單位化後的V才能是真正的低維空間的基,需要滿足正交化單位化兩個條件
pcaA=Z*V;       %線性變換,降至k維  ,將中心化的矩陣投影到低維空間的基中,V就是低維空間的基
end 

4.scaling.m函數

function scaledface = scaling( faceMat,lowvec,upvec )  
upnew=1;  
lownew=-1;  
[m,n]=size(faceMat);  
scaledface=zeros(m,n);  
for i=1:m  
    scaledface(i,:)=lownew+(faceMat(i,:)-lowvec)./(upvec-lowvec)*(upnew-lownew);  
    %將圖像數據中一個樣本的不同維度的值,最小值和最大值規範到-1和1,其他值按比例規範到(-1,1)
end  
end

5.SVMcgForClass.m子函數

用於交叉驗證,選擇合適的參數,參考來源:《MATLAB神經網絡43個案例分析》北京航空航天出版社

%% 子函數 SVMcgForClass.m
function [bestacc,bestc,bestg] = SVMcgForClass(train_label,train,cmin,cmax,gmin,gmax,v,cstep,gstep,accstep)
%SVMcg cross validation by faruto

%
% by faruto
%Email:[email protected] QQ:516667408 http://blog.sina.com.cn/faruto BNU
%last modified 2010.01.17
%Super Moderator @ www.ilovematlab.cn

% 若轉載請註明:
% faruto and liyang , LIBSVM-farutoUltimateVersion 
% a toolbox with implements for support vector machines based on libsvm, 2009. 
% Software available at http://www.ilovematlab.cn
% 
% Chih-Chung Chang and Chih-Jen Lin, LIBSVM : a library for
% support vector machines, 2001. Software available at
% http://www.csie.ntu.edu.tw/~cjlin/libsvm

% about the parameters of SVMcg 
if nargin < 10
    accstep = 4.5;
end
if nargin < 8
    cstep = 0.8;
    gstep = 0.8;
end
if nargin < 7
    v = 5;
end
if nargin < 5
    gmax = 8;
    gmin = -8;
end
if nargin < 3
    cmax = 8;
    cmin = -8;
end
% X:c Y:g cg:CVaccuracy
[X,Y] = meshgrid(cmin:cstep:cmax,gmin:gstep:gmax);
[m,n] = size(X);
cg = zeros(m,n);

eps = 10^(-4);

% record acc with different c & g,and find the bestacc with the smallest c
bestc = 1;
bestg = 0.1;
bestacc = 0;
basenum = 2;
for i = 1:m
    for j = 1:n
        cmd = ['-v ',num2str(v),' -c ',num2str( basenum^X(i,j) ),' -g ',num2str( basenum^Y(i,j) )];
        cg(i,j) = svmtrain(train_label, train, cmd);

        if cg(i,j) <= 55
            continue;
        end

        if cg(i,j) > bestacc
            bestacc = cg(i,j);
            bestc = basenum^X(i,j);
            bestg = basenum^Y(i,j);
        end        

        if abs( cg(i,j)-bestacc )<=eps && bestc > basenum^X(i,j) 
            bestacc = cg(i,j);
            bestc = basenum^X(i,j);
            bestg = basenum^Y(i,j);
        end        

    end
end
% to draw the acc with different c & g
figure;
[C,h] = contour(X,Y,cg,70:accstep:100);
clabel(C,h,'Color','r');
xlabel('log2c','FontSize',12);
ylabel('log2g','FontSize',12);
firstline = 'SVC參數選擇結果圖(等高線圖)[GridSearchMethod]'; 
secondline = ['Best c=',num2str(bestc),' g=',num2str(bestg), ...
    ' CVAccuracy=',num2str(bestacc),'%'];
title({firstline;secondline},'Fontsize',12);
grid on; 

figure;
meshc(X,Y,cg);
% mesh(X,Y,cg);
% surf(X,Y,cg);
axis([cmin,cmax,gmin,gmax,30,100]);
xlabel('log2c','FontSize',12);
ylabel('log2g','FontSize',12);
zlabel('Accuracy(%)','FontSize',12);
firstline = 'SVC參數選擇結果圖(3D視圖)[GridSearchMethod]'; 
secondline = ['Best c=',num2str(bestc),' g=',num2str(bestg), ...
    ' CVAccuracy=',num2str(bestacc),'%'];
title({firstline;secondline},'Fontsize',12);

相關學習資料:

基於MATLAB,運用PCA+SVM的特徵臉方法人臉識別 http://blog.csdn.net/yb536/article/details/40586695
統計學習方法 李航等 清華大學出版社 http://download.csdn.net/detail/lengwuqin/7509495
《MATLAB神經網絡43個案例分析》王小川等 北京航空航天出版社 http://download.csdn.net/detail/lengwuqin/7509495
LIBSVM簡介及其使用方法 http://endual.iteye.com/blog/1267442
關於SVM http://www.dataguru.cn/thread-371987-1-1.html
SVM理解 http://blog.csdn.net/viewcode/article/details/12840405
Coursera斯坦福大學機器學習 https://www.coursera.org/learn/machine-learning/home/welcome
Orl人臉數據庫 http://download.csdn.net/detail/u014609362/7807751

                                                            2016/6/25 於上海
發佈了19 篇原創文章 · 獲贊 55 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章