一. 数据的存储方式
对于一个矩阵,在内存中有两种存储顺序:(下面图和表格摘自 https://en.wikipedia.org/wiki/Row-major_order)
对于下面的矩阵:
可以有两种存储方式:左为列优先,右为行优先。
顾名思义,列优先:优先按列存储,先存完第一列再存第二列,行优先同理。
C/C++中矩阵的存储为行优先,但cublas/Matlab中是列优先准则,在不同语言间读取数据时需要注意这点,同时在写Matlab时要尽量取一个二维数组的列,而不是行。
扩展到N维矩阵,列优先意味着存储时第一个维度先变化,即存储顺序为(0,0,0,...)、(1,0,0,...)、(max,0,0,...)、(0,1,0,...)、(1,1,0,...),
行优先意味着最后一个维度先变化。
p.s:在处理数据时,说明数据的顺序需要表明:
1)维度安排
2)是否是行\列优先
这两个信息缺一不可。
p.s:caffe的Blob、numpy的array、OpenCV的Mat都是和C语言一样,是行优先的。
p.s:貌似只有CUBLAS/Matlab中的矩阵是列优先,Eigen默认使用列优先存储,可以指定存储方式。
二. cublasSgemm的使用
在做人脸相似度比对时,需要求解人脸特征与注册人脸特征的余弦相似度。当注册人连库的规模达到百万千万的规模是该过程是很耗时的,我们可以采用GPU进行优化计算。优化策略如下:
1. 多batch
2. 利用cublasgemm加速计算
假设一个batch的三个人脸特征如A矩阵所述,人脸注册库特征如B所描述:
目标求解:
转化为:
d=norm(A).norm(B)
矩阵norm(A):
矩阵norm(B):
由于cublas按照列优先存储,那么数据放到cublas内,如果我们再次按照按行优先取出来,那么我们会以为cublas对矩阵做了“转置”运算。
我们来看看caffe是怎么封装的: