Python 三维阵列的Numpy元素级产品

Python 三维阵列的Numpy元素级产品,python,arrays,numpy,matrix,vectorization,Python,Arrays,Numpy,Matrix,Vectorization,我有两个形状为(N,2,2)的3d阵列A和B,我想根据N轴乘以元素,每个2x2矩阵上的矩阵积。通过循环实现,它看起来像 C[i] = dot(A[i], B[i]) 有没有一种不使用循环的方法可以做到这一点?我已经调查了tensordot,但还没能让它发挥作用。我想我可能需要类似于张量的东西(a,b,轴=([1,2],[2,1]),但这给了我一个NxN矩阵。看起来你在沿着第一个轴对每个切片进行矩阵乘法。同样,你也可以这样使用- np.einsum('ijk,ikl->ijl',A,B)

我有两个形状为(N,2,2)的3d阵列A和B,我想根据N轴乘以元素,每个2x2矩阵上的矩阵积。通过循环实现,它看起来像

C[i] = dot(A[i], B[i])

有没有一种不使用循环的方法可以做到这一点?我已经调查了tensordot,但还没能让它发挥作用。我想我可能需要类似于张量的东西(a,b,轴=([1,2],[2,1]),但这给了我一个NxN矩阵。

看起来你在沿着第一个轴对每个切片进行矩阵乘法。同样,你也可以这样使用-

np.einsum('ijk,ikl->ijl',A,B)
我们也可以使用-

在Python3.x上,这个
matmul
操作简化为-

标杆管理 接近-

def einsum_based(A,B):
    return np.einsum('ijk,ikl->ijl',A,B)

def matmul_based(A,B):
    return np.matmul(A,B)

def forloop(A,B):
    N = A.shape[0]
    C = np.zeros((N,2,2))
    for i in range(N):
        C[i] = np.dot(A[i], B[i])
    return C
时间安排-

In [44]: N = 10000
    ...: A = np.random.rand(N,2,2)
    ...: B = np.random.rand(N,2,2)

In [45]: %timeit einsum_based(A,B)
    ...: %timeit matmul_based(A,B)
    ...: %timeit forloop(A,B)
100 loops, best of 3: 3.08 ms per loop
100 loops, best of 3: 3.04 ms per loop
100 loops, best of 3: 10.9 ms per loop

您只需要对张量的第一个维度执行操作,该维度标记为
0

c = tensordot(a, b, axes=(0,0))
这将如你所愿。此外,您不需要轴的列表,因为您正在执行操作的只是一个维度。使用
轴([1,2],[2,1])
可以交叉乘以第二维度和第三维度。如果你用索引表示法(爱因斯坦求和约定)写它,它对应于
c[i,j]=a[i,k,l]*b[j,k,l]
,因此你收缩了你想要保留的索引

编辑:好的,问题是两个3d对象的张量积是一个6d对象。由于收缩涉及成对的索引,因此不可能通过
tensordot
操作获得3d对象。诀窍是将计算一分为二:首先对索引执行
tensordot
以执行矩阵运算,然后采用张量对角线将4d对象缩减为3d。在一个命令中:

d = np.diagonal(np.tensordot(a,b,axes=()), axis1=0, axis2=2)

用张量表示法
d[i,j,k]=c[i,j,i,k]=a[i,j,l]*b[i,l,k]

我得到了一个
(2,2,2,2)
形状,而不是
(10,2,2)
,所以可能有问题。对不起,我给了你一个错误的答案,请看我的编辑。谢谢Divakar。我希望我能使用这个,但我有点被一个没有einsum的旧版本的numpy卡住了。是否有tensordot等效调用?我永远无法理解
einsum
是如何工作的。你有没有读过一些东西教你语法是如何工作的?@rayryeng只是一些官方文档和几个小时的游戏。还有很多其他的事情我看到人们用它做,所以我需要弄清楚!就像您使用
permute
一样,只需使用它即可。最近,我又通过玩弄它来弄明白了。@Remy你终于可以访问
np.einsum
支持的NumPy了吗?我真的不知道如何让tensordot在这种情况下工作。@Divakar是的,我在自己的电脑上工作过,而且速度真的快得多,我要咬紧牙关,升级其他人的numpy。再次感谢。
c = tensordot(a, b, axes=(0,0))
d = np.diagonal(np.tensordot(a,b,axes=()), axis1=0, axis2=2)