numpy 矩阵的向量化乘法

numpy Vectorized multiplication 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)

我将这些数组的集合矢量化以生成

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

然后我需要执行类似

的操作
A.T @ B @ C

我想以

的形式得到结果
np.array([A1.T @ B1 @ C1, A2.T @ B2 @ C2, A3.T @ B3 @ C3])

这些三元组矩阵的实际数量是数十万,所以我想使用 numpy 向量化来实现,例如某种形式的张量乘法

我已经尝试应用 np.tensordot,但它没有按预期正常工作:

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

产生:

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

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

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

而我希望它只是那些标记数组的数组(每个对应于 Ai.T @ Bi)

简单的 A @ B 产生相同的结果...

那么有没有一种方法可以产生预期的结果而无需在第一毛钱上循环

您好,您可以矢量化您的问题,添加一些维度并进行乘积:

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

编辑

您也可以使用 Einsten 求和符号解决同样的问题(我刚刚意识到)。这样更直接也更容易。

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

形状:

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)

子数组乘积是一个标量:

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

matmul/@ 可以将第一个维度 (3) 视为一个批次,如果我们将所有数组扩展到 3d,请记住我们想要“A 的最后一个与第二个到最后一个 B " 规则最后 2 个维度:

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

相当于einsum是:

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

这里batchi一路重复,而jk就是大家熟悉的矩阵乘积变量