bla*_*laz 94 python numpy matrix-multiplication python-3.5
我最近转向Python 3.5并注意到新的矩阵乘法运算符(@)有时与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)
Run Code Online (Sandbox Code Playgroud)
的@运算符返回形状的阵列:
c.shape
(8, 13, 13)
Run Code Online (Sandbox Code Playgroud)
而np.dot()函数返回:
d.shape
(8, 13, 8, 13)
Run Code Online (Sandbox Code Playgroud)
如何用numpy dot重现相同的结果?还有其他重大差异吗?
Ale*_*ley 109
该@运营商称阵列的__matmul__方法,而不是dot.该方法也作为函数存在于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)
Run Code Online (Sandbox Code Playgroud)
从文档:
matmul与dot两个重要方面不同.
- 不允许使用标量进行乘法运算.
- 矩阵堆栈一起广播,就好像矩阵是元素一样.
最后一点清楚地表明dot,matmul当传递3D(或更高维)数组时,方法的行为会有所不同.从文档中引用更多:
用于matmul:
如果任一参数是ND,N> 2,则将其视为驻留在最后两个索引中的矩阵堆栈并相应地进行广播.
用于np.dot:
对于2-D阵列,它相当于矩阵乘法,对于1-D阵列相当于矢量的内积(没有复共轭).对于N维,它是a的最后一个轴和b的倒数第二个轴的和积
Nic*_*mer 15
仅供参考,@其numpy的等价物dot,并matmul都同样快。(用perfplot创建的图,我的一个项目。)
重现情节的代码:
import perfplot
import numpy
def setup(n):
A = numpy.random.rand(n, n)
x = numpy.random.rand(n)
return A, x
def at(data):
A, x = data
return A @ x
def numpy_dot(data):
A, x = data
return numpy.dot(A, x)
def numpy_matmul(data):
A, x = data
return numpy.matmul(A, x)
perfplot.show(
setup=setup,
kernels=[at, numpy_dot, numpy_matmul],
n_range=[2 ** k for k in range(15)],
)
Run Code Online (Sandbox Code Playgroud)
小智 12
在数学中,我认为numpy 中的点更有意义
点(a,b)_{i,j,k,a,b,c} =
因为当 a 和 b 是向量时它给出点积,或者当 a 和 b 是矩阵时给出矩阵乘法
至于numpy 中的matmul操作,它由部分点结果组成,可以定义为
所以,你可以看到matmul(a,b)返回一个小形状的数组,它具有更小的内存消耗并且在应用程序中更有意义。特别是,结合广播,你可以得到
matmul (a,b)_{i,j,k,l} =
例如。
从上面的两个定义,你可以看到使用这两个操作的要求。假设a.shape=(s1,s2,s3,s4)和b.shape=(t1,t2,t3,t4)
要使用dot(a,b)你需要
要使用matmul(a,b)你需要
使用下面的一段代码来说服自己。
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
Run Code Online (Sandbox Code Playgroud)
@ajcr的答案解释了dot和matmul(由@符号调用)的不同之处.通过一个简单的例子,可以清楚地看到两者在"堆叠的基质"或张量上进行操作时的行为方式.
为了澄清差异,需要使用4x4阵列,dot并matmul使用2x4x3'堆叠的matricies'或张量返回产品和产品.
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)))
Run Code Online (Sandbox Code Playgroud)
每个操作的产品如下所示.注意点积是怎样的,
... a的最后一个轴和b的倒数第二个的和积
以及如何通过将矩阵一起广播来形成矩阵产品.
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]]]
Run Code Online (Sandbox Code Playgroud)
这是一个比较np.einsum以显示指数是如何预测的
np.allclose(np.einsum('ijk,ijk->ijk', a,b), a*b) # True
np.allclose(np.einsum('ijk,ikl->ijl', a,b), a@b) # True
np.allclose(np.einsum('ijk,lkm->ijlm',a,b), a.dot(b)) # True
Run Code Online (Sandbox Code Playgroud)