Necesitamos calcular matrices de covarianza con tamaños que varían de a . Tenemos acceso a GPU y clústeres, nos preguntamos cuál es el mejor enfoque paralelo para acelerar estos cálculos.100000 × 100000
Necesitamos calcular matrices de covarianza con tamaños que varían de a . Tenemos acceso a GPU y clústeres, nos preguntamos cuál es el mejor enfoque paralelo para acelerar estos cálculos.100000 × 100000
Respuestas:
Lo primero es reconocer que puedes hacer esto usando BLAS. Si su matriz de datos es (cada x es un vector de columna correspondiente a una medida; las filas son pruebas), entonces puede escribir la covarianza como: C i j = E [ x i , x j ] - E [ x i ] E [ x j ] = 1 Podemos escribir esto como: C=1
Sus matrices de datos y resultados pueden ser de alrededor de 64 GB, por lo que no va a caber en un solo nodo o en el valor de un nodo de GPU. Para un clúster que no sea GPU, es posible que desee ver PBLAS , que se siente como scalapack. Para las GPU, las bibliotecas de múltiples nodos aún no están allí. Magma tiene algún tipo de implementación BLAS paralela subyacente, pero puede no ser fácil de usar. No creo que CULA tenga múltiples nodos todavía, pero es algo a lo que hay que prestarle atención. CUBLAS es de nodo único.
También le sugiero que considere implementar el paralelismo usted mismo, especialmente si está familiarizado con MPI y tiene que conectarlo a una base de código existente. De esa manera, puede cambiar fácilmente entre CPU y GPU BLAS y comenzar y terminar con los datos exactamente donde lo desee. No debería necesitar más que unas pocas llamadas MPI_ALLREDUCE .
Implementé la fórmula dada por @Max Hutchinson con CUBlas y Cuda Thrust y la comparé con las herramientas de cálculo de covarianza en línea. Parece que el mío produce buenos resultados. El siguiente código planeado para QDA Bayes. Entonces la matriz dada puede contener más de una clase. Entonces se calculan las matrices de covarianza múltiple. Espero que sea útil para alguien.
//! 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);
}