~ 범위의 크기를 갖는 공분산 행렬을 계산해야합니다 . 우리는 GPU와 클러스터에 액세스 할 수 있으며 이러한 계산 속도를 높이는 가장 좋은 병렬 접근 방법이 무엇인지 궁금합니다.
~ 범위의 크기를 갖는 공분산 행렬을 계산해야합니다 . 우리는 GPU와 클러스터에 액세스 할 수 있으며 이러한 계산 속도를 높이는 가장 좋은 병렬 접근 방법이 무엇인지 궁금합니다.
답변:
첫 번째는 BLAS를 사용하여이 작업을 수행 할 수 있다는 것을 인식하는 것입니다. 데이터 행렬이 (각 는 하나의 측정 값에 해당하는 열 벡터이며 행은 시험판 임) 공분산은 다음과 같습니다. 다음과 같이 작성할 수 있습니다. 여기서 는 모든 요소가 1 인 행 벡터 이므로 는 열 합의 행 벡터입니다. . 이것은 BLAS로 완전히 쓸 수 있습니다.
데이터 및 결과 매트릭스는 약 64GB가 될 수 있으므로 단일 노드 또는 노드 가치 GPU에 적합하지 않습니다. 비 GPU 클러스터의 경우 스칼라 팩 처럼 느껴지는 PBLAS 를 볼 수 있습니다 . GPU의 경우 다중 노드 라이브러리가 아직 없습니다. Magma 에는 일종의 기본 병렬 BLAS 구현이 있지만 사용자 친화적이지 않을 수 있습니다. CULA 는 아직 다중 노드를 하지 않는다고 생각 하지만 계속 지켜봐야 할 부분 입니다. CUBLAS 는 단일 노드입니다.
또한 병렬 처리를 직접 구현하는 것이 좋습니다. 특히 MPI에 익숙하고 기존 코드 기반에 연결해야하는 경우 특히 그렇습니다. 이렇게하면 CPU와 GPU BLAS간에 쉽게 전환 할 수 있으며 원하는 위치에서 정확하게 데이터를 시작하고 끝낼 수 있습니다. MPI_ALLREDUCE 호출 이 몇 개 이상 필요하지 않아야 합니다.
@Max Hutchinson이 CUBlas 및 Cuda Thrust와 함께 제공 한 공식을 구현하고 온라인 공분산 계산 도구와 비교했습니다. 좋은 결과를내는 것 같습니다. 아래 코드는 QDA Bayes로 계획되었습니다. 따라서 주어진 행렬에는 둘 이상의 클래스가 포함될 수 있습니다. 따라서 다중 공분산 행렬이 계산됩니다. 누군가에게 도움이되기를 바랍니다.
//! Calculates one or more than one coVarianceMatrix given data.
// There can be many classes since many covariance matrixes.
/*!
\param inMatrix This vector contains matrix data in major storage.
Forexample if inMatrix=[1 2 3 4 5 6] and trialSizes=[2] this means matrix we will work on a matrix like :
|1 4 |
|2 5 |
|3 6 | -> 2 Trials, 3 Features. Columns contains feature rows contains trials (samples)
\param trialSizes There can be many classes since many covariance matrixes. Samples from all classes will be given with inMatrix.
But we need to know how many trials(samples) we have for each class.
For example if inMatrix=[1 2 3 4 5 6 7 8 9 10 11 12] and trialSizes=[2,2]
this means matrix we will work on a matrix like :
|1 4 | |7 10 |
|2 5 | |8 11 |
|3 6 | |9 12 | --> Total number of trials(samples which is total rowCount) 2 + 2 = 4 ,
So colSize = inMatrix.size()/4 = 3(feature vector size)
--> There is two element in trialSize vec so each vector has to samples
*/
void multiQDACovianceCalculator(std::vector<float>& inMatrix, std::vector<int>& trialSizes)
{
cublasHandle_t handle; // CUBLAS context
int classCount = trialSizes.size();
int rowSize = std::accumulate(trialSizes.begin(), trialSizes.end(), 0);
int dimensionSize = inMatrix.size() / rowSize;
float alpha = 1.0f;
float beta = 0.0f; // bet =1
thrust::device_vector<float> d_cov1(dimensionSize * dimensionSize);
thrust::device_vector<float> d_cov2(dimensionSize * dimensionSize);
thrust::device_vector<float> d_covResult(dimensionSize * dimensionSize);
thrust::device_vector<float> d_wholeMatrix(inMatrix);
thrust::device_vector<float> d_meansVec(dimensionSize); // rowVec of means of trials
float *meanVecPtr = thrust::raw_pointer_cast(d_meansVec.data());
float *device2DMatrixPtr = thrust::raw_pointer_cast(d_wholeMatrix.data());
auto maxTrialNumber = *std::max_element(trialSizes.begin(), trialSizes.end());
thrust::device_vector<float> deviceVector(maxTrialNumber, 1.0f);
cublasCreate(&handle);
// Inside of for loop one covariance matrix calculated each time
for (int i = 0; i < trialSizes.size(); i++)
{
// X*transpose(X) / N
alpha = 1.0f / trialSizes[i];
cublasSgemm(handle, CUBLAS_OP_N, CUBLAS_OP_T, dimensionSize, dimensionSize, trialSizes[i], &alpha,
device2DMatrixPtr, dimensionSize, device2DMatrixPtr, dimensionSize, &beta,
thrust::raw_pointer_cast(d_cov1.data()), dimensionSize);
// Mean vector of each column
alpha = 1.0f;
cublasSgemv(handle, CUBLAS_OP_N, dimensionSize, trialSizes[i], &alpha, device2DMatrixPtr,
dimensionSize, thrust::raw_pointer_cast(deviceVector.data()), 1, &beta, meanVecPtr, 1);
// MeanVec * transpose(MeanVec) / N*N
alpha = 1.0f / (trialSizes[i] * trialSizes[i]);
cublasSgemm(handle, CUBLAS_OP_T, CUBLAS_OP_N, dimensionSize, dimensionSize, 1, &alpha,
meanVecPtr, 1, meanVecPtr, 1, &beta,
thrust::raw_pointer_cast(d_cov2.data()), dimensionSize);
alpha = 1.0f;
beta = -1.0f;
// (X*transpose(X) / N) - (MeanVec * transpose(MeanVec) / N*N)
cublasSgeam(handle, CUBLAS_OP_N, CUBLAS_OP_N, dimensionSize, dimensionSize, &alpha,
thrust::raw_pointer_cast(d_cov1.data()), dimensionSize, &beta, thrust::raw_pointer_cast(d_cov2.data()),
dimensionSize, thrust::raw_pointer_cast(d_covResult.data()), dimensionSize);
// Go to other class and calculate its covarianceMatrix
device2DMatrixPtr += trialSizes[i] * dimensionSize;
}
printVector(d_covResult);
cublasDestroy(handle);
}