我有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
。希望有所帮助。
任何帮助将不胜感激。谢谢!
答案 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, ....
。 1
和2
之间没有间距(即内存地址增加了数组中一个元素的大小),但2
和{{之间的内存大幅跳跃1}}。因此,您必须制作副本才能创建25
。
话虽如此,有一种替代方法可以使用一些重塑(不复制)和numpy的Searching other questions on Stack Overflow函数来有效地实现所需的最终结果。
这是一个例子。首先定义k
和x
:
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