人臉識別中用主成分分析PCA來將資料降維--MATLAB程式碼
人臉識別的資料集,維度一般都比較高,在自己的電腦上跑這麼高維的資料集,很多個人計算機需要跑很長時間,因此一般都需要改變影象大小或者是降維。
常用的方式有以下幾種,最普通的是改變影象的大小,是用的MATLAB自帶的imresize函式來直接改變影象的大小,如何使用請自行查詢。其次就是降維,基本的降維方式主要是PCA和LDA兩種,複雜的我也曾用過自編碼器降維。本文主要講述的是用PCA的方式降維人臉資料集,因為我在查閱時,大多是分析原理,少有人能詳細說明,如何實現訓練集與資料集的處理。
一. PCA原理
PCA的演算法過程,用一句話來說,就是“將所有樣本X減去樣本均值m,再乘以樣本的協方差矩陣C的特徵向量V,即為PCA主成分分析
[1].將原始資料按行組成m行n列樣本矩陣X(每行一個樣本,每列為一維特徵)
[2].求出樣本X的協方差矩陣C和樣本均值m;(Matlab可使用cov()函式求樣本的協方差矩陣C,均值用mean函式)
[3].求出協方差矩陣的特徵值D及對應的特徵向量V;(Matlab可使用eigs()函式求矩陣的特徵值D和特徵向量V)
[4].將特徵向量按對應特徵值大小從上到下按行排列成矩陣,取前k行組成矩陣P;(eigs()返回特徵值構成的向量本身就是從大到小排序的)
[5].Y=(X-m)×P即為降維到k維後的資料;
二. 實現方法
直接呼叫Matlab工具箱princomp( )函式實現,[COEFF SCORE latent]=princomp(X)
引數說明:
1)COEFF 是主成分分量,即樣本協方差矩陣的特徵向量;
2)SCORE主成分,是樣本X在低維空間的表示形式,即樣本X在主成份分量COEFF上的投影 ,若需要降k維,則只需要取前k列主成分分量即可
3)latent:一個包含樣本協方差矩陣特徵值的向量;
三. 疑惑與解答
我在看完原理之後遇到以下疑惑,雖然感覺比較傻,但是可能也有人遇到同樣的問題,因此說一下並解答:
①在使用PCA之前,是否需要先將資料歸一化才可以?
②該方法可以得到訓練的資料集,那麼測試集怎麼得到?如果也採用這樣的方法,那不是本身就已經得到測試集的主成分了?
③COEFF分量與SCORE分量應該使用哪一個作為最終資料?為什麼大多數程式碼兩個都要儲存?
關於第一個問題,使用之前是無需歸一化的,因為使用之前本身就需要減去樣本均值,注意此處是每一個維度減去每一個維度的均值。當然了,實際上對於影象資料,先進行歸一化也是可以的,我嘗試過,先歸一化之後分類精度甚至更高了一個百分點左右(只嘗試一次,不排除其隨機性)。
第二個問題其實和第三個問題是一樣的解決方法了,在下面的程式碼中也有體現。COEFF分量是主成分的特徵矩陣,SCORE是訓練集的主成分特徵,即SCORE取其前K個就是將其降低到K維(此處看到有些文章說還需要繼續處理,為保險起見,程式碼中訓練集也是用的COEFF分量,但是直接使用SCORE分量應該也是沒問題的),留下COEFF分量是因為得到測試集時需要用到主成分的特徵矩陣。此外需要注意的是,測試集在與特徵矩陣相乘前,需要做與訓練集同樣的資料處理工作,具體方法見程式碼
四. 詳細程式碼
由於本人用的資料集是n×m,其中n為影象維度,m為影象張數,而MATLAB自帶的PCA函式為每一行為一張圖片,因此需要先做轉置處理,具體視自己使用的資料集而定。最後得到的trainFeatures和testFeatures即為需要的k維的訓練集和測試集。
function [ trainFeatures, testFeatures ] = myPCA( trainData, testData, k )
%UNTITLED 此處顯示有關此函式的摘要
% 此處顯示詳細說明
A = trainData';
B = testData';
%資料標準化:Z-標準化後的資料;mu-每列的均值;sigma-每列的標準差。
[Z,mu,sigma]=zscore(A);
%PCA降維:
[coeff,score,latent] = princomp(Z);
train = Z * coeff;
train = train(:,1:k);
rownum=size(B,1);
%按照訓練樣本的標準化引數,對測試資料進行處理:
% Y=(X-mu)/sigma;
B = (B-repmat(mu,rownum,1))./repmat(sigma,rownum,1);
%再按照訓練樣本的PCA降維後所選擇的係數矩陣對資料進行處理:
% Y=X*coeff
%由於在標準化中,已經對資料進行了減去均值處理,所以在此可直接乘係數矩陣。
test = B * coeff;
test = test(:,1:k);
trainFeatures = train';
testFeatures = test';
end
參考部落格