大きな共分散行列の並列計算


9

サイズがから100000 × 100000の範囲の共分散行列を計算する必要があります。GPUとクラスターにアクセスできます。これらの計算を高速化するための最適な並列アプローチは何でしょうか。10000×10000100000×100000


1
共分散行列の特殊性を期待していますか?たとえば、「0に近い」相関が多数ある場合はどうでしょうか。
Dr_Sam 2013年

いいえ、現時点では何も期待できません
道を開きます

あなたのkは何ですか?つまり、各データベクトルの長さです。彼らはすでにゼロ平均ですか?
Max Hutchinson

いいえ、彼らはゼロ平均ではなく、彼らはどんな値を取ることもできます
道を開き

3
@フロー: ''臨床データ ''はアプリケーションですが、使用ではありません。私の質問は次のとおりです。共分散行列があるとしたら、それを(数学的な観点から)どうするのでしょうか。私が尋ねる理由は、結局のところ、常にそれからほとんど計算しないので、これを考慮に入れると、通常、完全な共分散行列を計算することを回避しながら、必要な後続の結果を取得することによって、物事を大幅にスピードアップできます。
Arnold Neumaier 2013年

回答:


17

X=[x1x2x3...]Rm×nx

Cij=E[xi,xj]E[xi]E[xj]=1nkxikxjk1n2(kxik)(kxjk)
C=1nXTX1n2(1TX)T(1TX)
(1T)(1TX)XXTX(1TX)=bbTb

データと結果のマトリックスは約64GBになる可能性があるため、単一のノードまたはノードに相当するGPUには適合しません。非GPUクラスターの場合は、ScalapackのようなPBLASを確認することをお勧めします。GPUの場合、マルチノードライブラリはまだ十分ではありません。 マグマは、ある種の並列BLAS実装を備えていますが、ユーザーフレンドリーではない場合があります。CULAはまだマルチノードを実行しているとは思いませんが、監視するためのものです。 CUBLASは単一ノードです。

特にMPIに精通していて、これを既存のコードベースにフックする必要がある場合は、並列処理を自分で実装することを強くお勧めします。このようにして、CPUとGPU BLASを簡単に切り替え、必要な場所で正確にデータの開始と終了を行うことができます。いくつかのMPI_ALLREDUCE呼び出しを超える必要はありません。


分析と関連するBLAS関数のリストをありがとうございます。あなたの答えを読んだ後、私はこれらを使用して、Scilab(www.scilab.org)の開発バージョンでの共分散行列の計算を加速し、最適化しました。
ステファンMottelet

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

1

@Max Hutchinsonによって与えられた式をCUBlasおよびCuda Thrustに実装し、オンラインの共分散計算ツールと比較しました。私は良い結果を生み出しているようです。以下のコードはQDAベイズを計画しています。したがって、与えられた行列は複数のクラスを含む可能性があります。したがって、複数の共分散行列が計算されます。誰かのお役に立てれば幸いです。

//! 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);
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.