Python numpy点积与矩阵积

Python numpy点积与矩阵积,python,numpy,matrix,Python,Numpy,Matrix,我正在使用形状(N,),(N,3)和(N,3,3)的numpy数组,它们表示三维空间中的标量、向量和矩阵序列。我实现了点式点积、矩阵乘法和矩阵/向量乘法,如下所示: 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

我正在使用形状(N,),(N,3)和(N,3,3)的numpy数组,它们表示三维空间中的标量、向量和矩阵序列。我实现了点式点积、矩阵乘法和矩阵/向量乘法,如下所示:

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)
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)
正如您所看到的,我使用einsum是因为缺少更好的解决方案。令我惊讶的是,我不能使用np.dot。。。这似乎不适合这种需要。有没有一种更具numpythonic的方法来实现这些功能


特别是,如果函数也能通过广播第一个缺失的轴在形状(3,)和(3,3)上工作,那就更好了。我想我需要省略号,但我不太明白如何实现这个结果。

这些操作不能被重塑为一般的BLAS调用,对于这种大小的数组,循环BLAS调用会非常慢。因此,einsum可能是此类操作的最佳选择

您的函数可以用椭圆概括如下:

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

正如工作说明一样,这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])
还是用蛇夫的概括

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.array([np.dot(i,j) for i,j in zip(a,b)])
如果没有定义轴的额外参数,
np.dot
只执行两种可能的组合,这些组合可以表示为:

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


这可能被标记为重复问题。一段时间以来,人们一直在询问如何制作多点产品

建议使用
numpy.core.umath\u tests.matrix\u multiply

等同于:

matrix_multiply(matrices, vectors[..., None])
np.einsum('ijk,ik->ij', matrices, vectors)
矩阵乘法的
C
文档说明:

* 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)))
补充说,这种计算可以使用
*
和sum来完成,例如

(w*v).sum(-1)
(M*v[...,None]).sum(-1)
(A*B.swapaxes(...)).sum(-1)

在进一步测试中,我认为
inner1d
matrix\u multiply
匹配您的
dot
matrix-matrix
产品案例,如果您添加
[…,None]
则匹配
矩阵向量
案例。看起来它们比
einsum
版本(在我的机器和测试阵列上)快2倍


是关于
numpy
上的
@
中缀运算符的讨论。我认为
numpy
开发人员对这个PEP的热情不如Python开发人员。

他们使用
v=np.ones((3,)
A=np.ones((3,3))
。没有一种明显的方式来组合这三种场景。对我来说,奇怪的是,在另一个问题中,我被指到了应该在python中添加一个新的操作符“@”,以准确地执行我需要的操作(如果我理解正确的话)。因此,numpy社区似乎正在建议一个新的python操作符来执行一个目前没有任何专用函数执行的操作……python社区可以添加
@
操作符,但
numpy
开发者将赋予
ndarray
以意义。它是否会包括你想要的广播类型是一个开放的问题。@EmanuelePaolini将矩阵乘法推广到更高维度的问题是,有两种方法可以做到这一点。Numpy认为它是组合内积(),这与您在这里提出的不同。根据两个输入的维度生成
'ij,ij…'
字符串应该不难。还有一种指定这些索引的子列表方法。如果
N=3
,规则是什么?即两(3,3)个阵列。”ij,ij->i'或'jk,ik->ij'或'jk,kl->jl'?很好地解释了为什么BLAS在这里会慢。我正在通过使用中间张量和BLAS调用来优化
einsum
表达式。我不知道这是不是我们应该考虑的一个场景。查看PR。去年,在处理
einsum
bug(包括省略号)时,我编写了一个纯Python模拟器。它可能有助于跟踪索引字符串的解析。代码位于,