Python Numpy 矩阵乘法/形状不兼容/违抗数学?

Python Numpy Matrix Multiplication / Shape Not Compatible / Defying Math?

考虑以下代码:

X = np.array([[1,1,1],
            [2,2,2],
            [3,3,3],
            [4,4,4]]) # shape of (4,3)

print("Matrix X is:\n", X)


print("\n --------- TEST 1 ---------\n")

W = np.array([1,2,3]) # 1D array (row)
print("W is:", W)
print("X * W is:\n", X*W)

print("\n --------- TEST 2 ---------\n")

W = np.array([[1,2,3]]) # 2D array (shape 1,3)
print("W is:", W)
print("X * W is:\n", X*W)


print("\n --------- TEST 3 ---------\n")

W = np.array([[1,2,3]]).T # 2D array (shape 3,1)
print("W is:\n", W)
print("X * W is:\n", X*W)


print("\n --------- TEST 4 ---------\n")

W = np.array([1,2,3]) # 1D array (row)
print("W is:\n", W)
print("X @ W is:\n", X@W.T) # dot product


print("\n --------- TEST 5 ---------\n")

W = np.array([[1,2,3]]) # 2D array (shape 1,3)
print("W is:\n", W)
print("X @ W is:\n", X@W.T) # dot product


print("\n --------- TEST 6 ---------\n")

W = np.array([[1,2,3]]).T # 2D array (shape 3,1)
print("W is:\n", W)
print("X @ W is:\n", X@W) # dot product

输出(省略测试 3)为:

Matrix X is:
 [[1 1 1]
 [2 2 2]
 [3 3 3]
 [4 4 4]]

 --------- TEST 1 ---------

W is: [1 2 3]
X * W is:
 [[ 1  2  3]
 [ 2  4  6]
 [ 3  6  9]
 [ 4  8 12]]

 --------- TEST 2 ---------

W is: [[1 2 3]]
X * W is:
 [[ 1  2  3]
 [ 2  4  6]
 [ 3  6  9]
 [ 4  8 12]]

 --------- TEST 4 ---------

W is:
 [1 2 3]
X @ W is:
 [ 6 12 18 24]

 --------- TEST 5 ---------

W is:
 [[1 2 3]]
X @ W is:
 [[ 6]
 [12]
 [18]
 [24]]

 --------- TEST 6 ---------

W is:
 [[1]
 [2]
 [3]]
X @ W is:
 [[ 6]
 [12]
 [18]
 [24]]

问题:

测试 3 将失败并显示以下错误消息:

ValueError: operands could not be broadcast together with shapes (4,3) (3,1)

但是从数学上讲这是不正确的,应该可以正常工作。 N 列矩阵乘以 N 行矩阵或向量是有效的数学运算。在这种情况下,X 中有 3 列,W 中有 3 行。那么这是怎么回事?

我预计测试 1 和测试 2 会出现这种错误,但也许可以理解 numpy 如何 "reshape" W 以便它们匹配。但是 Test3 出错了?真的吗?

我认为这与 Numpy 中的广播有关?在数学上似乎有点违反直觉。 Numpy 是否需要让乘数的列(第二个因子/从现在开始 "F2")的形状始终与被乘数的列(第一个因子/从现在开始 "F1")相匹配?所以基本上它遍历 F1 中的每一行并将该行的每一列与 F2 的列相乘?

重新审视这个数学上正确的是: 列 F1 = 行 F2。 这似乎是: F1 列 = F2 列。

还有更多:

在测试 3 之后将其扩展到点积,从技术上讲,测试 6 应该不起作用,但突然它起作用了(而且在数学上是正确的!)。

除此之外,测试 6 对我来说在数学上很扎实,所以这里没有问题。

我的以下假设是否正确:

测试 4:

如果 F2 是一维行向量,点积仍将完全相同(就像它是列向量一样),但它会输出一维行向量。这基本上是像这样的乘法的唯一真正区别?在引擎盖下,完全相同的工作本质上就像二维矢量一样发生?

测试 5:

所以在数学上我假设 Numpy 是 "auto-transforming" F2 (Row) 内部进入一个列,所以测试 6 和测试 5 真的是一样的。

PS:写这个问题我想我已经意识到 Numpy 再次匹配位置。几乎就像某种地图网格系统。但是,老实说,不允许进行 Test 3 仍然让我感到困惑。如果您正在寻找 "grids" 不相互对齐,这是有道理的,但肯定可以实现吗?如果测试 6 有效,我不明白为什么测试 3 不应该。

谢谢!

我认为您将 * 运算符与 @ 运算符混淆了。

  • 前者是逐元素乘法,两个操作数的形状必须匹配或可以是"broadcasted"。
  • 后者是矩阵乘法,所以只有X.shape[1]W.shape[0]重合才能使用。

您在测试 3 中遇到的错误是因为 numpy brodcasting 遵循特定规则,这些规则可以在 here 中找到,并且不适用于测试 3,另一方面,在测试 6 中,您完全能够按预期进行矩阵乘法。

除非XWnumpy.matrix,否则*不是用于矩阵乘法而是用于广播。

您可以在 broadcasting documentation 中查看此操作仅在

时有效

both dimensions are equal, or one of them is 1

这就是为什么它适用于测试 1 和 2 的原因。 一旦 W 具有形状 (1,3),它将在操作期间被拉伸成具有 (4,3) 形状的数组

您可以了解有关阵列广播和拉伸的更多信息here

在测试 3 中,W 具有形状 (3,1),这会导致第一维发生冲突 (4 来自 X,3 来自 W) 因为它不遵守 2 规则上面提到。 另一方面,第二个维度会很好 (3,1)