2013-04-13 40 views
2

我试图用MATLAB'sprincomp做维度降低,但我不确定我是否做得对。在MATLAB中使用princomp的PCA(用于人脸识别)

这里是我的只是用于测试的代码,但我不知道我在做正确的投影:

A = rand(4,3) 
AMean = mean(A) 
[n m] = size(A) 
Ac = (A - repmat(AMean,[n 1])) 
pc = princomp(A) 
k = 2; %Number of first principal components 
A_pca = Ac * pc(1:k,:)' %Not sure I'm doing projection right 
reconstructedA = A_pca * pc(1:k,:) 
error = reconstructedA- Ac 

并采用ORL数据集我的面部识别码:

%load orl_data 400x768 double matrix (400 images 768 features) 
%make labels 
orl_label = []; 
for i = 1:40 
    orl_label = [orl_label;ones(10,1)*i]; 
end 

n = size(orl_data,1); 
k = randperm(n); 
s = round(0.25*n); %Take 25% for train 

%Raw pixels 
%Split on test and train sets 
data_tr = orl_data(k(1:s),:); 
label_tr = orl_label(k(1:s),:); 
data_te = orl_data(k(s+1:end),:); 
label_te = orl_label(k(s+1:end),:); 

tic 
[nn_ind, estimated_label] = EuclDistClassifier(data_tr,label_tr,data_te); 
toc 

rate = sum(estimated_label == label_te)/size(label_te,1) 

%Using PCA 
tic 
pc = princomp(data_tr); 
toc 

mean_face = mean(data_tr); 
pc_n = 100; 
f_pc = pc(1:pc_n,:)'; 
data_pca_tr = (data_tr - repmat(mean_face, [s,1])) * f_pc; 
data_pca_te = (data_te - repmat(mean_face, [n-s,1])) * f_pc; 

tic 
[nn_ind, estimated_label] = EuclDistClassifier(data_pca_tr,label_tr,data_pca_te); 
toc 

rate = sum(estimated_label == label_te)/size(label_te,1) 

如果我选择了足够多的主要组件,它给了我相同的识别率。如果我使用少量的principal components(PCA),那么使用PCA的比率较差。

这里有一些问题:

  1. princomp功能利用MATLAB计算第一ķ主要成分的最佳方法是什么?
  2. 使用PCA投影特征vs原始特征不提供额外的准确性,但只有更小的特征矢量大小? (比较特征向量更快)。
  3. 如何自动选择与原始特征向量相同精度的最小k(主要组件的数量)?
  4. 如果我有很大的一组样本,那么我可以只使用它们的子集,并且具有相当的精度?或者我可以在一些集合上计算PCA,然后“添加”一些其他集合(我不想重新计算set1 + set2的pca,但以某种方式迭代地将set2的信息添加到set1中的现有PCA)?

我也尝试使用简单的gpuArray GPU版本:

%Test using GPU 
tic 
A_cpu = rand(30000,32*24); 
A = gpuArray(A_cpu); 
AMean = mean(A); 
[n m] = size(A) 
pc = princomp(A); 
k = 100; 
A_pca = (A - repmat(AMean,[n 1])) * pc(1:k,:)'; 
A_pca_cpu = gather(A_pca); 
toc 
clear; 

tic 
A = rand(30000,32*24); 
AMean = mean(A); 
[n m] = size(A) 
pc = princomp(A); 
k = 100; 
A_pca = (A - repmat(AMean,[n 1])) * pc(1:k,:)'; 
toc 
clear; 

它工作得更快,但它不适合大矩阵。也许我错了?

如果我使用一个大的矩阵,它给了我:在设备上使用的内存gpuArray出

错误。

回答

1

“Princomp函数是使用MATLAB计算前k个主要组件的最佳方法吗?”

它计算一个完整的SVD,所以它在大型数据集上会很慢。您可以通过指定开始时需要的维度数并计算部分svd来显着提高速度。部分svd的matlab函数是svds

如果SVDS'你不够快,还有一个更现代的实行这里:

http://cims.nyu.edu/~tygert/software.html(matlab版:http://code.google.com/p/framelet-mri/source/browse/pca.m

(CF纸描述算法http://cims.nyu.edu/~tygert/blanczos.pdf

您可以控制通过增加计算出的奇异向量的数量来增加逼近的误差,链接文件中有精确的边界。这里有一个例子:

>> A = rand(40,30); %random rank-30 matrix 
>> [U,S,V] = pca(A,2); %compute a rank-2 approximation to A 
>> norm(A-U*S*V',2)/norm(A,2) %relative error    

ans = 

    0.1636 

>> [U,S,V] = pca(A,25); %compute a rank-25 approximation to A 
>> norm(A-U*S*V',2)/norm(A,2) %relative error     

ans = 

    0.0410 

当你有大量的数据和稀疏矩阵计算全SVD往往是不可能的,因为因素永远是稀疏。在这种情况下,您必须计算部分SVD以适应内存。例如:

>> A = sprandn(5000,5000,10000); 
>> tic;[U,S,V]=pca(A,2);toc; 
no pivots 
Elapsed time is 124.282113 seconds. 
>> tic;[U,S,V]=svd(A);toc; 
??? Error using ==> svd 
Use svds for sparse singular values and vectors. 

>> tic;[U,S,V]=princomp(A);toc; 
??? Error using ==> svd 
Use svds for sparse singular values and vectors. 

Error in ==> princomp at 86 
    [U,sigma,coeff] = svd(x0,econFlag); % put in 1/sqrt(n-1) later 

>> tic;pc=princomp(A);toc;  
??? Error using ==> eig 
Use eigs for sparse eigenvalues and vectors. 

Error in ==> princomp at 69 
     [coeff,~] = eig(x0'*x0); 
+0

这些方法的内存消耗是多少? – mrgloom

+1

对于MxN矩阵上的全SVD(即使用“princomp”或“svd”),您将需要存储稠密矩阵U和V,所以2 * M * N。当输入数据很大(并且因此存储在稀疏矩阵中)时,这是禁止的。使用svds或pca.m只需要存储k * max(M,N),其中k是您需要的维数。如果你的数据真的很大,你可以在Mahout中使用PCA实现(这只是我的答案中链接的论文的实现)https://builds.apache.org/job/Mahout-Quality/javadoc/org/apache /mahout/math/ssvd/SequentialOutOfCoreSvd.html – dranxo