numpy点()和Python 3.5+matrix乘法之间的区别@

我最近搬到了Python 3.5,注意到新的matrix乘法运算符(@)有时候与numpy的点运算符有所不同。 例如,对于3D数组:

import numpy as np a = np.random.rand(8,13,13) b = np.random.rand(8,13,13) c = a @ b # Python 3.5+ d = np.dot(a, b) 

@运算符返回形状数组:

 c.shape (8, 13, 13) 

np.dot()函数返回:

 d.shape (8, 13, 8, 13) 

我怎样才能重现与numpy点相同的结果? 还有其他的重大差异吗?

@运算符调用数组的__matmul__方法,而不是dot 。 该方法也作为np.matmul函数在API中np.matmul

 >>> a = np.random.rand(8,13,13) >>> b = np.random.rand(8,13,13) >>> np.matmul(a, b).shape (8, 13, 13) 

从文档:

matmuldot有两个重要的不同之处。

  • 乘以标量是不允许的。
  • 就像matrix是元素一样广播matrix的堆栈。

最后一点清楚地表明, dotmatmul方法在传递3D(或更高维)数组时行为不同。 更多的引用文档:

对于matmul

如果其中一个参数是ND,N> 2,则将其作为最后两个索引中的一系列matrix处理,并相应地进行广播。

对于np.dot

对于二维arrays,它相当于matrix乘法,而一维arrays是向量的内积(无复共轭)。 对于N维,它是a的最后一个轴和b的倒数第二个和的积

@ajcr的答案解释了dotmatmul (由@符号调用)是如何不同的。 通过一个简单的例子,我们可以清楚地看到在“堆栈”或张量上运行时,这两者的行为是如何不同的。

为了澄清差异,需要一个4x4arrays,并返回一个2x4x3'matrix'或张量的dot积和matmul产品。

 import numpy as np fourbyfour = np.array([ [1,2,3,4], [3,2,1,4], [5,4,6,7], [11,12,13,14] ]) twobyfourbythree = np.array([ [[2,3],[11,9],[32,21],[28,17]], [[2,3],[1,9],[3,21],[28,7]], [[2,3],[1,9],[3,21],[28,7]], ]) print('4x4*4x2x3 dot:\n {}\n'.format(np.dot(fourbyfour,twobyfourbythree))) print('4x4*4x2x3 matmul:\n {}\n'.format(np.matmul(fourbyfour,twobyfourbythree))) 

每个操作的产品如下所示。 注意点积如何,

在a的最后一个轴上的和和b的倒数第二个和

以及如何通过将matrix一起广播来形成matrix乘积。

 4x4*4x2x3 dot: [[[232 152] [125 112] [125 112]] [[172 116] [123 76] [123 76]] [[442 296] [228 226] [228 226]] [[962 652] [465 512] [465 512]]] 4x4*4x2x3 matmul: [[[232 152] [172 116] [442 296] [962 652]] [[125 112] [123 76] [228 226] [465 512]] [[125 112] [123 76] [228 226] [465 512]]] 

在math上,我认为numpy中的更有意义

(a,b)_ {i,j,k,a,b,c} = \ sum_m a_ {i,j,k,m} b_ {a,b,m,c}

因为当a和b是vector时它给出点积,或者当a和b是matrix时它是matrix相乘


至于numpy中的matmul操作,它由结果的部分组成,可以定义为

matmul (a,b)_ {i,j,k,c} = \ sum_m a_ {i,j,k,m} b_ {i,j,m,c}


所以,你可以看到matmul(a,b)返回一个小形状的数组,它具有较小的内存消耗,在应用程序中更有意义。 特别是结合广播 ,你可以得到

matmul (a,b)_ {i,j,k,l} = \ sum_m a_ {i,j,k,m} b_ {j,m,l}

例如。


从以上两个定义中,您可以看到使用这两个操作的要求。 假设a.shape =(s1,s2,s3,s4)b.shape =(t1,t2,t3,t4)

  • 要使用点(a,b),你需要

      1. **t3=s4**; 
  • 要使用matmul(a,b),你需要

    1. T3 = S4
    2. t2 = s2 ,或者t2和s2中的一个是1
    3. t1 = s1 ,或者t1和s1中的一个为1

使用下面的一段代码来说服自己。

代码示例

 import numpy as np for it in xrange(10000): a = np.random.rand(5,6,2,4) b = np.random.rand(6,4,3) c = np.matmul(a,b) d = np.dot(a,b) #print 'c shape: ', c.shape,'d shape:', d.shape for i in range(5): for j in range(6): for k in range(2): for l in range(3): if not c[i,j,k,l] == d[i,j,k,j,l]: print it,i,j,k,l,c[i,j,k,l]==d[i,j,k,j,l] #you will not see them