2014-06-12 2 views
1

치수가 미리 알지 못하는 일부 고유 메트릭스가 있는데, 상한 만 있습니다. 나는 멈춤 기준이 충족 될 때까지 열을 기준으로 열을 채우는 반복문을 채운다 (j 반복 이후에 말하자).C++ : Eigen conservativeResize가 너무 비쌉니까?

내 문제는 다음과 같습니다. 루프가 끝나면 행렬 곱셈 (분명히 첫 번째 열만 사용)에 해당 행렬이 필요합니다. 직접적인 솔루션은 Eigen의 conservativeResize를 사용하고 바로 진행하여 행렬 곱셈을 수행하는 것입니다. 행렬은 (100000+ 차원) 상당히 큰 경향이 있기 때문에 Eigen의 conservativeResize는 크기가 조정 된 행렬에 대한 메모리를 재 할당하고 하나의 완전한 복사본을 수행하므로이 솔루션은 상당히 비쌉니다.

필자는 오래된 (큰) 행렬을 사용하는 자체 사용자 정의 행렬 곱셈 함수를 작성하고 인수를 사용하여 사용할 열의 수를 지정하려고했습니다. 나는 Eigen의 행렬 곱셈이 훨씬 더 최적화되어 결국이 솔루션은 보수적 인 크기 조정과 표준 고유 곱셈을 사용하는 것보다 느리다는 것을 두려워합니다 ...

그냥 글 머리 기호를 물리고 conservativeResize를 사용해야합니까? 더 좋은 생각이야? BTW : 우리가 말하고있는 행렬은 루프/크기 변경 후 3 곱셈과 1 전치 연산에 사용됩니다.

미리 감사드립니다!

편집 : 이 코드의 관련 부분 (X는 MatrixXd이고, Y는 VectorXd이고 numComponents가 PLS1을 사용하도록되어 잠재 변수의 수이다). 문제는 : 처음에는 numComponents가 항상 X (X.cols())의 차원 수이지만 중지 기준은 출력 벡터의 분산에 대한 상대적인 향상을 확인한다고 가정합니다. 아직 구현되지 않음). 상대적인 개선이 너무 작 으면, 알고리즘은 멈춰 있어야하고 (우리는 첫 번째 구성 요소에 만족하기 때문에) 회귀 계수를 계산해야합니다.

using namespace Eigen; 
MatrixXd W,P,T,B; 
VectorXd c,xMean; 
double xMean; 

W.resize(X.cols(),numComponents); 
P.resize(X.cols(),numComponents); 
T.resize(X.rows(),numComponents); 
c.resize(numComponents); 
xMean.resize(X.cols()); 
xMean.setZero(); 
yMean=0; 
VectorXd yCopy=y; 
//perform PLS1 
for(size_t j=0; j< numComponents; ++j){ 
    VectorXd tmp=X.transpose()*y; 
    W.col(j)=(tmp)/tmp.norm(); 
    T.col(j)=X*W.col(j); 
    double divisorTmp=T.col(j).transpose()*T.col(j); 
    c(j)=(T.col(j).transpose()*y); 
    c(j)/=divisorTmp; 
    P.col(j)=X.transpose()*T.col(j)/divisorTmp; 
    X=X-T.col(j)*P.col(j).transpose(); 
    y=y-T.col(j)*c(j); 
    if(/*STOPPINGCRITERION(TODO)*/ && j<numComponents-1){ 
     numComponents=j+1; 
     W.conservativeResize(X.cols(),numComponents); 
     P.conservativeResize(X.cols(),numComponents); 
     T.conservativeResize(X.rows(),numComponents); 
     c.conservativeResize(numComponents); 
    } 
} 
//store regression matrix 
MatrixXd tmp=P.transpose()*W; 
B=W*tmp.inverse()*c; 
yCopy=yCopy-T*c; 
mse=(yCopy.transpose()*yCopy); 
mse/=y.size();//Mean Square Error 
+0

당신은 어떤 코드를 작성하거나 벤치 마크 그것을 시도 적이 있습니까? –

+0

예 대부분의 코드 (PLS1 알고리즘의 수정 버전입니다)가 누락 된 유일한 이유는 중지 기준입니다. 질문에 추가하겠습니다. 나는 벤치마킹을 시도하지 않았다. – user1544100

+0

/벤치 마크/프로파일 /, 또한 흥미 롭다 : http://channel9.msdn.com/Events/Build/2014/4-587 – sehe

답변

6

내가 다음 곱셈을 사용 block에 대한 의미있는 데이터를 포함하는 것 그 부분의 뷰를 생성, 한 번 큰 행렬을 할당 할 수 있다고 생각 :이를 위해, 나는 conservativeResize이 필요합니다. 그런 다음 큰 행렬을 재사용 할 수 있습니다. 이것은 재 할당을 할애 할 것입니다.

다음 예제에서는이를 충분히 보여줍니다.

./eigen_block_multiply.cpp :

#include <Eigen/Dense> 
#include <iostream> 
using namespace std; 
using namespace Eigen; 
int main() 
{ 
    Matrix<float, 2, 3> small; 
    small << 1,2,3, 
      4,5,6; 

    Matrix<float, 4, 4> big = Matrix<float, 4, 4>::Constant(0.6); 
    cout << "Big matrix:\n"; 
    cout << big << endl; 
    cout << "Block of big matrix:\n"; 
    cout << big.block(0,0,3,2) << endl; 
    cout << "Small matrix:\n"; 
    cout << small << endl; 
    cout << "Product:\n"; 
    cout << small * big.block(0,0,3,2) << endl; 

    Matrix<float, 3, 3> small2; 
    small2 << 1,2,3, 
      4,5,6, 
      7,8,9; 
    big = Matrix<float, 4, 4>::Constant(6.66); 
    cout << "Product2:\n"; 
    cout << small * big.block(0,0,3,3) << endl; 
} 

출력 :

Big matrix: 
0.6 0.6 0.6 0.6 
0.6 0.6 0.6 0.6 
0.6 0.6 0.6 0.6 
0.6 0.6 0.6 0.6 
Block of big matrix: 
0.6 0.6 
0.6 0.6 
0.6 0.6 
Small matrix: 
1 2 3 
4 5 6 
Product: 
3.6 3.6 
    9 9 
Product2: 
39.96 39.96 39.96 
99.9 99.9 99.9 
+0

아이겐 (Eigen) 그것은 내가 찾고 있던 것과 정확히 일치합니다. 고맙습니다. 선생님, 오늘 하루를 보냈습니다. – user1544100

+1

캐시 익숙 함 때문에 정확하게 맞추어 진 매트릭스보다 여전히 느릴 수 있습니다. 데이터 액세스 패턴은 전체 행렬에 대해 반복하지 않을 때 약간의 구멍이 생기며 캐시에 덜 친숙합니다. 하지만 그렇게 할 필요는 없습니다. 나는 몇 가지 검사를 할 것입니다. 캐시 친화적 인 것이 큰 개선을 가져올 수 있습니다. – luk32

+0

좋아, 나는 그것을 명심하고 모든 것이 실행되면 – user1544100