我正在处理形状(N,),(N,3)和(N,3,3)的numpy数组,这些数组表示3D空间中的标量,向量和矩阵的序列。我已经实现了逐点点积,矩阵乘法和矩阵/向量乘法,如下所示:
def dot_product(v, w):
return np.einsum('ij, ij -> i', v, w)
def matrix_vector_product(M, v):
return np.einsum('ijk, ik -> ij', M, v)
def matrix_matrix_product(A, B):
return np.einsum('ijk, ikl -> ijl', A, B)
正如您所看到的,我使用einsum缺乏更好的解决方案。令我惊讶的是,我无法使用np.dot ......这似乎不适合这种需要。是否有更多的numpythonic方式来实现这些功能?
特别是如果函数也可以通过广播第一个缺失的轴来对形状(3,)和(3,3)起作用,那将是很好的。我想我需要省略号,但我不太了解如何实现结果。
答案 0 :(得分:4)
这些操作不能重新整形为一般的BLAS调用,对于这种大小的数组,循环BLAS调用会非常慢。因此,einsum可能是这种操作的最佳选择。
您的函数可以使用省略号进行推广,如下所示:
def dot_product(v, w):
return np.einsum('...j,...j->...', v, w)
def matrix_vector_product(M, v):
return np.einsum('...jk,...k->...j', M, v)
def matrix_matrix_product(A, B):
return np.einsum('...jk,...kl->...jl', A, B)
答案 1 :(得分:2)
正如工作笔记一样,这3个计算也可以写成:
np.einsum(A,[0,1,2],B,[0,2,3],[0,1,3])
np.einsum(M,[0,1,2],v,[0,2],[0,1])
np.einsum(w,[0,1],v,[0,1],[0])
或者与Ophion的概括
np.einsum(A,[Ellipsis,1,2], B, ...)
根据输入数组的维度生成[0,1,..]
列表应该不难。
通过专注于概括einsum
表达式,我错过了你想要重现的是N
小点积的事实。
np.array([np.dot(i,j) for i,j in zip(a,b)])
值得注意的是np.dot
使用快速编译的代码,并专注于数组较大的计算。你的问题在于计算许多小点产品。
如果没有额外的参数来定义轴,np.dot
只执行2种可能的组合,可以表示为:
np.einsum('i,i', v1, v2)
np.einsum('...ij,...jk->...ik', m1, m2)
dot
的运算符版本将面临同样的限制 - 没有额外的参数来指定轴的组合方式。
注意tensordot
概括dot
的内容可能也很有启发性:
def tensordot(a, b, axes=2):
....
newshape_a = (-1, N2)
...
newshape_b = (N2, -1)
....
at = a.transpose(newaxes_a).reshape(newshape_a)
bt = b.transpose(newaxes_b).reshape(newshape_b)
res = dot(at, bt)
return res.reshape(olda + oldb)
它可以对多个轴执行求dot
。但是在完成转置和重新整形后,计算将成为带有2d数组的标准dot
。
这可能被标记为重复问题。一段时间以来人们都在询问有关多点产品的问题。
Matrix vector multiplication along array axes
建议使用numpy.core.umath_tests.matrix_multiply
https://stackoverflow.com/a/24174347/901925等同于:
matrix_multiply(matrices, vectors[..., None])
np.einsum('ijk,ik->ij', matrices, vectors)
C
备注的matrix_multiply
文档:
* This implements the function
* out[k, m, p] = sum_n { in1[k, m, n] * in2[k, n, p] }.
来自同一目录的 inner1d
对(N,n)
向量
inner1d(vector, vector)
np.einsum('ij,ij->i', vector, vector)
# out[n] = sum_i { in1[n, i] * in2[n, i] }
两者都是UFunc
,可以处理最正确的广播。在numpy/core/test/test_ufunc.py
中,这些函数用于执行UFunc
机制。
matrix_multiply(np.ones((4,5,6,2,3)),np.ones((3,2)))
https://stackoverflow.com/a/16704079/901925补充说,这种计算可以使用*
和总和来完成,例如
(w*v).sum(-1)
(M*v[...,None]).sum(-1)
(A*B.swapaxes(...)).sum(-1)
在进一步测试时,我认为inner1d
和matrix_multiply
与您的dot
和matrix-matrix
产品案例相匹配,如果您添加matrix-vector
案例[...,None]
1}}。看起来它们比einsum
版本快2倍(在我的机器和测试阵列上)。
https://github.com/numpy/numpy/blob/master/doc/neps/return-of-revenge-of-matmul-pep.rst
是@
上numpy
中缀运算符的讨论。我认为numpy
开发人员对这个PEP的兴趣不如Python。