查看您的 MATLAB 代码,您有 -
C = bsxfun(@times, permute(A,[4,2,5,1,3]), permute(B, [1,6,2,7,3,4,5])
所以,本质上——
B : 1 , 6 , 2 , 7 , 3 , 4 , 5
A : 4 , 2 , 5 , 1 , 3
现在,在 MATLAB 中,我们不得不从更高的维度借用单例维度,这就是引入 dims 6
、7
forB
和 dims 4
5
for的所有麻烦的原因A
。
np.newaxis
在 NumPy 中,我们使用/None显式引入那些。因此,对于 NumPy,我们可以这样说——
B : 1 , N , 2 , N , 3 , 4 , 5
A : N , 2 , N , 1 , 3 , N , N
,其中N
代表新轴。请注意,我们需要在末尾添加新轴,A
以推动其他维度进行对齐。相反,这在 MATLAB 中默认发生。
使这B
看起来很容易,因为尺寸似乎是有序的,我们只需要在适当的位置添加新的轴 - B[:,None,:,None,:,:,:]
。
创建这样A
的看起来并不简单。忽略N's
,A
我们会有 - A : 2 , 1 , 3
。因此,起点将是置换维度,然后添加被忽略的两个新轴 - A.transpose(1,0,2)[None,:,None,:,:,None,None]
。
到目前为止,我们有——
B (new): B[:,None,:,None,:,:,:]
A (new): A.transpose(1,0,2)[None,:,None,:,:,None,None]
在 NumPy 中,我们可以跳过前导的新轴和尾随的非单例暗淡。所以,我们可以像这样简化——
B (new): B[:,None,:,None]
A (new): A.transpose(1,0,2)[:,None,...,None,None]
最终输出将是这两个扩展版本之间的乘法 -
C = A.transpose(1,0,2)[:,None,...,None,None]*B[:,None,:,None]
运行时测试
我相信@Andras 的帖子意味着等效的np.einsum
实现类似于 : np.einsum('ijk,lmkno->ljmikno',A,B)
。
In [24]: A = np.random.randint(0,9,(10,10,10))
...: B = np.random.randint(0,9,(10,10,10,10,10))
...:
In [25]: C1 = np.einsum('ijk,lmkno->ljmikno',A,B)
In [26]: C2 = A.transpose(1,0,2)[:,None,...,None,None]*B[:,None,:,None]
In [27]: np.allclose(C1,C2)
Out[27]: True
In [28]: %timeit np.einsum('ijk,lmkno->ljmikno',A,B)
10 loops, best of 3: 102 ms per loop
In [29]: %timeit A.transpose(1,0,2)[:,None,...,None,None]*B[:,None,:,None]
10 loops, best of 3: 78.4 ms per loop
In [30]: A = np.random.randint(0,9,(15,15,15))
...: B = np.random.randint(0,9,(15,15,15,15,15))
...:
In [31]: %timeit np.einsum('ijk,lmkno->ljmikno',A,B)
1 loop, best of 3: 1.76 s per loop
In [32]: %timeit A.transpose(1,0,2)[:,None,...,None,None]*B[:,None,:,None]
1 loop, best of 3: 1.36 s per loop