简体   繁体   English

numpy 矩阵的向量化乘法

[英]numpy Vectorized multiplication of matrices

So what Im trying to do is this...所以我想做的是这个......

Suppose we have a set of matrices:假设我们有一组矩阵:

a1 = [1, 2]
b1 = [[3, 4], [5, 6]]
c1 = [7, 8]

a2 = [2, 4]
b2 = [[6, 8], [10, 12]]
c2 = [14, 16]

a3 = [3, 5]
b3 = [[7, 9], [11, 13]]
c3 = [15, 17]

A1 = np.array(a1)
B1 = np.array(b1)
C1 = np.array(c1)

A2 = np.array(a2)
B2 = np.array(b2)
C2 = np.array(c2)

A3 = np.array(a3)
B3 = np.array(b3)
C3 = np.array(c3)

I vectorized the collection of those arrays to produce我对这些数组的集合进行矢量化以生成

A = np.array([A1, A2, A3])
B = np.array([B1, B2, B3])
C = np.array([C1, C2, C3])

Then I need to perform something like然后我需要执行类似的操作

A.T @ B @ C

And I'd like to get the restult in the form of我想得到结果的形式

np.array([A1.T @ B1 @ C1, A2.T @ B2 @ C2, A3.T @ B3 @ C3])

The actual number of these triplets of matrices is in hundreds of thousands , so I'd like to do it using numpy vectorization, eg some form of tensor multiplication这些矩阵三元组的实际数量是数十万,所以我想使用 numpy 向量化来做,例如某种形式的张量乘法

I've tried to apply np.tensordot, but it doesn't qutie work as expected:我试图应用 np.tensordot,但它没有按预期工作:

np.tensordot(A, B, axes=((1), (1)))

Produces:产生:

array([[**[13, 16]**,
        [26, 32],
        [29, 35]],

       [[26, 32],
        **[52, 64]**,
        [58, 70]],

       [[34, 42],
        [68, 84],
        **[76, 92]**]])

Whereas I'd like it to be just an array of those marked arrays (each corresponding to Ai.T @ Bi)而我希望它只是那些标记数组的数组(每个对应于 Ai.T @ Bi)

The simple A @ B produces the same result...简单的 A @ B 产生相同的结果......

So is there a way to produce the expected result without a loop over first dime那么有没有一种方法可以产生预期的结果,而无需在第一角钱上进行循环

Hi you can vectorize your problem adding some dimensions and doing the product:嗨,您可以矢量化您的问题,添加一些维度并制作产品:

import numpy as np


a1 = [1, 2]
b1 = [[3, 4], [5, 6]]
c1 = [7, 8]

a2 = [2, 4]
b2 = [[6, 8], [10, 12]]
c2 = [14, 16]

a3 = [3, 5]
b3 = [[7, 9], [11, 13]]
c3 = [15, 17]

A1 = np.array(a1)
B1 = np.array(b1)
C1 = np.array(c1)

A2 = np.array(a2)
B2 = np.array(b2)
C2 = np.array(c2)

A3 = np.array(a3)
B3 = np.array(b3)
C3 = np.array(c3)

A = np.array([A1, A2, A3])
B = np.array([B1, B2, B3])
C = np.array([C1, C2, C3])

Res = (A[:,:,None]*B*C[:,None,:]).sum((1,2))

EDIT编辑

You also can solve the same problem using Einsten sum notation (i've just realized that).您也可以使用 Einsten sum notation 解决同样的问题(我刚刚意识到这一点)。 This is more straight forward and also easier.这更直接,也更容易。

res = np.einsum('ni,nij,nj->n',A,B,C)

The shapes:形状:

In [272]: A.shape
Out[272]: (3, 2)
In [273]: B.shape
Out[273]: (3, 2, 2)
In [274]: C.shape
Out[274]: (3, 2)

the subarray product is a scalar:子阵列乘积是一个标量:

In [275]: (A1.T@B1@C1).shape
Out[275]: ()
In [276]: (A1.T@B1@C1)
Out[276]: 219

matmul/@ can treat the first dimension (3), as a batch one if we expand all arrays to 3d, keeping in mind that we want the "the last of A with the 2nd to the last B" rule the last 2 dimensions: matmul/@可以将第一个维度 (3) 视为批处理,如果我们将所有数组扩展到 3d,请记住我们希望“A 的最后一个与第二个到最后一个 B”规则最后两个维度:

In [277]: A[:,None,:]@B@C[:,:,None]
Out[277]: 
array([[[ 219]],

       [[1752]],

       [[2704]]])
In [278]: _.shape
Out[278]: (3, 1, 1)
In [279]: (A[:,None,:]@B@C[:,:,None])[:,0,0]
Out[279]: array([ 219, 1752, 2704])

the equivalent einsum is:等效的einsum是:

In [280]: np.einsum('ij,ijk,ik->i', A, B, C)
Out[280]: array([ 219, 1752, 2704])

Here batch i is repeated all the way, while j and k are the familiar matrix product variables.这里batch i一直重复,而jk是熟悉的矩阵乘积变量。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM