虽然矩阵加法、减法和标量乘法是按元素进行运算的,但矩阵乘法的工作方式大不相同。它是一种基本运算,根据涉及行和列的规则组合两个矩阵,而不仅仅是对应元素。此运算对机器学习中的许多原理都非常重要,例如转换数据点、在神经网络中连接计算步骤以及表示线性方程组。了解维度规则矩阵乘法是一种将两个矩阵组合起来的操作。为了执行矩阵乘法,被相乘的两个矩阵必须满足关于其维度的特定条件。例如,如果矩阵 $A$ 的维度是 $m imes n$(即 $m$ 行 $n$ 列),而矩阵 $B$ 的维度是 $n imes p$(即 $n$ 行 $p$ 列),则矩阵积 $AB$ 才会被定义。最重要的一点是,第一个矩阵($A$)的列数必须等于第二个矩阵($B$)的行数。在此情况下,两者都是 $n$。结果矩阵,我们称之为 $C = AB$,其维度将是 $m \times p$。它将具有与第一个矩阵 ($A$) 相同的行数,以及与第二个矩阵 ($B$) 相同的列数。$$ \underbrace{A}{m \times n} \quad \times \quad \underbrace{B}{n \times p} \quad = \quad \underbrace{C}_{m \times p} $$如果内部维度不匹配($n \neq n$),则矩阵无法按该顺序相乘。计算积:行与列的点积我们如何找出结果矩阵 $C$ 内部的值?每个元素 $C_{ij}$(矩阵 $C$ 中第 $i$ 行第 $j$ 列的元素)是通过取矩阵 $A$ 的第 $i$ 行与矩阵 $B$ 的第 $j$ 列的点积来计算的。请记住,两个向量 $u = [u_1, u_2, \dots, u_n]$ 和 $v = [v_1, v_2, \dots, v_n]$ 的点积是 $u \cdot v = u_1v_1 + u_2v_2 + \dots + u_nv_n = \sum_{k=1}^{n} u_k v_k$。对于矩阵乘法 $C = AB$,若 $A$ 是 $m \times n$ 矩阵且 $B$ 是 $n \times p$ 矩阵:$$ C_{ij} = (\text{A 的第 } i \text{ 行}) \cdot (\text{B 的第 } j \text{ 列}) $$从数学上讲,如果 $A_{ik}$ 是 $A$ 中第 $i$ 行第 $k$ 列的元素,并且 $B_{kj}$ 是 $B$ 中第 $k$ 行第 $j$ 列的元素,则:$$ C_{ij} = \sum_{k=1}^{n} A_{ik} B_{kj} $$这意味着您将 $A$ 的行和 $B$ 的列中的对应元素相乘,然后将这些乘积相加。digraph G { rankdir=LR; node [shape=plaintext]; splines=false; edge [arrowhead=none]; subgraph cluster_A { label="矩阵 A (m x n)"; A [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"><TR><TD>...</TD></TR><TR><TD BGCOLOR="#a5d8ff">第 i 行</TD></TR><TR><TD>...</TD></TR></TABLE>>]; } subgraph cluster_B { label="矩阵 B (n x p)"; B [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"><TR><TD>...</TD><TD BGCOLOR="#ffc9c9">第 j 列</TD><TD>...</TD></TR></TABLE>>]; } subgraph cluster_C { label="结果 C (m x p)"; C [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"><TR><TD>...</TD><TD>...</TD><TD>...</TD></TR><TR><TD>...</TD><TD BGCOLOR="#96f2d7">C_ij</TD><TD>...</TD></TR><TR><TD>...</TD><TD>...</TD><TD>...</TD></TR></TABLE>>]; } A:s -> C:w [label="点积", style=dashed, arrowhead=normal, color="#495057"]; B:s -> C:e [style=dashed, arrowhead=normal, color="#495057"]; {rank=same; A; B;} {rank=same; C;} }这是一个可视化表示,展示了矩阵 $A$ 的第 $i$ 行和矩阵 $B$ 的第 $j$ 列如何通过点积组合来计算结果矩阵 $C$ 中的元素 $C_{ij}$。数值例子让我们将一个 $2 \times 3$ 矩阵 $A$ 乘以一个 $3 \times 2$ 矩阵 $B$。结果 $C$ 应该是一个 $2 \times 2$ 矩阵。$$ A = \begin{bmatrix} 1 & 2 & 3 \ 4 & 5 & 6 \end{bmatrix} \quad B = \begin{bmatrix} 7 & 8 \ 9 & 1 \ 2 & 3 \end{bmatrix} $$结果矩阵是 $C = AB$: $$ C = \begin{bmatrix} C_{11} & C_{12} \ C_{21} & C_{22} \end{bmatrix} $$让我们计算每个元素:$C_{11}$: $A$ 的第 1 行和 $B$ 的第 1 列的点积。 $C_{11} = (1 \times 7) + (2 \times 9) + (3 \times 2) = 7 + 18 + 6 = 31$$C_{12}$: $A$ 的第 1 行和 $B$ 的第 2 列的点积。 $C_{12} = (1 \times 8) + (2 \times 1) + (3 \times 3) = 8 + 2 + 9 = 19$$C_{21}$: $A$ 的第 2 行和 $B$ 的第 1 列的点积。 $C_{21} = (4 \times 7) + (5 \times 9) + (6 \times 2) = 28 + 45 + 12 = 85$$C_{22}$: $A$ 的第 2 行和 $B$ 的第 2 列的点积。 $C_{22} = (4 \times 8) + (5 \times 1) + (6 \times 3) = 32 + 5 + 18 = 55$因此,结果矩阵是: $$ C = AB = \begin{bmatrix} 31 & 19 \ 85 & 55 \end{bmatrix} $$NumPy 中的矩阵乘法NumPy 使矩阵乘法变得简单。自 Python 3.5 以来,在两个 NumPy 数组(表示矩阵)之间执行矩阵乘法的标准方式是使用 @ 运算符。让我们使用 NumPy 执行与上面相同的计算:import numpy as np # 定义矩阵 A 和 B A = np.array([[1, 2, 3], [4, 5, 6]]) B = np.array([[7, 8], [9, 1], [2, 3]]) # 检查形状 print(f"A 的形状: {A.shape}") # Output: Shape of A: (2, 3) print(f"B 的形状: {B.shape}") # Output: Shape of B: (3, 2) # 使用 @ 运算符执行矩阵乘法 C = A @ B print(f"\n矩阵 A:\n{A}") print(f"矩阵 B:\n{B}") print(f"结果 C = A @ B:\n{C}") # 输出: # Result C = A @ B: # [[31 19] # [85 55]] print(f"C 的形状: {C.shape}") # Output: Shape of C: (2, 2)结果与我们手动计算的结果一致。注意 NumPy 如何在内部处理行与列的点积。您也可能会遇到 np.dot(A, B) 或 A.dot(B)。对于二维数组(矩阵),这些函数执行标准的矩阵乘法,就像 @ 运算符一样。然而,@ 运算符通常更受欢迎,因为它对于矩阵乘法是明确的,而 np.dot 对于维度超过两个的数组行为不同。为了在处理矩阵时保持清晰,请坚持使用 @。一个重要说明:不可交换性与常规数字(标量)的乘法不同,常规数字乘法有 $a \times b = b \times a$,而矩阵乘法通常不具有可交换性。这意味着,在大多数情况下:$$ AB \neq BA $$有时,即使 $AB$ 被定义, $BA$ 也可能甚至未被定义。例如,在我们上面的例子中,$A$ 是 $2 \times 3$ 矩阵,$B$ 是 $3 \times 2$ 矩阵。积 $AB$ 被定义,结果是一个 $2 \times 2$ 矩阵。那 $BA$ 呢?这里,$B$ 是 $3 \times 2$ 矩阵,$A$ 是 $2 \times 3$ 矩阵。内部维度匹配(2 和 2),所以 $BA$ 是被定义的。结果矩阵 $BA$ 将是 $3 \times 3$。因为 $AB$ 是 $2 \times 2$ 矩阵,$BA$ 是 $3 \times 3$ 矩阵,它们显然不能相等。让我们用 NumPy 计算 $BA$ 来看一看:# 计算 BA (注意顺序) C_BA = B @ A print(f"\n结果 BA = B @ A:\n{C_BA}") # 输出: # Result BA = B @ A: # [[ 39 54 69] # [ 13 23 33] # [ 14 19 24]] print(f"BA 的形状: {C_BA.shape}") # Output: Shape of BA: (3, 3)正如所料,$BA$ 是一个 $3 \times 3$ 矩阵,与 $AB$ 完全不同。即使 $A$ 和 $B$ 是相同大小的方阵,并且 $AB$ 和 $BA$ 都被定义并具有相同的维度,结果通常也会不同。矩阵相乘的顺序非常重要。这对计算机图形学和机器学习等方面有重要影响,在这些方面,矩阵运算序列表示变换或计算步骤的序列。改变顺序会改变结果。