2013-04-13 2 views
2

Я пытаюсь уменьшить размерность, используя MATLAB'sprincomp, но я не уверен, что делаю это правильно.PCA с использованием princomp в MATLAB (для распознавания лиц)

Вот мой код только для тестирования, но я не уверен, что я делаю проекционное право:

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 против сырых функций не дает дополнительной точности, но только меньшие возможности векторного размера? (быстрее сравнивать векторы признаков).
  3. Как автоматически выбрать min k (количество основных компонентов), которые дают такую ​​же точность, что и исходный вектор функции?
  4. Что делать, если у меня есть очень большой набор образцов, я могу использовать только их подмножество с сопоставимой точностью? Или я могу вычислить PCA на каком-то множестве, а потом «добавить» другой набор (я не хочу перекомпилировать pca для set1 + set2, но каким-то образом итеративно добавить информацию из set2 в существующую PCA из set1)?

Я также попробовал версию GPU просто используя gpuArray:

%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 лучшим способом вычисления первых k основных компонентов с использованием MATLAB?»

Он вычисляет полный SVD, поэтому он будет медленным на больших наборах данных. Вы можете значительно ускорить это, указав количество необходимых вам параметров в начале и вычислив частичный svd. Функции matlab для частичного svd равны svds.

Если СВД не достаточно быстро для вас есть более современная реализация здесь:

http://cims.nyu.edu/~tygert/software.html (MATLAB версии: http://code.google.com/p/framelet-mri/source/browse/pca.m)

(КФ документ, описывающий алгоритм 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 для размещения в памяти. Пример:

>> 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

Для полного SVD на матрице MxN (т. Е. Используя «princomp» или «svd») вам нужно будет хранить плотные матрицы U и V, поэтому 2 * M * N. Это недопустимо, когда входные данные большие (и, следовательно, они хранятся в разреженной матрице). Использование svds или pca.m требует только сохранения k * max (M, N), где k - количество необходимых вам измерений. Если ваши данные действительно велики, вы можете использовать реализацию PCA в Mahout (это всего лишь реализация документа, связанного в моем ответе) https://builds.apache.org/job/Mahout-Quality/javadoc/org/apache /mahout/math/ssvd/SequentialOutOfCoreSvd.html – dranxo

Смежные вопросы