AI 数学课程 · 第 21 课,共 180

面向 AI 的转置:重新定向 token 与特征的关系

转置矩阵、预测其形状,并在按词元排列特征与按特征排列词元的视图之间安全切换,同时不丢失底层数值。

分享这篇文章

假设一个批次包含两个 token,每个 token 由三个特征表示。你把数据存储为两行三列。但之后的某个操作却要比较不同 token 之间的特征。数据变了吗,还是这个操作需要另一种方向?

答案通常是转置:同样的六个数,只是以交换行列的方式读取。在机器学习中,这个小操作是形状调试的重要工具,因为轴的含义本身就是张量契约的一部分。

学完本课后,你将能够转置矩阵、预测输出形状、解释语义上发生了什么交换,并在按词元排列特征与按特征排列词元的布局之间做出选择,同时不丢失对底层数值的追踪。

**学习成果:**转置矩阵并解释语义上的交换。

第 18 课:矩阵组织线性规则介绍了矩阵中行和列作为有意义位置的概念。本课的示例和可视化是对 Mathematics for Machine Learning 第 2.2 节中转置记号的原创应用。

矩阵沿着轴存储关系

先看一个形状为 2×32\times3 的矩阵 XX:

X=[2−10431].X = \begin{bmatrix} 2 & -1 & 0\\ 4 & 3 & 1 \end{bmatrix}.

第一个维度长度为 22,所以有两行。第二个维度长度为 33,所以有三列。形状只能告诉我们维度;标签才能告诉我们这些维度的含义。在本课中,让每一行表示一个 token,每一列表示一个特征:

f1f_1f2f_2f3f_3
t1t_12−10
t2t_2431

元素 X2,3=1X_{2,3}=1 的意思是“第 2 行、第 3 列”:第二个 token 的第三个特征。索引不是装饰。如果后续代码把列当作 token,数字看起来仍可能合理,但模型读取的关系已经错了。

定义:转置交换位置,而不是数值

矩阵 XX 的转置写作 XTX^{\mathsf T}。它的定义规则是

(XT)j,i=Xi,j.\left(X^{\mathsf T}\right)_{j,i}=X_{i,j}.

换句话说,位于第 ii 行、第 jj 列的元素会移动到第 jj 行、第 ii 列。因此,如果 XX 的形状是 m×nm\times n,那么 XTX^{\mathsf T} 的形状就是 n×mn\times m:

X∈Rm×n⟹XT∈Rn×m.X\in\mathbb{R}^{m\times n} \quad\Longrightarrow\quad X^{\mathsf T}\in\mathbb{R}^{n\times m}.

转置不会对任何元素取相反数、排序、缩放或重新计算。它重新定向元素与行列标签之间的关系。

六个数保持不变,同时行和列的角色互换。面板下方的原生展开区域提供精确的单元格映射,供不使用颜色或交互式图形的读者查看。

X:token 按行、特征按列

两行 token,每列包含一个特征。

原始矩阵 X,形状为 2×3
词元f₁f₂f₃
t₁2−10
t₂431

词元 → rows · 特征 → columns

Xᵀ:特征按行、token 按列

三行特征,每列包含一个 token。

转置矩阵 Xᵀ,形状为 3×2
特征t₁t₂
f₁24
f₂−13
f₃01

特征 → rows · 词元 → columns

单元格对应关系:X[2, 3] = 1 变为 Xᵀ[3, 2] = 1:这个数保持自身身份不变,只是坐标发生交换。

逐步检查一个单元格

第二个 token 的第三个特征中的数值,在转置后移动到第三行第二列。

转置前
X[2, 3] = 1
转置后
Xᵀ[3, 2] = 1

这个可视化以标签而不是颜色作为主要提示。它的两个语义表格也是完整的回退内容:读者无需 JavaScript,就能核对每个数值、维度和轴的含义。展开区域是原生、可用键盘操作的控件,组件也没有会干扰减少动态效果偏好的持续运动。

例题:转置一个 2×32\times3 矩阵

按照定义逐个位置处理。XTX^{\mathsf T} 的第一行来自 XX 的第一列:

(XT)1,1=X1,1=2,(XT)1,2=X2,1=4.\left(X^{\mathsf T}\right)_{1,1}=X_{1,1}=2, \qquad \left(X^{\mathsf T}\right)_{1,2}=X_{2,1}=4.

第二行来自第二列:

(XT)2,1=X1,2=−1,(XT)2,2=X2,2=3.\left(X^{\mathsf T}\right)_{2,1}=X_{1,2}=-1, \qquad \left(X^{\mathsf T}\right)_{2,2}=X_{2,2}=3.

第三行来自第三列:

(XT)3,1=X1,3=0,(XT)3,2=X2,3=1.\left(X^{\mathsf T}\right)_{3,1}=X_{1,3}=0, \qquad \left(X^{\mathsf T}\right)_{3,2}=X_{2,3}=1.

把这些元素放在一起得到

XT=[24−1301],XT∈R3×2.X^{\mathsf T}= \begin{bmatrix} 2 & 4\\ -1 & 3\\ 0 & 1 \end{bmatrix}, \qquad X^{\mathsf T}\in\mathbb{R}^{3\times2}.

有两个检查可以发现大多数手算错误。第一,形状从 2×32\times3 反转为 3×23\times2。第二,沿着 XTX^{\mathsf T} 的一列向下读取,应该能还原 XX 的一行:它的第一列是 [2,4]T[2,4]^{\mathsf T},也就是 XX 的第一行。

为什么方向对 AI 数据很重要

按行存储的批次便于执行一种常见操作。如果 X∈Rb×dX\in\mathbb{R}^{b\times d} 存储了 bb 个样本、每个样本有 dd 个特征,而特征到输出的权重矩阵 W∈Rk×dW\in\mathbb{R}^{k\times d},那么通常会这样应用:

Y=XWT,(b×d)(d×k)=(b×k).Y=XW^{\mathsf T}, \qquad (b\times d)(d\times k)=(b\times k).

这里的转置没有改变学习到的数值。它让权重的特征轴与批次矩阵的特征列对齐。输出有 bb 行,每行对应一个样本;有 kk 列,每列对应一个输出特征。

同一份数据也可以按特征优先存储为 XT∈Rd×bX^{\mathsf T}\in\mathbb{R}^{d\times b}。当问题是“每个特征如何在样本之间变化”时,这种视图很有用,但它不能与按行批次的视图互换。在把数组传给要求样本位于行中的代码之前,务必先转置回来,或者按照特征优先的约定写出乘积。

XTXX^{\mathsf T}X 与 XXTXX^{\mathsf T} 提出不同的问题

转置常常出现在矩阵乘积旁边。它们的形状揭示了比较的对象:

XTX:(d×b)(b×d)=(d×d),X^{\mathsf T}X: \quad (d\times b)(b\times d)=(d\times d),

因此每个元素都会比较 bb 个样本中的两个特征。相比之下,

XXT:(b×d)(d×b)=(b×b),XX^{\mathsf T}: \quad (b\times d)(d\times b)=(b\times b),

所以每个元素都会比较 dd 个特征中的两个样本。两个乘积没有哪个“转置得更多”;它们回答的是不同的关系问题。

对于本课的矩阵,

XTX=[1021124−211−217]以及XXT=[6−1−125].X^{\mathsf T}X= \begin{bmatrix} 10 & 2 & 11\\ 2 & 4 & -2\\ 11 & -2 & 17 \end{bmatrix} \quad\text{以及}\quad XX^{\mathsf T}= \begin{bmatrix} 6 & -1\\ -1 & 25 \end{bmatrix}.

第一个矩阵是 3×33\times3,因为有三个特征。第二个矩阵是 2×22\times2,因为有两个 token。数值彼此相关,但索引的含义不同。

在 NumPy 中实现交换

对于小型教学示例,显式循环与定义相互对应。它先分配反转后的形状,然后把 matrix[row, column] 复制到 result[column, row]:

import numpy as np

X = np.array([[2, -1, 0],
              [4,  3, 1]])

def transpose_by_loops(matrix):
    rows, columns = matrix.shape
    result = np.empty((columns, rows), dtype=matrix.dtype)
    for row in range(rows):
        for column in range(columns):
            result[column, row] = matrix[row, column]
    return result

X_T_by_loops = transpose_by_loops(X)
X_T = X.T

np.testing.assert_array_equal(X_T_by_loops, X_T)
np.testing.assert_array_equal(X_T.T, X)

feature_relationships = X.T @ X
token_relationships = X @ X.T
print(X_T)
print(feature_relationships.shape, token_relationships.shape)

循环有助于理解,但不适合追求生产速度。NumPy 的 ndarray.T 是二维数组中 transpose 的简写,而 np.transpose 可以推广到具有更多轴的数组。NumPy 官方文档指出了一个重要边界:转置一维数组不会改变它的形状。形状为 (3,) 的向量没有可供交换的独立行轴和列轴;如果需要明确的 (3, 1) 列向量,可以使用 vector[:, np.newaxis],如果需要 (1, 3) 行向量,则可以使用 vector[np.newaxis, :]。

当下一步是矩阵乘积时,要区分运算符:@ 表示矩阵乘法,而 * 表示逐元素乘法。例如,X.T @ X 会缩并 token 轴并返回一个 (3, 3) 矩阵;X.T * X.T 只有在形状匹配时才有效,并会返回逐元素乘积。NumPy 转置参考、.T 参考和矩阵乘积参考是这些区别的实现依据。

边界情况:转置不是逆

把 XTX^{\mathsf T} 称为“撤销” XX 的操作很诱人。但一般来说这是错误的。转置只交换轴;逆矩阵(如果存在)是另一个矩阵 X−1X^{-1},满足

X−1X=I以及XX−1=I.X^{-1}X=I \quad\text{以及}\quad XX^{-1}=I.

逆矩阵要求矩阵是方阵且非奇异。本课的 2×32\times3 矩阵 XX 不可能有普通的双侧逆,因为它的形状甚至无法与方形单位矩阵匹配。即使是方阵,XTX^{\mathsf T} 也只有在特殊情况下才是逆,例如 XX 是正交矩阵。

代码中还有另一个边界情况。对于二维矩阵,表达式 X.T 没有歧义,但对一维 NumPy 数组来说,vector.T 什么也不会做。如果模型需要一个特征列,就要明确创建这个维度,并在矩阵乘法前检查 array.shape。形状错误通常是有用的证据,说明某个轴约定仍未明确。

可靠的调试顺序是:

  1. 说明每个轴的含义。
  2. 在转置前预测新形状。
  3. 手动核对一两个索引映射。
  4. 检查下一个运算符的形状契约。
  5. 确认生成的行和列仍与模型约定相符。

第 22 课将用恒等变换和逆变换讨论线性运算在什么时候确实可以被撤销。转置是其中谨慎的桥梁:它改变方向,让下一个关系可以用兼容的轴表达,但不承诺可逆性。

检查你的理解

Question 1

如果 A 的形状是 4 × 7,Aᵀ 的形状是什么?元素 A[3, 6] 会移动到哪里?

Show the step-by-step solution

第 1 步:反转维度。 转置会把 (m,n)(m,n) 变成 (n,m)(n,m),所以 4×74\times7 矩阵会变成 7×47\times4。

第 2 步:交换索引。 定义规则是 (AT)j,i=Ai,j(A^{\mathsf T})_{j,i}=A_{i,j}。因此,第 3 行、第 6 列的元素会移动到第 6 行、第 3 列。

第 3 步:解释结果。 数值不会改变;只有行列位置以及相应的标签发生交换。

Question 2

手算 M = [[5, −2, 1], [0, 4, 3]] 的转置,并说明结果的形状。

Show the step-by-step solution

第 1 步:数原来的轴。 MM 有两行三列,因此它的转置必须有三行两列。

第 2 步:把列复制为行。 第一列 [5,0][5,0] 变成第一行;第二列 [−2,4][-2,4] 变成第二行;第三列 [1,3][1,3] 变成第三行。

第 3 步:写出结果。

MT=[50−2413],MT∈R3×2.M^{\mathsf T}=\begin{bmatrix}5&0\\-2&4\\1&3\end{bmatrix}, \qquad M^{\mathsf T}\in\mathbb{R}^{3\times2}.

Question 3

一个矩阵的行表示文档,列表示词汇特征。转置后,行和列分别表示什么?

Show the step-by-step solution

第 1 步:命名原来的轴。 转置前,每一行是一个文档,每一列是一个词汇特征。

第 2 步:应用索引规则。 每个文档-特征数值都会从 (document,feature)(document, feature) 移动到 (feature,document)(feature, document)。

第 3 步:说明新的含义。 转置后,每一行是一个词汇特征,每一列是一个文档。数值没有改变,但按行执行的操作现在会跨文档而不是跨特征聚合。这就是为什么轴的含义必须与数组一起传递。

Question 4

为什么 (Aᵀ)ᵀ = A?这个恒等式不代表什么?

Show the step-by-step solution

第 1 步:交换一次。 第一次转置把元素 (i,j)(i,j) 送到 (j,i)(j,i)。

第 2 步:再交换一次。 第二次转置把同一个元素从 (j,i)(j,i) 送回 (i,j)(i,j)。每个数值都回到原来的位置。

第 3 步:保持区分。 这个恒等式说明转置是一个对合:执行两次相同的方向交换,就会回到原矩阵。它不表示 ATA^{\mathsf T} 是逆矩阵,也不表示第一次操作以逆矩阵的意义撤销了一个学习到的变换。

Question 5

对于形状为 (8, 5) 的 X,XᵀX 和 XXᵀ 的形状是什么?每一对索引分别比较什么?

Show the step-by-step solution

第 1 步:转置形状。 XTX^{\mathsf T} 的形状是 (5,8)(5,8)。

第 2 步:计算第一种乘积。 (5,8)(8,5)→(5,5)(5,8)(8,5)\to(5,5),所以 XTXX^{\mathsf T}X 比较八个样本中的五个特征之间的成对关系。

第 3 步:计算第二种乘积。 (8,5)(5,8)→(8,8)(8,5)(5,8)\to(8,8),所以 XXTXX^{\mathsf T} 比较八个样本之间、沿着它们五个特征的成对关系。反转乘积顺序改变的是问题,而不只是记号。

Question 6

在 NumPy 中,为什么 vector.T 会让形状为 (3,) 的向量保持在 (3,),而 vector[:, np.newaxis] 的形状是 (3, 1)?

Show the step-by-step solution

第 1 步:检查轴的数量。 形状 (3,) 描述了一个长度为三的轴。.T 没有独立的行轴和列轴可以交换。

第 2 步:读取 NumPy 的行为。 一维转置是一个保持不变的视图,所以 vector.T.shape 仍然是 (3,)。

第 3 步:明确添加所需的轴。 vector[:, np.newaxis] 会在三个元素之后插入第二个轴,得到 (3, 1)。这是一个明确的列向量,可以按预期形状参与矩阵乘法。

Question 7

学习者说 Xᵀ 是 X 的逆,因为两次转置会返回 X。准确的纠正是什么?

Show the step-by-step solution

第 1 步:区分两个恒等式。 (XT)T=X(X^{\mathsf T})^{\mathsf T}=X 表示两次交换轴会恢复原来的位置。

第 2 步:说明逆矩阵的要求。 逆矩阵必须与 XX 相乘,在适当的一侧产生单位矩阵。

第 3 步:使用边界情况。 本课的 2×32\times3 矩阵不是方阵,因此根本不可能有普通的双侧逆。即使是方阵,也不一定等于其转置的逆。转置是方向操作;逆是可逆性属性。

Question 8

批次 X 的形状是 (32, 768),权重矩阵 W 的形状是 (256, 768)。为什么 X @ W 无效?哪个转置能得到通常的按行批次输出?

Show the step-by-step solution

第 1 步:检查尝试的乘积。 形状是 (32,768)(32,768) 和 (256,768)(256,768)。矩阵乘法要求左矩阵的列数 768 等于右矩阵的行数 256,但它们不相等,因此 X @ W 无效。

第 2 步:转置权重。 WTW^{\mathsf T} 的形状是 (768,256)(768,256)。

第 3 步:检查修正后的乘积。 (32,768)(768,256)→(32,256)(32,768)(768,256)\to(32,256)。32 行仍然表示样本,256 列表示输出特征。转置修正的是轴约定,而不是学习到的权重数值。

资料来源

  1. Mathematics for Machine Learning companion website
  2. Mathematics for Machine Learning book PDF
  3. NumPy documentation: numpy.transpose
  4. NumPy documentation: ndarray.T
  5. NumPy documentation: numpy.matmul