使用cblas_sgemm执行复杂的矩阵操作操作以执行乘法

时间:2016-07-14 16:11:06

标签: c numpy matrix blas

我有100个3x3x3矩阵,我想与另一个大小为3x5x5的大矩阵相乘(类似于使用多个滤镜卷积一个图像,但不完全相同)。

为了便于解释,这就是我的大矩阵的样子:

>>> x = np.arange(75).reshape(3, 5, 5)
>>> x
array([[[ 0,  1,  2,  3,  4],
        [ 5,  6,  7,  8,  9],
        [10, 11, 12, 13, 14],
        [15, 16, 17, 18, 19],
        [20, 21, 22, 23, 24]],

       [[25, 26, 27, 28, 29],
        [30, 31, 32, 33, 34],
        [35, 36, 37, 38, 39],
        [40, 41, 42, 43, 44],
        [45, 46, 47, 48, 49]],

       [[50, 51, 52, 53, 54],
        [55, 56, 57, 58, 59],
        [60, 61, 62, 63, 64],
        [65, 66, 67, 68, 69],
        [70, 71, 72, 73, 74]]])

在内存中,我假设大矩阵中的所有子矩阵都存储在连续的位置(如果我错了,请纠正我)。我想要做的是,从这个3x5x5矩阵,我想从大矩阵的每个子矩阵中提取3个5x3列,然后水平连接它们以获得5x9矩阵(如果这部分不清楚,我道歉,如果需要,我可以更详细地解释)。如果我使用numpy,我会这样做:

>>> k = np.hstack(np.vstack(x)[:, 0:3].reshape(3, 5, 3))
>>> k
array([[ 0,  1,  2, 25, 26, 27, 50, 51, 52],
       [ 5,  6,  7, 30, 31, 32, 55, 56, 57],
       [10, 11, 12, 35, 36, 37, 60, 61, 62],
       [15, 16, 17, 40, 41, 42, 65, 66, 67],
       [20, 21, 22, 45, 46, 47, 70, 71, 72]])

但是,我没有使用python所以我没有任何访问我需要的numpy函数,以便将数据块重塑为我想要进行乘法的形式...我只能直接在C中调用cblas_sgemm函数(来自BLAS库),其中k对应于输入B.

这是我对cblas_sgemm的电话:

    cblas_sgemm(    CblasRowMajor, CblasNoTrans, CblasTrans, 
                    100, 5, 9, 
                    1.0,
                    A, 9,
                    B, 9, // this is actually wrong, since I don't know how to specify the right parameter
                    0.0,
                    result, 5);

基本上,ldb属性是此处的违规者,因为我的数据不会像我需要的那样被阻止。我尝试了不同的东西,但我无法让cblas_sgemm了解我希望它如何阅读和理解我的数据。

简而言之,我不知道该怎么说 cblas_sgemm 阅读 x k 。有一种方法可以在将数据发送到C之前巧妙地重塑我在python中的数据,以便 cblas_sgemm 可以按照我想要的方式工作吗?

我将通过设置CblasTrans来转置k,因此在乘法过程中,B为9x5。我的矩阵A的形状为100x9。希望有所帮助。

任何帮助将不胜感激。谢谢!

1 个答案:

答案 0 :(得分:1)

  

简而言之,我不知道如何告诉cblas_sgemm像k一样读取x。

你不能。你必须要复制一份。

考虑k

In [20]: k
Out[20]: 
array([[ 0,  1,  2, 25, 26, 27, 50, 51, 52],
       [ 5,  6,  7, 30, 31, 32, 55, 56, 57],
       [10, 11, 12, 35, 36, 37, 60, 61, 62],
       [15, 16, 17, 40, 41, 42, 65, 66, 67],
       [20, 21, 22, 45, 46, 47, 70, 71, 72]])

在二维数组中,每个轴中内存中元素的间距必须相同。您知道x如何创建内存中的连续元素为0, 1, 2, 3, 4, ...,但您的第一行k包含0, 1, 2, 25, 26, ....12之间没有间距(即内存地址增加了数组中一个元素的大小),但2和{{之间的内存大幅跳跃1}}。因此,您必须制作副本才能创建25

话虽如此,有一种替代方法可以使用一些重塑(不复制)和numpy的Searching other questions on Stack Overflow函数来有效地实现所需的最终结果。

这是一个例子。首先定义kx

A

这是我对你想要达到的目标的理解; In [52]: x = np.arange(75).reshape(3, 5, 5) In [53]: A = np.arange(90).reshape(10, 9) 是理想的结果:

A.dot(k.T)

通过切片In [54]: k = np.hstack(np.vstack(x)[:, 0:3].reshape(3, 5, 3)) In [55]: A.dot(k.T) Out[55]: array([[ 1392, 1572, 1752, 1932, 2112], [ 3498, 4083, 4668, 5253, 5838], [ 5604, 6594, 7584, 8574, 9564], [ 7710, 9105, 10500, 11895, 13290], [ 9816, 11616, 13416, 15216, 17016], [11922, 14127, 16332, 18537, 20742], [14028, 16638, 19248, 21858, 24468], [16134, 19149, 22164, 25179, 28194], [18240, 21660, 25080, 28500, 31920], [20346, 24171, 27996, 31821, 35646]]) 并重新塑造x,您可以获得相同的结果:

A