numpy dot产品和矩阵产品

时间:2015-01-31 19:00:34

标签: python numpy matrix

我正在处理形状(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)起作用,那将是很好的。我想我需要省略号,但我不太了解如何实现结果。

2 个答案:

答案 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)

在进一步测试时,我认为inner1dmatrix_multiply与您的dotmatrix-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。