如何在Python中为每对矩阵向量进行内积运算?

5
假设我有一堆矩阵A和向量b。
As = array([[[1, 7], [3, 8]],
            [[2, 1], [5, 9]],
            [[7, 2], [8, 3]]])
bs = array([[8, 0], [8, 8], [7, 3]])

当我执行np.inner(As, bs)时,会得到以下结果:
array([[[  8,  64,  28], [ 24,  88,  45]],
       [[ 16,  24,  17], [ 40, 112,  62]],
       [[ 56,  72,  55], [ 64,  88,  65]]])

但我不需要所有的内积。我的需求是,每个矩阵只需与每个向量计算一次。

我可以这样做:

np.array(map(lambda (a, b): np.inner(a, b), zip(As, bs)))

然后我得到了预期的矩阵:

array([[  8,  24], [ 24, 112], [ 55,  65]])

现在我不想使用zip、map等方式,因为我需要执行这个操作超过10**6次(用于图像处理,确切地说是用于GMM)。 有没有办法可以使用numpy、scipy等库来为我完成此操作?(快速且高效)

1个回答

4
您可以使用 np.einsum 函数进行操作 -
np.einsum('ijk,ik->ij',As, bs)

解释

通过 np.array(map(lambda (a, b): np.inner(a, b), zip(As, bs))),我们选择As的第一个元素作为a,选择bs的第一个元素作为b,并且进行内积计算。因此,我们执行的操作是:

In [19]: np.inner(As[0],bs[0])
Out[19]: array([ 8, 24])

In [20]: np.inner(As[1],bs[1])
Out[20]: array([ 24, 112])

In [21]: np.inner(As[2],bs[2])
Out[21]: array([55, 65])

可以将其看作一个循环,我们迭代3次,对应于As的第一轴的长度,这与bs相同。因此,在查看lambda表达式时,在每次迭代中,我们有 a = As [0]&b = bs [0]a = As [1]&b = bs [1]等。

Asbs都是3D2D的,让我们将它们表示为迭代器,并在我们的头脑中想象内积。因此,在迭代时,我们会有a:j,kb:m。通过ab之间的内积,我们将失去a的第二轴和b的第一轴。因此,我们需要将km对齐。因此,我们可以假设b具有与k相同的迭代器。从a返回到As,从b返回到bs,本质上,我们将在内积/总和缩减中失去As的第三轴和bs的第二轴。对于Asbs的第一轴进行迭代意味着我们需要在这些总和缩减下保持对齐。

让我们做个总结。

我们有输入数组的涉及到的迭代器,如下所示-

As :  i x j x k 
bs :  i x k

所需操作的步骤:

  • As的第一个轴与bs的第一个轴对齐。
  • 使用对第二个bs的求和约简,丢弃As的第三个轴。

因此,我们将得到输出的迭代器i,j

np.einsum是一种非常有效的实现,特别适用于需要使输入数组的一个或多个轴相互对齐的情况。

有关einsum的更多信息,请查看前面提供的文档链接,还可以参考这个问答


1
@PiMathCLanguage 添加了一些注释以帮助理解,请查看。 - Divakar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接