在Caffe的源码中有不少地方使用OpenBlas库进行矩阵运算,今天就简单讲一下我在使用cblas_dgemm()函数的使用时遇到的问题。html
在网上查到的资料不少都是简单的说了下cblas_dgemm()函数的参数和功能,具体怎么用没有给出相应的代码,并且我对里面的转置也是很迷惑。先给你们几个博客地址:ios
官方例子:https://github.com/xianyi/OpenBLAS/wiki/User-Manualgit
很棒的以一个例子,我根据这个搞定的:http://blog.sina.com.cn/s/blog_4a03c0100101ethf.htmlgithub
这个也不错:http://blog.csdn.net/g_spider/article/details/6054990数组
在看下面的内容以前,请先仔细阅读函数参数。ide
好了言归正传,讲讲几个你们不太熟悉的参数。函数
第一个参数是选择行主序仍是列主序。那什么是行主序?什么又是列主序呢?以下所示spa
数组A[1,2,3,4,5,6,7,8,9].net
若是咱们想将A按照行主序(CblasRowMajor)展开成一个3*3的矩阵结果以下:code
[1,2,3
4,5,6
7,8,9]
若是咱们想将A按照列主序(CblasRowMajor)展开成一个3*3的矩阵结果以下:
[1,4,7
2,5,8
3,6,9]
其实咱们发现按照行主序就是按照行遍历矩阵获得数组A,按照列主序就是按照列遍历矩阵获得数组A。
第二个参数:是不转置(CblasTrans or CblasNoTrans)
开始对这个参数很迷惑,后来发现其实很简单,这个参数是和前面的参数(行或列主序)配合使用的。举例:若是你已经选择CblasRowMajor 若是CblasTrans被选择,那么对数组就按照列展开;若是选择CblasNoTrans被选择,那么对数组就按照行展开。简单的说就CblasRowMajor和CblasColMajor是个总开关,CblasTrans和CblasNoTrans是分开关。
好了,下面贴出代码再仔细讲讲。
//g++ -o demo1 demo1.cpp -I/usr/include/openblas -llapacke -llapack -lblas #include <stdio.h> #include<iostream> extern "C" { #include <cblas.h> // <strong>因为cblas.h文件已经拷贝到工做目录中,只需用双引号 </strong> } using namespace std; int main(){ int i = 0; double A[6] = { 1.0, 2.0, 1.0, -3.0, 4.0, -1.0 }; double B[6] = { 1.0, 2.0, 1.0, -3.0, 4.0, -1.0 }; double C[9] = { .5, .5, .5, .5, .5, .5, .5, .5, .5 }; double D[9] = { .5, .5, .5, .5, .5, .5, .5, .5, .5 }; double E[9] = { .5, .5, .5, .5, .5, .5, .5, .5, .5 }; double F[9] = { .5, .5, .5, .5, .5, .5, .5, .5, .5 }; /*按列主序展开*/ //一、都无转置 cout << "按列主序展开,都无转置:" << endl; cblas_dgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, 3, 3, 2, 1, A, 3, B, 2, 1, C, 3); for (i = 0; i<9; i++) printf("%lf ", C[i]); printf("\n"); //2\矩阵B转置 cout << "按列主序展开,矩阵B转置:" << endl; cblas_dgemm(CblasColMajor, CblasNoTrans, CblasTrans, 3, 3, 2, 1, A, 3, B, 3, 1, D, 3); for (i = 0; i<9; i++) printf("%lf ", D[i]); printf("\n"); /*按行主序展开*/ //一、都无转置 cout << "按行主序展开,都无转置:" << endl; cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 3, 3, 2, 1, A, 2, B, 3, 1, E, 3); for (i = 0; i<9; i++) printf("%lf ",E[i]); printf("\n"); //二、矩阵B转置 cout << "按行主序展开,矩阵B转置:" << endl; cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, 3, 3, 2, 1, A, 2, B, 2, 1, F, 3); for (i = 0; i<9; i++) printf("%lf ",F[i]); printf("\n"); }
结果:
$ ./demo1
按列主序展开,都无转置:
-4.500000 10.500000 -0.500000 10.500000 -9.500000 4.500000 7.500000 4.500000 5.500000
按列主序展开,矩阵B转置:
10.500000 -9.500000 4.500000 -9.500000 20.500000 -1.500000 4.500000 -1.500000 2.500000
按行主序展开,都无转置:
-4.500000 10.500000 -0.500000 10.500000 -9.500000 4.500000 7.500000 4.500000 5.500000
按行主序展开,矩阵B转置:
5.500000 -4.500000 2.500000 -4.500000 10.500000 7.500000 2.500000 7.500000 17.500000
下面咱们来分析一下各类模式下数组A和B是怎样展开成矩阵的。
一、按列主序展开,都无转置
矩阵A=[1.0,-3.0 矩阵B=[1.0,1.0,4.0 A*B=[-5.0,10.0,7.0
2.0,4.0 2.0,-3.0,-1.0] 10.0,-10.0,4.0
1.0,-1.0] -1.0,4.0,5.0]
结果矩阵C也是按列主序展开,(这个地方有点问题,一直没找到缘由,你们注意)
二、按列主序展开,矩阵B转置
矩阵A=[1.0,-3.0 矩阵B=[1.0,2.0,1.0 A*B=[10.0,-10.0,4.0
2.0,4.0 -3.0,4.0,-1.0] -10.0,20.0,-2.0
1.0,-1.0] 4.0,-2.0,2.0]
结果矩阵D按行主序展开
三、按行主序展开,都无转置
矩阵A=[1.0,2.0 矩阵B=[1.0,2.0,1.0 A*B=[-5.0,10.0,-1.0
1.0,-3.0 -3.0,4.0,-1.0] 10.0,-10.0,4.0
4.0,-1.0] 7.0,4.0,5.0]
结果矩阵E按行主序展开
四、按行主序展开,矩阵B转置
矩阵A=[1.0,2.0 矩阵B=[1.0,1.0,4.0 A*B=[5.0,-5.0,2.0
1.0,-3.0 2.0,-3.0,-1.0] -5.0,10.0,7.0
4.0,-1.0] 2.0,7.0,17.0]
结果矩阵F按行主序展开
注意:若是CblasColMajor 则lda,ldb,ldc是A,B,C的行
若是CblasRowMajor则lda,ldb,ldc是A,B,C的列
// g++ -o mycblas mycblas.cpp -I/usr/include/openblas -llapacke -llapack -lblas extern "C" { #include <cblas.h> // <strong>因为cblas.h文件已经拷贝到工做目录中,只需用双引号 </strong> } #include <cstdlib> #include <iostream> using namespace std; int main(void) { const enum CBLAS_ORDER Order=CblasRowMajor; const enum CBLAS_TRANSPOSE TransA=CblasNoTrans; const enum CBLAS_TRANSPOSE TransB=CblasNoTrans; const int M=4;//A的行数,C的行数 const int N=2;//B的列数,C的列数 const int K=3;//A的列数,B的行数 const float alpha=1; const float beta=0; const int lda=K;//A的列 const int ldb=N;//B的列 const int ldc=N;//C的列 const float A[K*M]={1,2,3,4,5,6,7,8,9,8,7,6}; const float B[K*N]={5,4,3,2,1,0}; float C[M*N]; cblas_sgemm(Order, TransA, TransB, M, N, K, alpha, A, lda, B, ldb, beta, C, ldc); for(int i=0;i<M;i++) { for(int j=0;j<N;j++) { cout<<C[i*N+j]<<"/t"; } cout<<endl; } return EXIT_SUCCESS; }