簡體   English   中英

將矩陣的行乘以向量(低級優化)?

[英]Multiply rows of the matrix by a vector (low-level optimization)?

我正在優化一個函數,我想擺脫慢的循環。 我正在尋找一種將矩陣的每一行乘以矢量的更快方法。

我不是在尋找“經典”乘法。

例如。 我有一個具有1024列和20行的矩陣,以及一個長度為1024的向量。結果,我希望有一個1024 x 20的矩陣,其中每一行都乘以該向量。

我現在正在做的事情是在矩陣行的for循環中迭代,並使用mkl v?Mul對當前矩陣行和向量進行逐元素乘法。 有什么想法可以改善這一點嗎?

問題是將副本按矩陣乘以行嗎? 但對於具有可能的低級優化和MKL的C ++,不適用於R

使用Eigen矩陣庫 ,您要做的實際上是將對角矩陣相乘。 如果您具有任意多行和20列的矩陣,則可以編寫以下內容(不值得為此編寫函數):

void multRows(Eigen::Matrix<double, Eigen::Dynamic, 20>& mat,
              const Eigen::Matrix<double,20,1>& vect)
{
    mat = mat * vect.asDiagonal();
}

如果編譯器啟用了Eigen,它會生成AVX2代碼。 您可能要進行實驗,如果是更高效的存儲mat行主要或列在主要的使用情況。

附錄 (由於已編輯的問題):如果(多於)20列,則應該一起使用動態大小的矩陣:

void multRows(Eigen::MatrixXd& mat, const Eigen::VectorXd& vect)
{
    mat = mat * vect.asDiagonal();
}

最近的大多數處理器都支持AVX技術。 它提供了一個包含4個double(256位寄存器)的向量。 因此,此優化的解決方案可能是使用AVX。 為此,我使用x86intrin.h庫實現了它,它是GCC編譯器的一部分。 我還使用OpenMP使解決方案成為多線程。

//gcc -Wall  -fopenmp -O2 -march=native -o "MatrixVectorMultiplication" "MatrixVectorMultiplication.c" 
//gcc 7.2, Skylake Corei7-6700 HQ
//The performance improvement is significant (5232 Cycle in my machine) but MKL is not available to test
#include <stdio.h>
#include <x86intrin.h>
double A[20][1024] __attribute__(( aligned(32))) = {{1.0, 2.0, 3.0, 3.5, 1.0, 2.0, 3.0, 3.5}, {4.0, 5.0, 6.0, 6.5,4.0, 5.0, 6.0, 6.5},{7.0, 8.0, 9.0, 9.5, 4.0, 5.0, 6.0, 6.5 }};//The 32 is for 256-bit registers of AVX
double B[1024]  __attribute__(( aligned(32))) = {2.0, 2.0, 2.0, 2.0, 3.0, 3.0, 3.0, 3.0 }; //the vector
double C[20][1024] __attribute__(( aligned(32)));//the results are stored here

int main()
{
    int i,j;
    __m256d vec_C1, vec_C2, vec_C3, vec_C4;

    //begin_rdtsc
    //get the start time here
    #pragma omp parallel for
    for(i=0; i<20;i++){
        for(j=0; j<1024; j+=16){

            vec_C1 = _mm256_mul_pd(_mm256_load_pd(&A[i][j]), _mm256_load_pd(&B[j]));
            _mm256_store_pd(&C[i][j], vec_C1);

            vec_C2 = _mm256_mul_pd(_mm256_load_pd(&A[i][j+4]), _mm256_load_pd(&B[j+4]));
            _mm256_store_pd(&C[i][j+4], vec_C2);

            vec_C3 = _mm256_mul_pd(_mm256_load_pd(&A[i][j+8]), _mm256_load_pd(&B[j+8]));
            _mm256_store_pd(&C[i][j+8], vec_C3);

            vec_C4 = _mm256_mul_pd(_mm256_load_pd(&A[i][j+12]), _mm256_load_pd(&B[j+12]));
            _mm256_store_pd(&C[i][j+12], vec_C4);

        }
    }
    //end_rdtsc
    //calculate the elapsead time

    //print the results
    for(i=0; i<20;i++){
        for(j=0; j<1024; j++){
            //printf(" %lf", C[i][j]);
        }
        //printf("\n");
    }

    return 0;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM