python 中的多维矩阵乘法

Multidimensional matrix multiplication in python

我有维度 500x2000x30 的矩阵 A 和维度 30x5 的矩阵 B。

你可以认为 2000x30 有 500 个实例,因为矩阵 A 的维度是 500x2000x30

我想将 A 中的每个 1x2000x30 与矩阵 B 相乘以获得大小为 1x2000x5 的新矩阵。

A X B 应该给我一个维度矩阵 500x2000x5

显然通过矩阵 A 循环 500 次是一个解决方案,但是有没有有效的方法来实现这个?

编辑:A 和 B 都是 numpy 数组

如果您有 numpy 个数组,您可以为此使用 np.dot 函数:

np.dot(A, B)

它会做你想做的,即将 A 的最后一个轴与 B 的第一个轴“收缩”:

For 2-D arrays it is equivalent to matrix multiplication, and for 1-D arrays to inner product of vectors (without complex conjugation). For N dimensions it is a sum product over the last axis of a and the second-to-last of b:

 dot(a, b)[i,j,k,m] = sum(a[i,j,:] * b[k,:,m])

首先,任何多维数组都是展平数组的 n 次 b 拆分。 2,3,2 维数组 [ [ [A,B],[C,D],[E,F] ], [ [G,H],[I,J],[K,L] ] ] 只是将 A,B,C,D,E,F,G,H,I,J,K,L 分成 2 块,然后是 3 块,然后又是 2 块,这就是你的多维数组。这里的向量是二维的。

其次,二维矩阵乘法也是定长向量乘法与组合。 (n,m)*(m,l)维矩阵乘法实际上是l个不同的m个向量和n个不同的m个向量的逐项乘法和结果之和。两个不同的 m 向量的 l 次 n 组合。

当你得到它时,你可以简单地将 20 维矩阵转换为具有相同向量大小的二维矩阵并将它们相乘并重新整形。

快速示例:

import numpy as np

a=np.random.random(120).reshape(2,5,3,4)
b=np.random.random(120).reshape(5,3,4,2)

br=np.rollaxis(b,3,2).reshape(30,4).T  
# converted all combinations to a series of 4 dimension vectors here 

test1=np.matmul(a.reshape(30,4),br).reshape(2,5,3,5,3,2)
test2=np.dot(a,b)

np.all(test1==test2)

returns

array(True)

让我们基本上为所有组合(维度)做这件事

sa=a.shape
sb=b.shape
res=np.ndarray([sa[0],sa[1],sb[0],sb[1],sa[2],sb[3]])
for i in range(a.shape[0]):
  for j in range(a.shape[1]):
    for k in range(b.shape[0]):
      for n in range(b.shape[1]):
        x=np.matmul(a[i,j],b[k,n])
        np.append(res,x)
print(np.any(res==np.dot(a,b).reshape(2,5,5,3,3,2)))

returns

True

用例:

假设我们有一个案例,例如对于 10 种不同的材料和 20 种不同的几何形状,3 维向量中的 3 个不同物理量将被矩阵乘以用于几何和物理处理神经网络层,该神经网络层将使用遗传选择算法进行计算,该算法有5个不同群体的神经连接系数向量,每个群体有100个不同的基因序列(群体)和20个神经节点。在这种情况下,您可能会立即计算它,或者您可以以某种方式将此计算序列化为两个平面数组,并将其发送到您的 gpu 或 cpu 根据您的并发空闲 ram 数量。在这种情况下,您可能想了解此计算的工作原理。

任何情况下多维矩阵计算向量的组合都是逐项计算的 您可能希望将第一项与最后一项的秒向量相乘,然后对其余项求和。这取决于您,但了解它的工作原理很重要。 所以这是我用来理解这个的一个简单的例子。

[ [ [A,B],[C,D],[E,F] ], [ [G,H],[I,J],[K,L] ] ] --> ABCDEFGHIJKL [ [ [1,2],[3,4],[5,6] ], [ [7,8],[9,0],[€,$] ] ] --> 1234567890€$

逐项使用运算符(相乘)将第一个数组移动向量大小 (2)

ABCDEFGHIJKL   CDEFGHIJKLAB  FGHIJKLABCDE ...
1234567890€$   1234567890€$  1234567890€$ ...

所有组合都来了

追加所有这些并重塑并使用另一个运算符 (+)

[A+2*B],[C*3+D*4],[E*5,F*6] ...... [I*€+J*$] 

希望这有助于并节省时间来掌握这一点。