a=np.arange(8).reshape(2,2,2)
b=np.arange(4).reshape(2,2)
print(np.matmul(a,b))
结果是:
[[[ 2 3]
[ 6 11]]
[[10 19]
[14 27]]]
我不明白这个结果,有人可以解释一下吗?
简短回答:它将第二个 2d 矩阵“广播”到 3d 矩阵,然后执行“映射”,因此它将元素子矩阵映射到结果中的新子矩阵。
[numpy-doc]上的文档所说:
numpy.matmul(a, b, out=None)
两个数组的矩阵乘积。
行为取决于以下方式的参数。
- 如果两个参数都是二维的,它们会像传统矩阵一样相乘。
- 如果任一参数是 N 维,N > 2,则将其视为驻留在最后两个索引中的矩阵堆栈并广播 相应地。
- 如果第一个参数是一维的,则通过在其维度前添加 1 将其提升为矩阵。矩阵相乘后 删除前面的 1。
- 如果第二个参数是一维的,则通过在其维度上附加 1 将其提升为矩阵。矩阵相乘后 删除附加 1。
所以这里第二条适用。所以首先第二个矩阵也被“广播”到 3d 变体,这意味着我们乘以:
array([[[0, 1],
[2, 3]],
[[4, 5],
[6, 7]]])
与:
array([[[0, 1],
[2, 3]],
[[0, 1],
[2, 3]]])
我们将它们视为堆叠矩阵。所以首先我们乘以:
array([[0, 1], array([[0, 1],
[2, 3]]) x [2, 3]])
这给了我们:
array([[ 2, 3],
[ 6, 11]])
然后是元素第二个子矩阵:
array([[4, 5], array([[0, 1],
[6, 7]]) x [2, 3]])
这给了我们:
array([[10, 19],
[14, 27]])
因此,我们将它们叠加到结果中,并得到:
>>> np.matmul(a, b)
array([[[ 2, 3],
[ 6, 11]],
[[10, 19],
[14, 27]]])
尽管行为已被完美定义,但最好谨慎使用此功能,因为对于 3d 矩阵与 2d 矩阵的“矩阵乘积”可能是什么样子,还有其他“有意义的”定义,因此不使用这些定义在这里。
您可以更明确地将乘法视为求和。因此,如果
a
的尺寸为 (i, j, k)
并且 b
的尺寸为 (k, l)
,那么结果的尺寸将为 (i, j, l)
。
在代码中可以这样写(非常明确):
def matmul(a, b):
dim1, dim2, dim3 = a.shape
dim4 = b.shape[1]
c = np.zeros(shape=(dim1, dim2, dim4))
for i in range(dim1):
for j in range(dim2):
for l in range(dim4):
c[i, j, l] = sum(a[i, j, k] * b[k, l] for k in range(dim3))
return c
如果您尝试打印此
matmul()
函数的结果,它将与 numpy 函数相同。
注意:这个函数效率非常低,而且只有当a有3维而b有2维时才有效,但它可以很容易地推广。