Tính toán song song của ma trận hiệp phương sai lớn


9

Chúng ta cần tính toán ma trận hiệp phương sai với các kích thước từ đến 100000 × 100000 . Chúng tôi có quyền truy cập vào GPU và cụm, chúng tôi tự hỏi đâu là cách tiếp cận song song tốt nhất để tăng tốc các tính toán này.10000×10000100000×100000


1
Bạn có mong đợi sự đặc biệt cho ma trận hiệp phương sai của bạn? Ví dụ, số lượng lớn các tương quan "gần 0"?
Dr_Sam

không, chúng tôi không thể mong đợi bất cứ điều gì ngay bây giờ
Mở đường vào

K của bạn là gì Đó là, mỗi vector dữ liệu dài bao nhiêu. Họ có nghĩa là không?
Max Hutchinson

không, chúng không có nghĩa là không, chúng có thể nhận bất kỳ giá trị nào
Mở đường vào

3
@flow: '' dữ liệu lâm sàng '' là ứng dụng, nhưng không sử dụng. Câu hỏi của tôi là: Giả sử bạn có ma trận hiệp phương sai, bạn sẽ làm gì với nó (theo quan điểm toán học)? Lý do tôi hỏi là cuối cùng, người ta luôn tính toán rất ít từ nó, và nếu điều này được tính đến, người ta thường có thể tăng tốc mọi thứ rất nhiều bằng cách tránh tính toán ma trận hiệp phương sai đầy đủ trong khi vẫn nhận được kết quả mong muốn tiếp theo.
Arnold Neumaier

Câu trả lời:


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

Dữ liệu và ma trận kết quả của bạn có thể vào khoảng 64 GB, do đó bạn sẽ không vừa với một nút hoặc giá trị GPU của một nút. Đối với cụm không phải GPU, bạn có thể muốn xem PBLAS , cảm giác giống như scalapack. Đối với GPU, các thư viện đa nút chưa hoàn toàn ở đó. Magma có một số loại triển khai BLAS song song cơ bản, nhưng nó có thể không thân thiện với người dùng. Tôi không nghĩ CULA thực hiện đa nút, nhưng đây là điều cần chú ý. CUBLAS là một nút đơn.

Tôi cũng đề nghị bạn nên cân nhắc việc thực hiện song song chính mình, đặc biệt nếu bạn đã quen thuộc với Bộ KH & ĐT và phải nối cái này vào một cơ sở mã hiện có. Bằng cách đó, bạn có thể dễ dàng chuyển đổi giữa CPU và GPU BLAS và bắt đầu và kết thúc với dữ liệu chính xác nơi bạn muốn. Bạn không cần nhiều hơn một vài cuộc gọi MPI_ALLREDUCE .


Cảm ơn bạn đã phân tích và danh sách các chức năng BLAS có liên quan. Sau khi đọc câu trả lời của bạn, tôi đã sử dụng những điều này để tăng tốc và tối ưu hóa tính toán của ma trận hiệp phương sai trong phiên bản phát triển của Scilab (www.scilab.org).
Stéphane Mottelet

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

1

Tôi đã triển khai công thức được đưa ra bởi @Max Hutchinson với CUBlas và Cuda Thrust và so sánh với các công cụ tính toán phương sai đồng trực tuyến. Có vẻ như tôi tạo ra kết quả tốt. Mã dưới đây được lên kế hoạch cho QDA Bayes. Vì vậy, ma trận đưa ra có thể chứa nhiều hơn một lớp. Vì vậy, nhiều ma trận phương sai co được tính toán. Tôi hy vọng nó sẽ hữu ích cho một ai đó.

//! 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);
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.