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)
从文档:
matmul
和dot
有两个重要的不同之处。
- 乘以标量是不允许的。
- 就像matrix是元素一样广播matrix的堆栈。
最后一点清楚地表明, dot
和matmul
方法在传递3D(或更高维)数组时行为不同。 更多的引用文档:
对于matmul
:
如果其中一个参数是ND,N> 2,则将其作为最后两个索引中的一系列matrix处理,并相应地进行广播。
对于np.dot
:
对于二维arrays,它相当于matrix乘法,而一维arrays是向量的内积(无复共轭)。 对于N维,它是a的最后一个轴和b的倒数第二个和的积
@ajcr的答案解释了dot
和matmul
(由@
符号调用)是如何不同的。 通过一个简单的例子,我们可以清楚地看到在“堆栈”或张量上运行时,这两者的行为是如何不同的。
为了澄清差异,需要一个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),你需要
- T3 = S4
- t2 = s2 ,或者t2和s2中的一个是1
- 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