矩阵加法与矩阵乘法
理解了向量运算之后,升级到矩阵。矩阵乘法是理解神经网络前向传播的关键——全连接层的本质就是矩阵乘法。
矩阵加法:对应位置相加
两个形状相同的矩阵,把对应位置的元素加起来——和向量加法一样直观。
矩阵乘法:行与列的点积
矩阵乘法没有「对应位置乘」那么简单。为什么?
矩阵的深层含义是「线性变换」——它会把一个向量映射到另一个向量。
两个矩阵相乘 AB,在几何上的意思是:先做 B 变换,再做 A 变换。所以 AB 的运算法则必须反映「复合变换」的数学结构,而不是简单的逐元素相乘。
例如:A 表示「水平拉伸 2 倍」, B 表示「逆时针旋转 90°」。AB 表示「先旋转再拉伸」——这与 BA(先拉伸再旋转)完全不同,所以矩阵乘法不满足交换律。
运算法则是:
第 i 行 →
第 j 列 ↓
(i, j)
左矩阵的第 i 行与右矩阵的第 j 列做点积 → 结果矩阵的 (i, j) 位置的值。
维度匹配规则
\( (m \times \color{#e74c3c}{n}) \;\times\; (\color{#e74c3c}{n} \times p) = (m \times p) \)
A 的列数 必须等于 B 的行数。两个标红的 n 必须相等。
结果的形状 = (A 的行数, B 的列数)
矩阵乘法 不满足交换律:AB ≠ BA(通常情况)。
甚至维度可能不匹配导致 BA 无定义——这是初学者最容易出错的地方。
矩阵乘法的本质是线性变换的复合
乘以矩阵 A → 做完一次变换;再乘以矩阵 B → 做完第二次变换。
两次变换复合 = 一次 (BA) 变换。这就是矩阵乘法这样定义的原因。
生活例子
小卖部收入计算
三天的销量矩阵(行=日期,列=商品):
| 可乐 | 薯片 | 泡面 | |
|---|---|---|---|
| 周一 | 10 | 5 | 3 |
| 周二 | 8 | 7 | 4 |
| 周三 | 12 | 4 | 6 |
价格矩阵(行=商品,列=店铺):
| 店铺1 | 店铺2 | |
|---|---|---|
| 可乐 | 3 | 3.5 |
| 薯片 | 5 | 5.5 |
| 泡面 | 4 | 4.0 |
销量矩阵 (3×3) × 价格矩阵 (3×2) = 收入矩阵 (3×2)。
结果的每一格 = 某天在某个店铺的总收入。
数学定义
矩阵加法
\[ (\mathbf{A} + \mathbf{B})_{ij} = a_{ij} + b_{ij} \]前提:A 和 B 形状完全相同。
矩阵乘法
设 A 为 m×n,B 为 n×p,则 C = AB 为 m×p:
\[ c_{ij} = \sum_{k=1}^{n} a_{ik} b_{kj} \]Python 动手实践
实例
A_runoob = np.array([[10, 5, 3], [8, 7, 4], [12, 4, 6]])
price = np.array([[3, 3.5], [5, 5.5], [4, 4.0]])
# 矩阵加法(同形状)
bonus = np.array([[1, 0, 1], [0, 1, 0], [1, 1, 0]])
total = A_runoob + bonus
print("A + bonus:\n", total)
# 矩阵乘法:(3×3) @ (3×2) = (3×2)
revenue = A_runoob @ price
print("\n收入矩阵 A @ price:\n", revenue)
print("形状:", revenue.shape)
# 手动验证第(0,0)位置
manual = A_runoob[0,0]*price[0,0] + A_runoob[0,1]*price[1,0] + A_runoob[0,2]*price[2,0]
print(f"\n手动验证 [0,0]: {manual} == {revenue[0,0]}")
# 维度不匹配的陷阱
print(f"\nA 形状: {A_runoob.shape}") # (3, 3)
print(f"price.T 形状: {price.T.shape}") # (2, 3)
# A @ price.T → (3,3) @ (2,3) 不匹配!
# 正确:price.T @ A → (2,3) @ (3,3) = (2,3)
print(f"price.T @ A 形状: {(price.T @ A_runoob).shape}") # (2, 3)
收入矩阵 A @ price: [[67. 72. ] [75. 79.5] [80. 88. ]] 形状: (3, 2) A 形状: (3, 3) price.T 形状: (2, 3) price.T @ A 形状: (2, 3)
交互式矩阵乘法可视化
下方演示 2×2 矩阵 A 乘以 2×1 向量 v,观察线性变换如何将圆上的点映射到椭圆上:
AI 中的应用场景
全连接层 = 矩阵乘法
nn.Linear(d_in, d_out) 的本质:权重矩阵 W(d_out × d_in)乘以输入向量 x(d_in 维),得到输出(d_out 维)。
处理 batch 数据时,输入 X 是 (batch, d_in) 矩阵,计算 \( Y = XW^T \) 或 \( Y = WX^T \),这是一次矩阵乘法完成整个 batch 的前向计算。GPU 对矩阵乘法有专门硬件加速(Tensor Core)。
注意力机制的 QK^T
Transformer 中 Q 和 K 都是 (seq_len, d_k) 矩阵。\( QK^T \) 是 seq_len×d_k 乘 d_k×seq_len,得到 (seq_len, seq_len) 的注意力分数矩阵。
GPT-4 级别的大模型中,seq_len 可达 128K,这个矩阵乘法的计算量占整个推理成本的很大一部分。FlashAttention 算法就是专门优化这个矩阵乘法的显存访问模式。
卷积的矩阵乘法实现(im2col)
卷积操作可以展开为矩阵乘法:把输入图像按滑动窗口展开为一个大矩阵(im2col),然后把卷积核也展平为矩阵,两者相乘。这让卷积能利用高度优化的 GEMM(通用矩阵乘法)库来加速。
LoRA 微调中的矩阵分解
LoRA 在预训练权重旁加两个小矩阵 A 和 B 的乘积:\( W' = W + AB \)。这里的 AB 就是矩阵乘法——A 是 d×r,B 是 r×d,乘积是 d×d 的低秩矩阵。一个矩阵乘法实现了参数高效的微调。
