机器学习最核心的底层运算肯定是矩阵乘法无疑了,为了让矩阵乘法执行更快,大家也是绞尽脑汁。从算法层面,stranssen算法将矩阵乘法复杂度由O(n3)O(n^3)O(n3)降到O(n2.81)O(n^{2.81})O(n2.81),最新的算法好像已经降到O(n2.37)O(n^{2.37})O(n2.37)左右了(Coppersmith–Winograd algorithm),但这只是理论复杂度,只有在矩阵超大的情况下才能体现出优势。从并行角度,我们可以从很多层面对矩阵乘法进行加速:1. 指令集并行,现在的CPU都会有很多并行指令可以一次完成多个乘法运算,Intel下有mmx指令集,arm下有neon指令集;2. 多核并行,除了指令集并行,我们还可以将矩阵分块,放在不同的核上进行数据层面的并行;3. GPU加速,利用GPU上的众核完成并行;4. 多机并行,针对超大矩阵或者众多矩阵乘法还可以采用多机并行。

在实际中,我们往往会采用指令集并行和GPU对矩阵乘法进行加速。用指令集优化矩阵乘法难度比较大,非专业人士不建议采用,而且幸运的是我们现在有很多开源矩阵运算库,性能大概率超过手写的矩阵乘法。CPU下的矩阵运算库有openblas和mkl等,GPU下有cublas,它们都是对fortran blas接口的实现。在上述加速库的基础上,我们可以再对矩阵进行分割实现多核或者多机的并行。在目前情况下,要实现快速的矩阵乘法,最便捷快速的方法就是用好openblas和cublas。openblas下的矩阵乘法函数为:cblas_sgemm,cublas中为cubalsSgemm。两个函数的参数基本一致,不过一个是行主序一个是列主序(cblas下一般用行主序,虽然它支持列主序),导致传递参数的时候差别很大。本博客希望能给大家一个详细明白的解释。

矩阵乘法原理

在线性代数中我们都学习过矩阵乘法,简单描述就是A矩阵的一行乘以B矩阵的一列,如图1所示。如果A矩阵大小为m*k,B矩阵为k*n,则生成的C矩阵大小为m*n,形象地描述就是中间的维度被吃掉了。A矩阵的一行固定之后乘以B的所有列填充C矩阵的一行。这看似简单的矩阵乘法有很多奥妙在里面。

在实际中,为了避免cache缺失,B矩阵往往会事先做转置,之前B矩阵按列访问元素,转置之后就和A矩阵一样按行访问,如图2所示,这个操作带来的速度提升是很明显的。

在示意图中,矩阵都是二维形式展示的,但是在内存中它们实际上是以一维数组形式存在的(暂时不考虑padding问题)。A矩阵大小为m*k,在内存中A矩阵的存在形式不过是一个m*k的一维数组而已。针对这块空间我们有很多解释:它既可以表示一个一维数组,也可以表示以能整除m*k的整数为宽的二维数组(也即矩阵)。但是具体宽度是多少选择很多,至少宽度既可以是m也可以是k,所以我们需要知道矩阵的宽度。似乎指定m、n和k之后矩阵的长和宽就定了,绝大多数情况下确实如此,不过也有例外。如图3,比如要进行计算的矩阵是一个大矩阵的一部分,此时为了正确访问矩阵的一行,我们需要跳过的元素就不是k了,而是原始大矩阵的宽度K。这也是库函数中lda、ldb和ldc存在的原因,它表示leading dimension,在行主序中为访问矩阵的一行需要跨过的列元素个数,在列主序中为访问矩阵的一列需要跨过的行元素个数。

在行主序下,矩阵乘法是A的一行乘以B的一列,为了保证正确性在列主序下就变成了B的一列乘以A的一行。B矩阵的一列固定之后乘以A的所有行填充C的一列,如图4。这样我们就可以和行主序下计算的结果一致。所以在列主序下,A*B变成了B*A。

cblas_sgemm参数详解

函数原型如下:

void cblas_sgemm(
const enum CBLAS_ORDER Order,
const enum CBLAS_TRANSPOSE TransA,
const enum CBLAS_TRANSPOSE TransB,
const int M,
const int N,
const int K,
const float alpha,
const float  *A,
const int lda,
const float  *B,
const int ldb,
const float beta,
float  *C,
const int ldc);
  • 参数Order:表示计算在行主序下(CblasRowMajor)还是列主序下(CblasColMajor)完成,相信大家更熟悉行主序,所以CPU下我们就填CblasRowMajor;
  • 参数TransA:表示第一个矩阵A是否做了转置,转置就填CblasTrans,否则就填CblasNoTrans,在行主序下第一个矩阵往往不做转置,所以一般填CblasNoTrans;
  • 参数TransB:表示第二个矩阵B是否做了转置,在行主序下为了避免cache缺失,第二个矩阵通常会做转置;
  • 参数M:表示 A或C的行数。如果A转置,则表示转置后的列数(A的大小为M*K,则为M,转置之后为K*M,也为M);
  • 参数N:表示 B或C的列数。如果B转置,则表示转置后的行数(B的大小为K*N,则为N,转置之后为N*K,也为N);
  • 参数K:表示 A的列数或B的行数(A的列数=B的行数),即为被吃掉的维度;
  • 参数alpha和beta:计算公式C = alpha*op( A )*op( B ) + beta*C中的两个参数值;
  • 参数lda:表示矩阵A的leading dimension,在行主序下,A转置表示A的行否则为A的列,值均为K,和参数M相反(注意:当运算的矩阵是大矩阵中的小矩阵时不再是K);
  • 参数ldb:表示矩阵B的leading dimension,在行主序下,B转置表示B的列否则为B的行,值均为K,和参数N相反(注意:当运算的矩阵是大矩阵中的小矩阵时不再是K);
  • 参数ldc:表示矩阵C的leading dimension,在行主序下始终为N,表示C的列。

上面特别容易出错的几个参数是M、N、K和lda、ldb、ldc,在填这几个参数的时候要相当小心。

cublasSgemm参数详解

函数原型如下:

cublasStatus_t cublasSgemm (
cublasHandle_t handle,
cublasOperation_t transA,
cublasOperation_t transB,
int M,
int N,
int K,
const float *alpha,
const float *A,
int lda,
const float *B,
int ldb,
const float *beta,
float *C,
int ldc);
  • 参数handle:cublas的句柄,通过cublasCreate创建;
  • 参数transA:矩阵B是否转置,转置填CUBLAS_OP_T,否则填CUBLAS_OP_N;
  • 参数transB:矩阵A是否转置;
  • 参数M:表示矩阵B的列数,若转置则为B的行数(B大小为K*N,则为N,转置之后为N*K,也为N);
  • 参数N:表示矩阵A的行数,若转置则为A的列数(A大小为M*K,则为M,转置之后为K*M,也为M);
  • 参数K:表示 B的行数或A的列数(A的列数=B的行数),即为被吃掉的维度;
  • 参数alpha和beta:计算公式C = alpha*op( A )*op( B ) + beta*C中的两个参数的引用;
  • 参数lda:表示矩阵B的leading dimension,在列主序下,B转置表示B的列否则为B的行,值均为K,和参数M相反(注意:当运算的矩阵是大矩阵中的小矩阵时不再是K);
  • 参数ldb:表示矩阵A的leading dimension,在列主序下,A转置表示A的行否则为A的列,值均为K,和参数N相反(注意:当运算的矩阵是大矩阵中的小矩阵时不再是K);
  • 参数ldc:表示矩阵C的leading dimension,在列主序下始终为N,表示C的列(此处和行主序一样,本人略微不解)。

在填入cublasSgemm的参数时,首先要记得交换矩阵A和B,然后根据列主序的要求填入相关参数。在cuda samples/0_Simple中有一个cublas调用示例matrixMulCUBLAS,大家可以参考里面的调用来进一步学习cublasSgemm。

cblas_sgemm和cublasSgemm参数详解相关推荐

  1. CI流水线配置文件参数详解(一)

    文章目录 4. 参数详解(一) 4.1 ``script`` 4.2 ``image`` 指定使用Docker镜像.如 ``iamge:name`` ,暂时忽略. 4.3 ``before_scrip ...

  2. 内存性能参数详解(转载)

    内存性能参数详解 先说说最有效提高你机器内存性能的几个参数:CL,TRP,TRCD CAS Latency "列地址选通脉冲潜伏期" BIOS中可能的其他描述为:tCL.CAS L ...

  3. spring boot 实战 / 可执行war启动参数详解

    概述   上一篇文章<spring boot 实战 / mvn spring-boot:run 参数详解>主要讲解了spring boot 项目基于maven插件启动过程中借助profil ...

  4. 调包侠福音!机器学习经典算法开源教程(附参数详解及代码实现)

    Datawhale 作者:赵楠.杨开漠.谢文昕.张雨 寄语:本文针对5大机器学习经典算法,梳理了其模型.策略和求解等方面的内容,同时给出了其对应sklearn的参数详解和代码实现,帮助学习者入门和巩固 ...

  5. plot参数详解python_30行Python代码实现3D数据可视化

    作者:潮汐 来源:Python技术 欢迎来到编程教室~ 我们之前的文章中有讲解过不少 Matplotlib 的用法,比如: 完成这50个Matplotlib代码,你也能画出优秀的图表 25个常用Mat ...

  6. Ehcache配置参数详解

    ehcache配置参数详解 <?xml version="1.0" encoding="UTF-8"?><ehcache><dis ...

  7. PHP date函数参数详解

    PHP date函数参数详解 作者: 字体:[增加 减小] 类型:转载 time()在PHP中是得到一个数字,这个数字表示从1970-01-01到现在共走了多少秒,很奇怪吧  不过这样方便计算, 要找 ...

  8. ping ip 端口_学生会私房菜【20200305期】——Ping命令及其常用参数详解

    一命令原理 Ping是ICMP的一个典型应用.Ping是检测网络连通的常用工具,同时也能收集其他相关信息.用户可以在Ping命令中指定不同参数,如ICMP报文长度.发送的ICMP报文个数.等待回复响应 ...

  9. python箱线图_Python 箱线图 plt.boxplot() 参数详解

    Python 绘制箱线图主要用 matplotlib 库里 pyplot 模块里的 boxplot() 函数. plt.boxplot() 参数详解 plt.boxplot(x, # 指定要绘制箱线图 ...

  10. MySQL配置文件参数详解

    [client] port = 3307 socket = /usr/local/mysql5_6/mysql.sock default-character-set=utf8 [mysql] prom ...

最新文章

  1. 唯一聚集索引上的唯一和非唯一非聚集索引
  2. servlet生命周期
  3. Unity Application Block-配置文件的使用-示例(附×××)
  4. nodejs 实践项目_NodeJS:最佳生产实践
  5. nginx 在ubuntu 上的启动,停止,重启
  6. 公共代码参考(DisplayMetrics)
  7. 拓端tecdat|r语言有限正态混合模型EM算法的分层聚类、分类和密度估计及可视化
  8. Sequential Model - 序列模型(RNN循环神经网络)
  9. 单片机胡汉才第四版答案_单片机课后习题答案--胡汉才编
  10. linux程序性能分析工具stap,《面向应用开发者的系统指南》CPU篇之使用systemtap分析进程的行为...
  11. 数据科学家VS大数据专家VS数据分析师:有什么不同?
  12. Unity游戏热更新
  13. python结巴分词的问题_python—结巴分词的理解
  14. XP系统的的一些快捷方式
  15. 学计算机的用双核CPU够吗,电脑cpu核数越多越好吗
  16. 微专业数据分析师 数据资料_微数据:元数据的内容
  17. 输入一个字母,若是小写字母,则变为大写输出,否则,原样输出。
  18. DSC和HD医学图像分割评价指标
  19. win7 vs2013 编译错误
  20. 不足一年下跌830 麒麟970+128G 2400万像素手机加速清仓!

热门文章

  1. 黑马畅购商城06-Elasticsearch
  2. jquery 3D旋转效果
  3. C++获取SMART信息
  4. (三)Detecting Spacecraft Anomalies Using LSTMs and Nonparametric Dynamic Thresholding
  5. ZooKeeper session has been expired
  6. iPhone6 6p 7 7p屏幕适配,切图准则
  7. Oracle中打印99乘法表的13种方法
  8. c语言单片机实时闹钟,基于单片机的智能定时闹钟的设计
  9. 数组的趣味应用-文曲星猜数游戏
  10. TortoiseSVN—Repo-browser,打开你要比较的两个版本所在的地址,选择一个版本做为比较的基础(单击右键—选择mark for comparison),再选择另外一个版本(单击右键—选