MPI 块矩阵乘法

Posted

技术标签:

【中文标题】MPI 块矩阵乘法【英文标题】:MPI Block matrix multiplication 【发布时间】:2014-04-21 08:35:52 【问题描述】:

我正在尝试生成两个大小为 n 的矩阵 A&B,将它们划分为 s*s 子矩阵,并在将它们分散到处理器之后,在块矩阵之间执行乘法运算。我已经能够通过处理器成功生成和分散子矩阵;但是,我被困在每个处理器的子矩阵上执行乘法。我的代码与以下帖子中的代码(答案部分中的代码)非常相似,但我针对两个矩阵对其进行了修改: MPI partition matrix into blocks

您能告诉我如何修改它以执行乘法吗?

为了便于跟进,我一直使用相同的标签。

    #include <stdio.h>
    #include <stdlib.h>
    #include <mpi.h>
    #include <time.h>

    #define COLSa 10
    #define ROWSa 10

    #define COLSb 10
    #define ROWSb 10
    #define s 2

   int main(int argc, char **argv) 

    MPI_Init(&argc, &argv);
    int p, rank;
    MPI_Comm_size(MPI_COMM_WORLD, &p);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);

    char i;
    char j;

    char a[ROWSa*COLSa];
    char b[ROWSb*COLSb];
    char c[ROWSa*COLSb];  // c=a*b

    const int NPROWS=s;  /* number of rows in _decomposition_ */
    const int NPCOLS=s;  /* number of cols in _decomposition_ */

    const int BLOCKROWSa = ROWSa/NPROWS;  /* number of rows in _block_ */
    const int BLOCKCOLSa = COLSa/NPCOLS; /* number of cols in _block_ */

    const int BLOCKROWSb = ROWSb/NPROWS;  /* number of rows in _block_ */
    const int BLOCKCOLSb= COLSb/NPCOLS; /* number of cols in _block_ */

    if (rank == 0) 

    for (int ii=0; ii<ROWSa*COLSa; ii++) 
         a[ii]=rand() %10 ;
    

    for (int ii=0; ii<ROWSb*COLSb; ii++) 
         b[ii]=rand() %10 ;

       
    

    char BLa[BLOCKROWSa*BLOCKCOLSa];
    for (int ii=0; ii<BLOCKROWSa*BLOCKCOLSa; ii++)
    BLa[ii] = 0;

    char BLb[BLOCKROWSb*BLOCKCOLSb];
    for (int ii=0; ii<BLOCKROWSb*BLOCKCOLSb; ii++)
    BLb[ii] = 0;  

    char BLc[BLOCKROWSa*BLOCKCOLSb];
    for (int ii=0; ii<BLOCKROWSa*BLOCKCOLSb; ii++)
    BLc[ii] = 0; 

    MPI_Datatype blocktype;
    MPI_Datatype blocktype2;

    MPI_Type_vector(BLOCKROWSa, BLOCKCOLSa, COLSa, MPI_CHAR, &blocktype2);
    MPI_Type_vector(BLOCKROWSb, BLOCKCOLSb, COLSb, MPI_CHAR, &blocktype2);

    MPI_Type_create_resized( blocktype2, 0, sizeof(char), &blocktype);
    MPI_Type_commit(&blocktype);

    int dispsa[NPROWS*NPCOLS];
    int countsa[NPROWS*NPCOLS];
    int dispsb[NPROWS*NPCOLS];
    int countsb[NPROWS*NPCOLS];

    //*******************************Start Time Record****************//

    clock_t t;
    t=clock();

    for (int ii=0; ii<NPROWS; ii++) 
    for (int jj=0; jj<NPCOLS; jj++) 
    dispsa[ii*NPCOLS+jj] = ii*COLSa*BLOCKROWSa+jj*BLOCKCOLSa;
    countsa [ii*NPCOLS+jj] = 1;
        
    

    MPI_Scatterv(a, countsa, dispsa, blocktype, BLa, BLOCKROWSa*BLOCKCOLSa, MPI_CHAR, 0,   MPI_COMM_WORLD);


    for (int ii=0; ii<NPROWS; ii++) 
    for (int jj=0; jj<NPCOLS; jj++) 
    dispsb[ii*NPCOLS+jj] = ii*COLSb*BLOCKROWSb+jj*BLOCKCOLSb;
    countsb [ii*NPCOLS+jj] = 1;
         
    

    MPI_Scatterv(b, countsb, dispsb, blocktype, BLb, BLOCKROWSb*BLOCKCOLSb, MPI_CHAR, 0, MPI_COMM_WORLD);




     for (int proc=0; proc<p; proc++) 
        if (proc == rank) 

          printf("Rank = %d\n", rank);

                if (rank == 0) 
                  printf("Global matrix A : \n");

                   for (int ii=0; ii<ROWSa; ii++) 
                     for (int jj=0; jj<COLSa; jj++) 
                       printf("%3d ",(int)a[ii*COLSa+jj]);
                
                        printf("\n");
            
                 printf("\n");
            printf("Global matrix B : \n");

           for (int ii=0; ii<ROWSb; ii++) 
             for (int jj=0; jj<COLSb; jj++) 
              printf("%3d ",(int)b[ii*COLSb+jj]);
                
         printf("\n");
            
        printf("\n");
                  printf("Local Matrix A:\n");
              for (int ii=0; ii<BLOCKROWSa; ii++) 
                for (int jj=0; jj<BLOCKCOLSa; jj++) 
            printf("%3d ",(int)BLa[ii*BLOCKCOLSa+jj]);

                

             printf("\n");
            

           printf("\n");
              printf("Local Matrix B:\n");
                for (int ii=0; ii<BLOCKROWSb; ii++) 
                   for (int jj=0; jj<BLOCKCOLSb; jj++) 
                       printf("%3d ",(int)BLb[ii*BLOCKCOLSb+jj]);

                

          printf("\n");
            
                


            printf("Local Matrix A:\n");
                    for (int ii=0; ii<BLOCKROWSa; ii++) 
                   for (int jj=0; jj<BLOCKCOLSa; jj++) 
                       printf("%3d ",(int)BLa[ii*BLOCKCOLSa+jj]);
                  

             printf("\n");
            

          printf("Local Matrix B:\n");
            for (int ii=0; ii<BLOCKROWSb; ii++) 
                for (int jj=0; jj<BLOCKCOLSb; jj++) 
                   printf("%3d ",(int)BLb[ii*BLOCKCOLSb+jj]);
                

        printf("\n");
            

  //**********************Multiplication***********************//

       for (int i = 0; i < BLOCKROWSa; i++) 
          for (j = 0; j < BLOCKCOLSb; j++) 

        for (k = 0; k < BLOCKCOLSb; k++)   //I am considering square matrices with the same sizes
               BLc[i + j*BLOCKROWSa] += BLa[i + k*BLOCKROWSa]*BLb[k + BLOCKCOLb*j];
                  printf("%3d ",(int)BLc[i+j*BLOCKROWSa]);
                     
    printf("\n");

                 

      printf("\n");

             

       

      MPI_Barrier(MPI_COMM_WORLD);
    

   MPI_Finalize();

   //**********************End Time Record************************//

    t=clock()-t;
     printf("It took %f seconds (%d clicks).\n",t,((float)t)/CLOCKS_PER_SEC);


       return 0;
     

【问题讨论】:

除了缺少int k;BLc[i + j*BLOCKROWSa] += BLa[i + k*BLOCKROWSa]*BLb[k + BLOCKCOLb*j]; 变成BLc[i + j*BLOCKROWSa] += BLa[i + k*BLOCKROWSa]*BLb[k + BLOCKCOLSb*j];(一个S 更多),只要您希望执行乘法运算,您的代码没有什么特别奇怪的地方块矩阵之间。为什么你认为你被困住了?为什么你对你的代码不满意?它与mpicc main.c -o main -std=c99mpirun -np 4 main 一起使用。 嗨弗朗西斯。感谢您的评论和更正。但是,通过这段代码,由于每个处理器的乘法结果,我无法得到一个单一的矩阵,出于某种原因,我在每个处理器上得到了 5 个! 好的,我设法修复了那个部分,现在我得到了一个单一的产品结果。但是乘法是不正确的!数学有问题! 一个小补充,与您的问题无关。您正在使用 rand(),但尚未使用 srand 启动种子。所以每次运行你实际上都在使用相同的矩阵。您可以添加一个 ''srand(time(NULL)) '' 来修复那个。 【参考方案1】:

要将块返回到 proc 0 上的矩阵中,您可以使用 MPI_Scatterv() 的“相反”,称为 MPI_Gatherv() http://www.mpich.org/static/docs/latest/www3/MPI_Gatherv.html

MPI_Gatherv(BLc, BLOCKROWSb*BLOCKCOLSb,MPI_CHAR, c, countsb, dispsb,blocktype, 0, MPI_COMM_WORLD);

if (rank == 0) 
    printf("Global matrix C : \n");

    for (int ii=0; ii<ROWSa; ii++) 
        for (int jj=0; jj<COLSa; jj++) 
            printf("%3d ",(int)c[ii*COLSa+jj]);
        
        printf("\n");
    

请记住,您执行的是块乘法,这与矩阵乘法不同。

再见,

弗朗西斯

【讨论】:

弗朗西斯,非常感谢这个有用的观点。我才意识到问题出在哪里。我的矩阵乘法实际上是对的,但是从 256 中减去元素并显示出来。我的意思是,例如,我在输出中得到 (135-256)=-121 而不是 135。我尝试将定义矩阵更改为浮点而不是字符,并相应地更改了 MPI 命令参数,但它仍然不起作用。 @THTH : 只要你用char 就是这样! 我使用了浮点数,并在我的 MPI 命令中将 MPI_CHAR 更改为 MPI_FLOAT,但我没有得到任何输出! 不会从 256 中减去您的元素。您只是在使用 signed chars,这些元素通常可以包含 -128 到 127 之间的值。大于 127 的值被解释为二进制补码中的负数表示。事实上,135 是 121 的补码。 感谢 Hristo。那么这是否意味着如果我使用 MPI_UNSIGNED_CHAR 这将被修复?

以上是关于MPI 块矩阵乘法的主要内容,如果未能解决你的问题,请参考以下文章

利用MPI实现Cannon算法并行矩阵乘法

利用MPI实现Cannon算法并行矩阵乘法

MPI矩阵乘法

矩阵乘法 MPI 停止工作

块输出的 MPI 矩阵

MPI Java矩阵乘法错误