Нам потрібно обчислити коваріаційні матриці розмірами від до . У нас є доступ до графічних процесорів та кластерів, ми цікавимося, який найкращий паралельний підхід для прискорення цих обчислень.
Нам потрібно обчислити коваріаційні матриці розмірами від до . У нас є доступ до графічних процесорів та кластерів, ми цікавимося, який найкращий паралельний підхід для прискорення цих обчислень.
Відповіді:
Перше, що потрібно визнати, що ви можете це зробити за допомогою BLAS. Якщо у вас є матриця даних (кожен - вектор стовпця, що відповідає одному вимірюванню; рядки - випробування), тоді ви можете записати коваріацію як:
Ваші матриці даних та результатів можуть становити близько 64 Гб, тому ви не збираєтесь розміщуватись на одному вузлі чи GPU, який коштує. Для кластера, який не є GPU, ви можете подивитися на PBLAS , який відчуває себе як скалапак. Для графічних процесорів багатовузлових бібліотек ще не існує. У Magma є якась основна паралельна реалізація BLAS, але це може бути не зручним для користувачів. Я не думаю, що CULA ще не працює у багатьох вузлах, але це щось, на що слідкувати. CUBLAS - одновузлова.
Я б також запропонував вам настійно розглянути можливість здійснення паралелізму самостійно, особливо якщо ви знайомі з MPI і вам доведеться приєднати це до наявної кодової бази. Таким чином, ви можете легко перемикатися між процесором та 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);
}