2014-04-05 11 views
1

나는 이미 사용하지 않고 Python에 얼굴 인식을위한 Principal Component Analysis을 구현하고있어이 numpy 또는 OpenCVPCA 방법을 정의했다. 그러나 나의 결과는 말 그대로 쓰레기 다.주성분 분석 : 분석 실수

OpenCVdoc에서 설명서 및 알고리즘 설명을 읽었습니다. 그러나 어떤 것은 명확하지 않습니다.

  • X = {x1, x2, ..., xn} 그렇다면 나는 공변량 행렬을 계산할 때 사용 된 X 행렬이 아니라고 생각합니다. 하지만 처음 두 단계에서 설명한대로 평균 등을 빼야합니다.
  • 고유 벡터는 고유 값에 따라 내림차순으로 정렬되어야합니다. 상응하는 고유 값의 절대 값을 보면서 정렬해야합니까? 어쨌든 모든 고유 벡터를 그려내는 순서가 주요 문제가 아니므로 이에 맞게 다시 정렬 할 수 있습니다. 분석적인 실수를 저질렀다고 생각합니다. 샘플 값은 행이 아닌 컬럼에 저장되는 것을

    MU = X.mean(axis=0) 
    for i in range(n): 
        X[i,:] -= MU 
    
    S = (np.dot(X, X.T)/float(n)) 
    #Hermitian (or symmetric) matrix. 
    eigenvalues, eigenvectors = numpy.linalg.eigh(S) 
    eigenvectors = numpy.dot(X.T, eigenvectors) 
    for i in range(n): 
        eigenvectors[:,i] = normalize_vector(eigenvectors[:,i]) 
    

    참고 :

나는 다음을 구현했습니다. 따라서 X은 모양이 nxd이고 n의 샘플 수이고 d은 샘플의 크기입니다.

enter image description here

상기 이미지는 기준이다. 첫 번째는 평균이며, 다음 세 개가 가장 큰 고유 벡터입니다. 아래 이미지는 내 결과입니다. 첫 번째는 평균이고, 다음은 어떤 순서로 모든 고유 벡터입니다. 그러나 그들은 결과와 일치하지 않는 것 같습니다.

cv2.PCACompute(X, 6)은 여전히 ​​더 나은 결과를 산출합니다.

답변

1

첫 번째 질문은 답변이 here입니다.

두 번째 답변은 해당 고유 값의 값에 따라 고유 벡터를 정렬해야합니다. 이를 위해, 당신은 (더 큰에 작은에서 순서 argsort)이 순서를 반대로 다음 파이썬 np.argsort()을 사용하고 있습니다 :

    :

    indexes = np.argsort(eigenvalues)[::-1] 
    eigval = eigenvalues[indexes] 
    eigvec = eigenvectors[:,indexes] 
    

    이 코드를 확인, 난 그냥 몇 가지 문제를 발견했습니다

  1. 이제 모두 고유 벡터가 표시되고 nb_components 매개 변수는 무시되므로 요청한 벡터 만 사용해야합니다. 당신 만 요구하는 경우는, 3 개 고유 벡터를 말할 수, 당신은 0에서 n에 루프를 사용하는 (PCA 기능 내부) 벡터를 정규화

    eigenvectors = eigenvectors[:,indexes][0:nb_components]

  2. 로 만들었지 만, 당신 만 3 개의 열을 갖습니다. 이를 해결하려면 0에서 nb_components까지 반복하십시오.

이외에도 코드가 완벽하게 작동합니다. 나는 단지 3 개의 Principals 구성 요소만을 사용하여 시험해 보았고 최종 결과로 6/6을 얻었습니다. 필자의 의견으로는, 고유 벡터를 표시 할 때의 차이점은 imshow를 사용하기 위해 float에서 uint8로 캐스팅 할 때의 표현 문제 일뿐입니다.

그리고 음의 고유 값에 대해서는 단지 eigh의 문제입니다. 고유 값은 방향의 분산을 보여주기 때문에 절대 값은 중요하지만 기호를 변경하면 "방향"(고유 벡터)을 변경해야합니다.

s = np.where(eigenvalues < 0) 
eigenvalues[s] = eigenvalues[s] * -1.0 
eigenvectors[:,s] = eigenvectors[:,s] * -1.0 

는 또한이 사용 numpy.linalg.svd (docs)을 해결할 수 있지만, numpy.linalg.eigh보다 느리게한다이다 넌 (this 참조) -1.0로이 승산 제외 고유치 및 해당 고유 벡터를 만들 수있다.

def pca(X, nb_components=0): 
    [n,d] = X.shape 
    if (nb_components <= 0) or (nb_components>6): 
     nb_components = n 

    MU = X.mean(axis=0) 
    for i in range(n): 
     X[i,:] -= MU 

    S = (np.dot(X, X.T)/float(n)) 

    eigenvalues, eigenvectors = np.linalg.eigh(S) 

    s = np.where(eigenvalues < 0) 
    eigenvalues[s] = eigenvalues[s] * -1.0 
    eigenvectors[:,s] = eigenvectors[:,s] * -1.0 

    indexes = np.argsort(eigenvalues)[::-1] 
    eigenvalues = eigenvalues[indexes] 
    eigenvectors = eigenvectors[:,indexes][:,0:nb_components] 

    eigenvectors = np.dot(X.T, eigenvectors) 

    for i in range(nb_components): 
     eigenvectors[:,i] = normalize_vector(eigenvectors[:,i]) 

    return (eigenvalues, eigenvectors, MU) 
+0

가 첫 번째 질문은 잘 설명 좋아,하지만 지금 난 :

요약하면, 이것은 내가 당신에서 들어오는 코드 (이 짧게 여기를 극복 할 때 나는 모든 코멘트 삭제)입니다 n과 n-1로 나눗셈을 혼동하는 경우가 있습니다. 두 사이트 모두 일부 사이트에서 사용되는 것 같습니다. 정렬을 위해 나는 여전히 음의 고유치에 대한 질문을 가지고 있습니다. 300, -100, 1이 300, -100, 1로 정렬되어 있거나 300, 1, -100으로 정렬되어 있다고 생각합니다. 나는 X.T와 곱한 후 결과 고유 벡터를 정규화하려고 시도 할 것이다. – Matthias

+1

공분산 행렬을 'n'으로 나누어 계산하고 'n-1'로 일부 구현을 보았습니다. 그러나 이유를 말할 수 없습니다 (오랫동안 'n'을 사용하여 좋은 결과를 얻었습니다) . 음의 고유 값에 대해서, 당신은 공분산 행렬 [Positive Semi-defined] (http://en.wikipedia.org/wiki/Covariance_matrix#Properties)을 가지고 있지 않아야하며 그 행렬은 [양의 고유 값] (http : /www.math.ucsd.edu/~njw/Teaching/Math271C/Lecture_03.pdf). 이유를 찾지 못하면 테스트 img 링크를 게시하고 더 많은 것을 찾아 볼 수 있습니다. –

+0

https://dl.dropboxusercontent.com/u/69633291/face_recognition.zip 데이터 폴더를 사용자 폴더에 넣으십시오. – Matthias