เราจำเป็นต้องคำนวณเมทริกซ์ความแปรปรวนร่วมที่มีขนาดตั้งแต่ ถึง . เราสามารถเข้าถึง GPU และกลุ่มเราสงสัยว่าอะไรคือวิธีการขนานที่ดีที่สุดในการเร่งการคำนวณเหล่านี้
เราจำเป็นต้องคำนวณเมทริกซ์ความแปรปรวนร่วมที่มีขนาดตั้งแต่ ถึง . เราสามารถเข้าถึง GPU และกลุ่มเราสงสัยว่าอะไรคือวิธีการขนานที่ดีที่สุดในการเร่งการคำนวณเหล่านี้
คำตอบ:
สิ่งแรกคือการรู้ว่าคุณสามารถทำได้โดยใช้ BLAS ถ้าคุณเมทริกซ์ข้อมูลคือ (แต่ละ เป็นเวกเตอร์คอลัมน์ที่สอดคล้องกับการวัดเดียว แถวคือการทดลอง) จากนั้นคุณสามารถเขียนความแปรปรวนร่วมเป็น:
เมทริกซ์ข้อมูลและผลลัพธ์ของคุณสามารถอยู่ที่ประมาณ 64GB ดังนั้นคุณจะไม่พอดีกับโหนดเดียวหรือ GPU ที่คุ้มค่า สำหรับคลัสเตอร์ที่ไม่ใช่ GPU คุณอาจต้องการดูPBLASซึ่งให้ความรู้สึกเหมือน scalapack สำหรับ GPU นั้น multi-node libraries ยังไม่พร้อม Magmaมีการใช้งาน BLAS แบบขนานบางอย่าง แต่อาจไม่เป็นมิตรกับผู้ใช้ ฉันไม่คิดว่าCULAจะทำหลายโหนด แต่สิ่งที่ต้องคอยดู CUBLASเป็นโหนดเดียว
ฉันขอแนะนำให้คุณพิจารณาใช้ความเท่าเทียมกันโดยเฉพาะอย่างยิ่งถ้าคุณคุ้นเคยกับ MPI และต้องเชื่อมโยงสิ่งนี้เข้ากับรหัสฐานที่มีอยู่ ด้วยวิธีนี้คุณสามารถสลับระหว่าง CPU และ GPU BLAS ได้อย่างง่ายดายและเริ่มต้นและสิ้นสุดด้วยข้อมูลที่คุณต้องการ คุณไม่ควรต้องการการโทรMPI_ALLREDUCEมากกว่าสองสามครั้ง
ฉันใช้สูตรที่กำหนดโดย @ Max Hutchinson กับ CUBlas และ Cuda Thrust และเปรียบเทียบกับเครื่องมือคำนวณผลต่าง co แบบออนไลน์ ดูเหมือนว่าฉันจะให้ผลลัพธ์ที่ดี รหัสด้านล่างนี้ได้วางแผนไว้ที่ 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);
}