矩阵乘法优化:1x4矩阵块的各种优化方法

这篇具有很好参考价值的文章主要介绍了矩阵乘法优化:1x4矩阵块的各种优化方法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

文件名

优化方法

gFLOPs

峰值占比

线程数

MMult1.h

无任何优化

0.24gflops

2.1%

1

MMult2.h

一次计算4个元素

0.24gflops

2.1%

1

MMult_1x4_3.h

一次计算4个元素

0.24gflops

2.1%

1

MMult_1x4_4.h

一次计算4个元素

0.24gflops

2.1%

1

MMult_1x4_5.h

一次计算4个元素(将4个循环合并为1个)

0.25gflops

2.2%

1

MMult_1x4_7.h

一次计算4个元素(我们在寄存器中累加C的元素,并对a的元素使用寄存器),用指针来寻址B中的元素

0.98gflops

9.0%

1

MMult_1x4_8.h

在MMult_1x4_7的基础上循环展开四个(展开因子的相对任意选择)

1.1gflops

10%

1

MMult1:

void AddDot( int k, float *x, int incx,  float *y, float *gamma )
{
  /* compute gamma := x' * y + gamma with vectors x and y of length n.
     Here x starts at location x with increment (stride) incx and y starts at location y and has (implicit) stride of 1.
  */
 
  int p;

  for ( p=0; p<k; p++ ){
    *gamma += x[p] * Y(p);     
  }
}

void MY_MMult1( int m, int n, int k, float *a, int lda, 
                                    float *b, int ldb,
                                    float *c, int ldc )
{
  int i, j;
  for ( j=0; j<n; j+=1 ){        /* Loop over the columns of C */
    for ( i=0; i<m; i+=1 ){        /* Loop over the rows of C */
      /* Update the C( i,j ) with the inner product of the ith row of A
	 and the jth column of B */
    // for (int p=0; p<k; p++ ){      
    //             C(i, j) = C(i, j) + A(i, p) * B(p, j);
    //         }
      AddDot( k, &A( i,0 ), lda, &B( 0,j ), &C( i,j ) );
    }
  }
}

MMult2:

我们一次计算C矩阵的一个元素,这个时候需要遍历A矩阵的一行和B矩阵的一列并做乘加运算。如果我们一次计算C矩阵的4个元素,那么我们可以每次遍历A矩阵的一行和B矩阵的四列.

用B矩阵中当前元素的地址+1,+2,+3来快速索引B矩阵中的下一个元素:

void AddDot( int k, float *x, int incx,  float *y, float *gamma )
{
  int p;
  for ( p=0; p<k; p++ ){
    *gamma += x[p] * Y(p);     
  }
}

void MY_MMult2( int m, int n, int k, float *a, int lda, 
                                    float *b, int ldb,
                                    float *c, int ldc )
{
  int i, j;

  for ( j=0; j<n; j+=4 ){        /* Loop over the columns of C, unrolled by 4 */
    for ( i=0; i<m; i+=1 ){        /* Loop over the rows of C */
      AddDot( k, &A( i,0 ), lda, &B( 0,j ), &C( i,j ) );
      AddDot( k, &A( i,0 ), lda, &B( 0,j+1 ), &C( i,j+1 ) );
      AddDot( k, &A( i,0 ), lda, &B( 0,j+2 ), &C( i,j+2 ) );
      AddDot( k, &A( i,0 ), lda, &B( 0,j+3 ), &C( i,j+3 ) );
    }
  }
}

MMult_1x4_3:

将上一步里四次乘加操作独立出来作为单独函数,然后在这个单独函数调用4次上一轮的乘法函数。在主程序中只调用一次单独函数:

void AddDot( int k, float *x, int incx,  float *y, float *gamma )
{
  int p;
  for ( p=0; p<k; p++ ){
    *gamma += x[p] * Y(p);     
  }
}

void AddDot1x4( int k, float *a, int lda,  float *b, int ldb, float *c, int ldc )
{ 
  AddDot( k, &A( 0, 0 ), lda, &B( 0, 0 ), &C( 0, 0 ) );
  AddDot( k, &A( 0, 0 ), lda, &B( 0, 1 ), &C( 0, 1 ) );
  AddDot( k, &A( 0, 0 ), lda, &B( 0, 2 ), &C( 0, 2 ) );
  AddDot( k, &A( 0, 0 ), lda, &B( 0, 3 ), &C( 0, 3 ) );
}

void MY_MMult_1x4_3( int m, int n, int k, float *a, int lda, 
                                    float *b, int ldb,
                                    float *c, int ldc )
{
  int i, j;

  for ( j=0; j<n; j+=4 ){        /* Loop over the columns of C, unrolled by 4 */
    for ( i=0; i<m; i+=1 ){        /* Loop over the rows of C */
      AddDot1x4( k, &A( i,0 ), lda, &B( 0,j ), ldb, &C( i,j ), ldc );
    }
  }
}

MMult_1x4_4:

将上一步中独立出来的乘法函数进行进一步合并,两个乘加函数合并成一个:


void AddDot1x4( int k, float *a, int lda,  float *b, int ldb, float *c, int ldc )
{
  int p;
  for ( p=0; p<k; p++ ){
    C( 0, 0 ) += A( 0, p ) * B( p, 0 );     
  }
  for ( p=0; p<k; p++ ){
    C( 0, 1 ) += A( 0, p ) * B( p, 1 );     
  }
  for ( p=0; p<k; p++ ){
    C( 0, 2 ) += A( 0, p ) * B( p, 2 );     
  }
  for ( p=0; p<k; p++ ){
    C( 0, 3 ) += A( 0, p ) * B( p, 3 );     
  }
}

void MY_MMult_1x4_4( int m, int n, int k, float *a, int lda, 
                                    float *b, int ldb,
                                    float *c, int ldc )
{
  int i, j;
  for ( j=0; j<n; j+=4 ){        /* Loop over the columns of C, unrolled by 4 */
    for ( i=0; i<m; i+=1 ){        /* Loop over the rows of C */
      AddDot1x4( k, &A( i,0 ), lda, &B( 0,j ), ldb, &C( i,j ), ldc );
    }
  }
}

MMult_1x4_5: 

将上一步的乘加函数里,4个for循环合并成1个:

void AddDot1x4( int k, float *a, int lda,  float *b, int ldb, float *c, int ldc )
{
  int p;
  for ( p=0; p<k; p++ ){
    C( 0, 0 ) += A( 0, p ) * B( p, 0 );     
    C( 0, 1 ) += A( 0, p ) * B( p, 1 );     
    C( 0, 2 ) += A( 0, p ) * B( p, 2 );     
    C( 0, 3 ) += A( 0, p ) * B( p, 3 );     
  }
}

void MY_MMult_1x4_5( int m, int n, int k, float *a, int lda, 
                                    float *b, int ldb,
                                    float *c, int ldc )
{
  int i, j;

  for ( j=0; j<n; j+=4 ){        /* Loop over the columns of C, unrolled by 4 */
    for ( i=0; i<m; i+=1 ){        /* Loop over the rows of C */
      AddDot1x4( k, &A( i,0 ), lda, &B( 0,j ), ldb, &C( i,j ), ldc );
    }
  }
}

MMult_1x4x6:

将A和C矩阵中元素送入寄存器进行计算:

void AddDot1x4( int k, float *a, int lda,  float *b, int ldb, float *c, int ldc )
{
  /* So, this routine computes four elements of C: 
           C( 0, 0 ), C( 0, 1 ), C( 0, 2 ), C( 0, 3 ).  
     Notice that this routine is called with c = C( i, j ) in the
     previous routine, so these are actually the elements 
           C( i, j ), C( i, j+1 ), C( i, j+2 ), C( i, j+3 ) 
	  
     in the original matrix C.
     In this version, we accumulate in registers and put A( 0, p ) in a register */

  int p;
  register float 
       c_00_reg,   c_01_reg,   c_02_reg,   c_03_reg,  
       a_0p_reg;
    
  c_00_reg = 0.0; 
  c_01_reg = 0.0; 
  c_02_reg = 0.0; 
  c_03_reg = 0.0;
 
  for ( p=0; p<k; p++ ){
    a_0p_reg = A( 0, p );

    c_00_reg += a_0p_reg * B( p, 0 );     
    c_01_reg += a_0p_reg * B( p, 1 );     
    c_02_reg += a_0p_reg * B( p, 2 );     
    c_03_reg += a_0p_reg * B( p, 3 );     
  }

  C( 0, 0 ) += c_00_reg; 
  C( 0, 1 ) += c_01_reg; 
  C( 0, 2 ) += c_02_reg; 
  C( 0, 3 ) += c_03_reg;
}

void MY_MMult_1x4_6( int m, int n, int k, float *a, int lda, 
                                    float *b, int ldb,
                                    float *c, int ldc )
{
  int i, j;

  for ( j=0; j<n; j+=4 ){        /* Loop over the columns of C, unrolled by 4 */
    for ( i=0; i<m; i+=1 ){        /* Loop over the rows of C */
      AddDot1x4( k, &A( i,0 ), lda, &B( 0,j ), ldb, &C( i,j ), ldc );
    }
  }
}

MMult_1x4_7:

将B和C矩阵中元素送入寄存器计算,将A矩阵的元素用指针进行索引(这里要注意A和B到底是行主序还是列主序)

void AddDot1x4( int k, float *a, int lda,  float *b, int ldb, float *c, int ldc )
{
  int p;
  register float 
       c_00_reg,   c_01_reg,   c_02_reg,   c_03_reg,  
       b_0p_reg;
  float 
    *ap0_pntr, *ap1_pntr, *ap2_pntr, *ap3_pntr; 
    
  ap0_pntr = &A( 0, 0 );
  ap1_pntr = &A( 1, 0 );
  ap2_pntr = &A( 2, 0 );
  ap3_pntr = &A( 3, 0 );

  c_00_reg = 0.0; 
  c_01_reg = 0.0; 
  c_02_reg = 0.0; 
  c_03_reg = 0.0;
 
  for ( p=0; p<k; p++ ){
    b_0p_reg = B( p, 0 );

    c_00_reg += b_0p_reg * *ap0_pntr++;
    c_01_reg += b_0p_reg * *ap1_pntr++;
    c_02_reg += b_0p_reg * *ap2_pntr++;
    c_03_reg += b_0p_reg * *ap3_pntr++;
  }

  C( 0, 0 ) += c_00_reg; 
  C( 1, 0 ) += c_01_reg; 
  C( 2, 0 ) += c_02_reg; 
  C( 3, 0 ) += c_03_reg;
}

void MY_MMult_1x4_7( int m, int n, int k, float *a, int lda, 
                                    float *b, int ldb,
                                    float *c, int ldc )
{
  int i, j;

  for ( j=0; j<n; j+=1 ){        /* Loop over the columns of C, unrolled by 4 */
    for ( i=0; i<m; i+=4 ){        /* Loop over the rows of C */
      AddDot1x4( k, &A( i,0 ), lda, &B( 0,j ), ldb, &C( i,j ), ldc );
    }
  }
}

MMult_1x4_8:

展开上一步的“取出B矩阵中元素,存放到到寄存器中”这一过程的循环:文章来源地址https://www.toymoban.com/news/detail-554653.html

void AddDot1x4( int k, float *a, int lda,  float *b, int ldb, float *c, int ldc )
{
  int p;
  register float 
       c_00_reg,   c_01_reg,   c_02_reg,   c_03_reg,  
       b_0p_reg;
  float 
    *ap0_pntr, *ap1_pntr, *ap2_pntr, *ap3_pntr; 
    
  ap0_pntr = &A( 0, 0 );
  ap1_pntr = &A( 1, 0 );
  ap2_pntr = &A( 2, 0 );
  ap3_pntr = &A( 3, 0 );

  c_00_reg = 0.0; 
  c_01_reg = 0.0; 
  c_02_reg = 0.0; 
  c_03_reg = 0.0;
 
  for ( p=0; p<k; p+=4 ){
    b_0p_reg = B( p, 0 );

    c_00_reg += b_0p_reg * *ap0_pntr++;
    c_01_reg += b_0p_reg * *ap1_pntr++;
    c_02_reg += b_0p_reg * *ap2_pntr++;
    c_03_reg += b_0p_reg * *ap3_pntr++;

    b_0p_reg = B( p+1, 0 );

    c_00_reg += b_0p_reg * *ap0_pntr++;
    c_01_reg += b_0p_reg * *ap1_pntr++;
    c_02_reg += b_0p_reg * *ap2_pntr++;
    c_03_reg += b_0p_reg * *ap3_pntr++;

    b_0p_reg = B( p+2, 0 );

    c_00_reg += b_0p_reg * *ap0_pntr++;
    c_01_reg += b_0p_reg * *ap1_pntr++;
    c_02_reg += b_0p_reg * *ap2_pntr++;
    c_03_reg += b_0p_reg * *ap3_pntr++;

    b_0p_reg = B( p+3, 0);

    c_00_reg += b_0p_reg * *ap0_pntr++;
    c_01_reg += b_0p_reg * *ap1_pntr++;
    c_02_reg += b_0p_reg * *ap2_pntr++;
    c_03_reg += b_0p_reg * *ap3_pntr++;
  }

  C( 0, 0 ) += c_00_reg; 
  C( 1, 0 ) += c_01_reg; 
  C( 2, 0 ) += c_02_reg; 
  C( 3, 0 ) += c_03_reg;
}

void MY_MMult_1x4_8( int m, int n, int k, float *a, int lda, 
                                    float *b, int ldb,
                                    float *c, int ldc )
{
  int i, j;

  for ( j=0; j<n; j+=1 ){        /* Loop over the columns of C, unrolled by 4 */
    for ( i=0; i<m; i+=4 ){        /* Loop over the rows of C */
      AddDot1x4( k, &A( i,0 ), lda, &B( 0,j ), ldb, &C( i,j ), ldc );
    }
  }
}

到了这里,关于矩阵乘法优化:1x4矩阵块的各种优化方法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【易混区分】 tensor张量 Numpy张量的各种矩阵乘法、点积的函数对比 (dot, multiply,*,@matmul)

    又称为数量积、标量积(scalar product)或者内积(inner product) 它是指实数域中的两个向量运算得到一个实数值标量的二元运算。也就是对应元素的位置相乘 举例: 对于向量 a = ( x 1 , y 1 ) 和 b = ( x 2 , y 2 ) ,他们的点积就是 a ⋅ b = x 1 x 2 + y 1 y 2 a=(x_1,y_1)和b=(x_2,y_2),他们的点

    2024年01月25日
    浏览(45)
  • 矩阵乘法优化:GEMM中如何将大矩阵切割成小矩阵

     论文自然还是 Anatomy of High-Performance Matrix Multiplication。 如何拆分 一个矩阵乘法有 6 种拆分方式,其中对 row-major 效率最高的是: 第一次拆分 先做第一次拆分,取 A 的 kc 列(PanelA)和 B 的 kc 行(PanelB),得到待累加的一部分结果; 第二次拆分 第二次拆分,把 PanelB 按 nc 大

    2024年04月27日
    浏览(35)
  • 矩阵算法之矩阵乘法

    矩阵算法在图像处理、神经网络、模式识别等领域有着广泛的用途。 在矩阵乘法中,A矩阵和B矩阵可以做乘法运算必须满足A矩阵的列的数量等于B矩阵的行的数量。 运算规则:A的每一行中的数字对应乘以B的每一列的数字把结果相加起来。 1、当矩阵A的列数(column)等于矩阵

    2024年02月11日
    浏览(38)
  • 高性能计算的矩阵乘法优化 - Python + OpenMP实现

    关于上一节读者某些疑问 :为什么你用进程并行不是线程并行? 回答 :由于Python解释器有GIL(全局解释器锁),在单进程的解释器上有线程安全锁,也就是说每次只能一个线程访问解释器,因此Python在语法上的多线程(multithreads)实现是不会提高并行性能的。 这一点和C

    2024年02月15日
    浏览(65)
  • UG\NX二次开发 获取部件的4x4矩阵的方法

    文章作者:里海 来源网站: https://blog.csdn.net/WangPaiFeiXingYuan 方法1: 输入部件occ,获取矩阵。用函数UF_ASSEM_ask_transform_of_occ(),比较直接。 方法2: 输入部件的实例或事例,获取矩阵。用函数UF_ASSEM_ask_component_data()。 通过部件事例获取实例的方法 相关函数:    

    2024年02月12日
    浏览(50)
  • 高性能计算的矩阵乘法优化 - Python +MPI的实现

    本次实验的目的是使用MPI的并行性来进行矩阵乘法优化,本人使用 Python 实现 实验硬件: CPU :AMD Ryzen 7 5800H(3.20 GHz) 内存 :32GB (3200MHz) 要求 :使用一个矩阵,一个向量相乘,分别用单进程和多进程的mpi接口实现。 全局的规模参数是 Scale 数据示例 : 当 Scale=5 时,数据示例如

    2023年04月22日
    浏览(98)
  • 高性能计算实验——矩阵乘法基于MPI的并行实现及优化

    熟练掌握MPI编程方法,并将通用矩阵乘法转为MPI并行实现,进一步加深MPI的使用与理解。 进一步熟悉MPI矩阵乘法的实现,学习MPI点对点通信与集合通信的异同点和各自的优缺点,学会比较二者的性能以及各自使用的情形。 学习如何将自己编写的代码改造为标准库函数,供其

    2024年02月03日
    浏览(50)
  • FPGA HLS Matrix_MUL 矩阵乘法的计算与优化

    设置clock,10表示一个周期10ns,带宽100M vivado工具比较保守,计算需要的延迟是14,实际优化可以在10,设置大一点,优化的计算更多,一般约束设置大一点在30-50 选择开发板 xc7z020clg400-1 Source:描述功能模块的cpp和h代码 Test Bench:测试代码的 main.cpp matrix_mul.h #ifndef __xxxx__ #def

    2024年02月09日
    浏览(42)
  • 矩阵链乘法的动态规划算法_1

    上次我们学习了rod-cutting 问题的动态规划算法,初步了解求解动态规划过程的CRCC步骤,此步骤对于可以运用动态优化的问题非常有用,类似给大家提供了一套思维模板,让我们能更系统的思考和解决问题。本次我们将讨论矩阵链乘法的动态规划算法。 矩阵乘法 在讨论矩阵链

    2024年01月19日
    浏览(50)
  • 【动态规划】矩阵链乘法——算法设计与分析

    对于矩阵 U p × q U_{ptimes q} U p × q ​ 和 V q × r V_{qtimes r} V q × r ​ , Z p × r = U V Z_{ptimes r}=UV Z p × r ​ = U V ,共需计算 p q r pqr pq r 次标量乘法,时间复杂度为 Θ ( p q r ) Theta (pqr) Θ ( pq r ) 矩阵乘法满足结合律,即 ( U V ) W = U ( V W ) (UV)W=U(VW) ( U V ) W = U ( VW ) ,选择不同的结合

    2024年02月03日
    浏览(61)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包