Calcolo parallelo di grandi matrici di covarianza


9

Dobbiamo calcolare le matrici di covarianza con dimensioni che vanno da a . Abbiamo accesso a GPU e cluster, ci chiediamo quale sia il miglior approccio parallelo per accelerare questi calcoli.100000 × 10000010000×10000100000×100000


1
Ti aspetti particolarità per la tua matrice di covarianza? Ad esempio, un gran numero di correlazioni "vicino a 0"?
Dr_Sam

no, non possiamo aspettarci nulla adesso
Apri la strada il

Qual è la tua k? Cioè, quanto dura ciascun vettore di dati. Sono già a media zero?
Max Hutchinson

no, non sono a media zero, possono assumere qualsiasi valore
Apri la strada il

3
@flow: '' dati clinici '' è l'application, ma non l'uso. La mia domanda era: supponiamo che tu abbia la matrice di covarianza, cosa ne farai (da un punto di vista matematico)? Il motivo per cui chiedo è che alla fine si calcola sempre molto poco da esso, e se questo viene preso in considerazione si può di solito accelerare tremendamente le cose evitando di calcolare l'intera matrice di covarianza pur ottenendo il risultato successivo desiderato.
Arnold Neumaier l'

Risposte:


17

La prima cosa è riconoscere che puoi farlo usando BLAS. Se la matrice dei dati è (ogni x è un vettore di colonna corrispondente a una misurazione; le righe sono prove), quindi puoi scrivere la covarianza come: C i j = E [ x i , x j ] - E [ x i ] E [ x j ] = 1X=[x1x2x3...]Rm×nx Possiamo scrivere questo come: C=1

Cij=E[xi,xj]E[xi]E[xj]=1nkxikxjk1n2(kxik)(kxjk)
dove(1T)è la riga vettore con tutti gli elementi 1 così(1TX)è un vettore di riga delle somme di colonna diX. Questo può essere scritto completamente come BLAS, doveXTXè unGEMMo, meglio ancora, unSYRK/HERKe puoi ottenere(1TX)=bcon unGEMV,
C=1nXTX1n2(1TX)T(1TX)
(1T)(1TX)XXTX(1TX)=b con GEMM o SYRK / HERK di nuovo, e i prefattori conSCAL.bTb

Le matrici di dati e risultati possono avere una dimensione di circa 64 GB, quindi non ti adatterai a un singolo nodo o al valore di GPU di un nodo. Per un cluster non GPU, potresti voler guardare PBLAS , che sembra scalapack. Per le GPU, le librerie multi-nodo non sono ancora presenti. Magma ha una sorta di implementazione BLAS parallela sottostante, ma potrebbe non essere facile da usare. Non credo che CULA faccia ancora più nodi, ma è qualcosa da tenere d'occhio. CUBLAS è a nodo singolo.

Suggerirei anche di prendere in seria considerazione l'idea di implementare il parallelismo da soli, soprattutto se hai familiarità con MPI e devi collegarlo a una base di codice esistente. In questo modo, puoi passare facilmente tra CPU e GPU BLAS e iniziare e terminare con i dati esattamente dove lo desideri. Non dovresti aver bisogno di più di qualche chiamata MPI_ALLREDUCE .


Grazie per l'analisi e l'elenco delle funzioni BLAS pertinenti. Dopo aver letto la tua risposta, li ho usati per accelerare e ottimizzare il calcolo della matrice di covarianza nella versione di sviluppo di Scilab (www.scilab.org).
Stéphane Mottelet

E[xi,xj]E[xi]E[xj]

1

Ho implementato la formula data da @Max Hutchinson con CUBlas e Cuda Thrust e confrontata con gli strumenti di calcolo della varianza online. Sembra che il mio abbia prodotto buoni risultati. Il codice di seguito previsto per QDA Bayes. Quindi la matrice fornita può contenere più di una classe. Quindi vengono calcolate più matrici di varianza. Spero che sia utile per qualcuno.

//! 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);
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.