ile arasında değişen boyutlarda kovaryans matrislerini hesaplamamız gerekir . GPU'lara ve kümelere erişebiliyoruz, bu hesaplamaları hızlandırmak için en iyi paralel yaklaşımın ne olduğunu merak ediyoruz.
ile arasında değişen boyutlarda kovaryans matrislerini hesaplamamız gerekir . GPU'lara ve kümelere erişebiliyoruz, bu hesaplamaları hızlandırmak için en iyi paralel yaklaşımın ne olduğunu merak ediyoruz.
Yanıtlar:
İlk şey, BLAS kullanarak bunu yapabileceğinizi tanımaktır. Veri matrisiniz (her bir ölçüme karşılık gelen bir sütun vektörüdür; satırlar deneme niteliğindedir), o zaman yazabilirsiniz kovaryans şu şekilde: Bunu şu şekilde yazabiliriz: burada , tüm öğeleri 1 olan satır-vektörüdür, bu nedenle , sütun toplamlarının bir satır vektörüdür . Bu tamamen BLAS olarak yazılabilir, burada
Verileriniz ve sonuç matrisleriniz 64 GB civarında olabilir, bu nedenle tek bir düğüme veya bir düğümün değerinde GPU'ya sığmayacaksınız. GPU olmayan bir küme için, iskele gibi görünen PBLAS'a bakmak isteyebilirsiniz. GPU'lar için, çok düğümlü kütüphaneler henüz tam olarak orada değildir. Magma'nın altta yatan bir çeşit paralel BLAS uygulaması vardır, ancak kullanıcı dostu olmayabilir. CULA'nın henüz çok düğümlü olduğunu düşünmüyorum , ama bu göz kulak olacak bir şey. CUBLAS tek düğümlüdür .
Ayrıca, özellikle MPI hakkında bilginiz varsa ve bunu mevcut bir kod tabanına bağlamanız gerekiyorsa, paralelliğin kendiniz uygulamanızı şiddetle tavsiye ederim. Bu şekilde, CPU ve GPU BLAS arasında kolayca geçiş yapabilir ve verilerle tam olarak istediğiniz yerde başlayıp bitebilirsiniz. Birkaç MPI_ALLREDUCE çağrıdan daha fazlasına ihtiyacınız olmamalıdır .
@Max Hutchinson tarafından CUBlas ve Cuda Thrust ile verilen formülü uyguladım ve çevrimiçi ortak varyans hesaplama araçlarıyla karşılaştırdım. Benimki iyi sonuçlar üretiyor gibi görünüyor. Aşağıdaki kod QDA Bayes için planlandı. Dolayısıyla verilen matris birden fazla sınıf içerebilir. Böylece çoklu ko varyans matrisleri hesaplanır. Umarım birisi için faydalı olur.
//! 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);
}