小明第一次拆开乐高套装时,最着迷的不是成品模型,而是那些大大小小的积木块:有的像窄窄的尺子(1×6),有的像扁平的托盘(2×4),还有的是立体方块(2×2×2)。无论形状多么五花八门,每块积木都由一颗颗整齐排列的凸点组成。把“数字”装进这些凸点,你就得到了深度学习世界的绝对主角——张量(Tensor)。张量运算,就是这些“数字积木”之间的拼合游戏:两块同尺寸的积木可以逐颗凸点对碰(逐元素运算);一块积木的所有凸点可以统一涂色(标量乘法);用行槽卡住列销能搭建新结构(矩阵乘法);一张小贴纸还能自动复制到每个位置(广播机制)。这篇文章请乐高当全程向导,把张量的加减乘、缩并、广播和形状变换一网打尽。读完你会发现,PyTorch 和 TensorFlow 里那些高深的 tensor 操作,不过是积木拼搭的另一种说法。

岗位关联

张量运算是深度学习底层计算的“乐高说明书”。掌握它,你就能看懂框架里每个 shape 的来龙去脉,理解模型为什么这样算、算得对不对——这是从“调库选手”升级为“算法工程师”的必经之路。

目录
  1. 可视化演示
  2. 张量初识
  3. 逐元素运算
  4. 标量乘法
  5. 矩阵乘法
  6. 缩并运算
  7. 广播机制
  8. 形状变换
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

展示张量运算三大核心概念:从标量到3D张量的阶数层次、广播机制自动扩展形状对齐、以及爱因斯坦求和约定的索引缩并运算过程。

本节配有交互动效(进入视口后自动加载,约 3KB)。

张量阶数:从标量到多维数组 0D标量(),单个数值 1D向量(n),一维数组 2D矩阵(m,n),行列结构 shape = (d1, d2, ..., dn) 张量阶数等于索引维度的数量。

张量初识

想象一盒刚开封的乐高:1×1 的方块上只有一颗凸点,1×6 的长条上六颗凸点排成一线,2×4 的平板上凸点铺成一个平面,而 2×2×2 的立方体则把凸点撑向了立体空间。无论多复杂的模型,本质都是凸点按特定形状排列。深度学习里的“张量”就是这些“数字积木”——只不过凸点换成了实实在在的数字。

张量是存储数字的多维数组,它的“阶数”就是积木有几个延伸方向:0 阶张量是单个数字(标量),宛如一颗孤零零的凸点;1 阶张量是数字列表(向量),好比一条长条积木;2 阶张量是数字表格(矩阵),恰似一块平面平板;3 阶及以上的张量则是立体甚至超立方的数字排列,每个数字的位置由多个下标共同确定。

在深度学习框架里,你接触到的几乎一切数据都是张量。一张灰度图是 (高,宽) 的矩阵;一张彩色图是 (高,宽,通道) 的三阶张量;一批图片则是 (批大小,高,宽,通道) 的四阶张量。张量的“形状”用 shape 记录每个维度上的长度,就像乐高包装盒侧面印的尺寸规格。

看懂形状这个“尺寸说明书”,后面所有运算规则才能对得上号。没有它,张量加法会乱套,矩阵乘法会撞车,广播机制更无从谈起。

X∈Rd1×d2×⋯×dn\mathcal{X} \in \mathbb{R}^{d_1 \times d_2 \times \cdots \times d_n}
这个公式的意思是:张量 \\(\mathcal{X}\\) 生活在“实数多维空间”里,它的第 1 维长度是 \\(d_1\\),第 2 维是 \\(d_2\\)……总共有 \\(n\\) 个维度方向。
  1. 张量记号 \\(\mathcal{X}\\)用大写花体字母表示整个多维数组,就像乐高积木�的“型号名”。
    X\mathcal{X}
  2. 属于符号 \\(\in\\)表示“位于、属于”,说明这个张量不是凭空存在,而是某个数学空间中的一员。
    ∈\in
  3. 实数空间 \\(\mathbb{R}\\)\\(\mathbb{R}\\) 是所有实数的集合,表示张量里装的每个元素都是普通实数(比如 1.5、-3、1024)。
    R\mathbb{R}
  4. 形状列表 \\(d_1 \times d_2 \times \cdots \times d_n\\)\\(d_1, d_2, \dots, d_n\\) 是每一维的长度,它们相乘的“维数结构”决定了积木的尺寸说明书。
    d1×d2×⋯×dnd_1 \times d_2 \times \cdots \times d_n
  5. 阶数 \\(n\\)右上角的 \\(n\\) 表示总共有多少个维度方向,也就是你这个积木“长”了几个方向。
    nn

逐元素运算

两块尺寸完全相同的乐高平板放在桌上,凸点天然一一对位。你要做的就是把对应位置的凸点按规则处理:上层 1 号凸点碰下层 1 号凸点,2 号碰 2 号,绝不跨位。这种“同位置对碰”就是逐元素运算(element-wise operation),它是张量世界里最朴素也最常用的一类操作。

逐元素运算要求两个张量形状完全一致,然后对同一位置的数字做相同操作。最常见的是逐元素加法和逐元素乘法(也叫哈达玛积,Hadamard product)。注意:这里的“乘法”是每个位置独立相乘,完全不同于后文要讲的矩阵乘法——就像乐高凸点是逐颗拼接,而不是整行整列咬合。

以两个 \\(2 \times 2\\) 矩阵为例,逐元素加法的结果矩阵中,第 \\(i\\) 行第 \\(j\\) 列的元素,等于两个输入矩阵同一位置元素之和。用公式写出来就是:

逐元素运算就像两块同尺寸乐高板逐颗凸点拼接,不会改变积木的外形——结果积木的尺寸永远等于输入尺寸。深度学习里的激活函数(ReLU、Sigmoid)本质上就是对张量做逐元素变换,所以“形状不变”这个特性在神经网络中无处不在。

Ci,j=Ai,j+Bi,jC_{i,j} = A_{i,j} + B_{i,j}
  1. 下标 \\((i,j)\\)乐高平板上第 \\(i\\) 行、第 \\(j\\) 列的那颗凸点坐标,是整个运算的“定位系统”。
    (i,j)(i, j)
  2. 读取 \\(A_{i,j}\\)从积木 A 中取出坐标 \\((i,j)\\) 处的那颗“数字凸点”。
    Ai,jA_{i,j}
  3. 读取 \\(B_{i,j}\\)从积木 B 中取出同一坐标处的数字凸点——两块积木必须同尺寸,否则这里就取空了。
    Bi,jB_{i,j}
  4. 相加操作把两个取出来的数字直接相加,相当于两颗凸点“对碰合并”成一个数值。
    Ai,j+Bi,jA_{i,j} + B_{i,j}
  5. 写入结果 \\(C_{i,j}\\)把合并后的数值放到结果积木 C 的同一坐标位置,形状完全保留。
    Ci,jC_{i,j}

标量乘法

如果你想把一块乐高积木整体换成另一种颜色,最省事的办法是给每一颗凸点都涂上相同的颜料:一颗凸点涂一次,全部涂完,整块积木就焕然一新。这就是标量乘法(scalar multiplication)的直观画面——用一个数字去“涂”遍张量的每一个元素。

标量就是一个独立的数字,也就是 0 阶张量。标量乘法是用这个数字乘上张量的每个元素,相当于把整块积木“整体缩放”。注意它和逐元素乘法的区别:逐元素乘法是两个同形状张量逐颗对碰,而标量乘法是一个数字对全体元素统一操作。

公式写出来非常简洁:结果张量 B 的第 \\(i\\) 行第 \\(j\\) 列元素,等于标量 \\(c\\) 乘以原张量 A 的对应元素。

标量乘法不改变积木的形状,只改变每颗凸点的“颜色深浅”。在神经网络中,学习率(learning rate)本质上就是一个标量:它乘以梯度张量,控制每次参数更新的步长——一步迈多大,全看这个“颜料浓度旋钮”拧到了哪里。

Bi,j=c×Ai,jB_{i,j} = c \times A_{i,j}
  1. 标量 \\(c\\)那个统一颜色的“颜料桶”,它是一个普通实数,没有维度,所以能自由地“触碰”张量里每个元素。
    cc
  2. 原张量元素 \\(A_{i,j}\\)从积木 A 的 \\((i,j)\\) 位置取出待涂色的数字凸点。
    Ai,jA_{i,j}
  3. 乘法操作 \\(c \times A_{i,j}\\)标量与这个元素相乘,相当于给凸点涂上新颜色的同时按比例调整了它的“深浅”。
    c×Ai,jc \times A_{i,j}
  4. 写回 \\(B_{i,j}\\)把缩放后的值放回结果积木 B 的同一位置,逐颗涂完,形状不变。
    Bi,jB_{i,j}

矩阵乘法

乐高能搭出复杂模型,靠的是榫卯卡扣:一块积木的行槽与另一块的列销精确咬合。不同于逐元素的“颗粒对颗粒”,矩阵乘法是“整行与整列”的配对——左矩阵的第 \\(i\\) 行要和右矩阵的第 \\(j\\) 列做一次“内积约会”,约会的产物就是结果矩阵的 \\(C_{i,j}\\)。

具体来说,把左矩阵第 \\(i\\) 行上的每个数字,与右矩阵第 \\(j\\) 列上对应位置的数字相乘,再把所有乘积加起来。用一个求和符号概括就是:

矩阵乘法有一条铁律:左矩阵 \\((m, k)\\) 与右矩阵 \\((k, n)\\) 相乘,内维 \\(k\\) 必须相等,结果形状是 \\((m, n)\\),由两个外维决定。形象地说,只有行槽的宽度和列销的宽度一致,榫卯才能咬合。这个“先乘后加、行配列”的模式正是深度学习全连接层的计算内核。

Ci,j=∑k=1nAi,k×Bk,jC_{i,j} = \sum_{k=1}^{n} A_{i,k} \times B_{k,j}
  1. 求和符号 \\(\sum_{k=1}^{n}\\)让变量 \\(k\\) 从 1 走到 \\(n\\),把沿途每一项都累加起来——这是“流水线汇总”的总开关。
    ∑k=1n\sum_{k=1}^{n}
  2. 左矩阵元素 \\(A_{i,k}\\)取左积木第 \\(i\\) 行第 \\(k\\) 列的那颗凸点,\\(k\\) 是行内游走的位置。
    Ai,kA_{i,k}
  3. 右矩阵元素 \\(B_{k,j}\\)取右积木第 \\(k\\) 行第 \\(j\\) 列的那颗凸点,与 \\(A_{i,k}\\) 形成“行槽对列销”的配对。
    Bk,jB_{k,j}
  4. 相乘并累加每一对 \\(A_{i,k} \times B_{k,j}\\) 先相乘,再交给求和符号累加,最终汇总成一个数。
    Ai,k×Bk,jA_{i,k} \times B_{k,j}
  5. 写入结果 \\(C_{i,j}\\)这个汇总数就是结果积木 \\((i,j)\\) 位置上的凸点值,整行配整列的“婚礼”完成。
    Ci,jC_{i,j}

缩并运算

当你把两块乐高板用力压在一起时,中间的隔层消失了,原本各自独立的两个维度融成一个整体。张量里的“缩并”(contraction)就是这样一种“压合”操作:沿着某个轴把元素求和,从而消去这个维度。

最典型的缩并是向量点积:两个长度相同的向量,对应元素相乘后全部累加,最终得到一个标量。矩阵的迹也是缩并——只对主对角线元素求和。无论是哪种,共同点是“某些轴被求和吃掉,维度消失”。

向量点积的公式是:

矩阵的迹公式类似,只是它只对 \\(i=j\\) 的对角线元素求和:

缩并就是“压合成一块”——两个向量的 \\(n\\) 个分量像 \\(n\\) 对齿轮,咬合转动后只剩下总的力矩(一个数)。在爱因斯坦求和约定中,出现两次的下标就是“要消失的轴”的标记。深度学习里的注意力分数 \\(QK^{\top}\\) 和全连接层的加权求和,本质都是缩并运算。

c=∑i=1nai×bic = \sum_{i=1}^{n} a_i \times b_i
  1. 对角线下标 \\(A_{i,i}\\)只取行号等于列号的对角线凸点。
    Ai,iA_{i,i}
  2. 求和 \\(\sum_{i}\\)把整条主对角线上的元素相加,一个正方形矩阵被压缩成一个数字。
    ∑i\sum_{i}

广播机制

老师发给每个小组一张“规则贴纸”,上面写着“全体加 1”。贴纸只有一份,却会自动复制,贴满教室每个座位——这就是广播(Broadcasting):当两个张量的形状不完全一致时,小张量会自动“复制扩展”成大张量的形状,然后进行逐元素运算。

广播的规则可以概括为三条:第一,从右往左对齐两个张量的形状;第二,某维度长度为 1 时,自动扩展到另一方的长度;第三,若某维度两边都大于 1 且不相等,则直接报错。最常见的例子是标量与张量运算——标量的形状是空的(或视为 \\((1,)\\)),它可以广播到任意形状。

一个经典的广播例子是列向量与行向量相加:

广播机制让代码简洁得惊人:给一批数据统一加一个均值向量,不用写任何 for 循环,一行 X + mean 就完成。就像贴纸自动复制到每个座位,省去手工一张张贴的功夫——这正是 NumPy 和 PyTorch 中 bias 叠加、归一化等操作高效的秘密。

(3,1)⏟列向量+(1,4)⏟行向量→(3,4)\underbrace{(3,1)}_{\text{列向量}} + \underbrace{(1,4)}_{\text{行向量}} \rightarrow (3,4)
  1. 形状 \\((3,1)\\)一个 3 行 1 列的“竖条”积木,只有一列凸点。
    (3,1)(3,1)
  2. 形状 \\((1,4)\\)一个 1 行 4 列的“横条”积木,只有一行凸点。
    (1,4)(1,4)
  3. 从右对齐第 2 维是 1 和 4,取较大值 4;第 1 维是 3 和 1,取较大值 3。
    (3,1)+(1,4)(3,1) + (1,4)
  4. 维度扩展竖条自动复制成 4 列,横条自动复制成 3 行,二者都变成 \\((3,4)\\) 的大积木。
    (3,4)(3,4)
  5. 逐元素相加扩展后的两块同尺寸积木执行普通的逐元素加法。
    Ci,j=Ai,j+Bi,jC_{i,j} = A_{i,j} + B_{i,j}

形状变换

一块 2×4 的乐高平板拆下来,可以重新拼成 4×2 的长条——颗粒总数不变,只是排列方式变了。张量的形状变换正如拆拼重组:元素总数不变,“形状”被重新解释。

最常用的形状变换有三个:reshape 重排形状(要求新旧形状的元素总数一致);转置 交换两个轴(就像把积木旋转 90°);增删维度 用 None 或 unsqueeze 增加一个长度为 1 的轴(相当于给积木加一个“单层包装盒”)。注意 reshape 是按行优先顺序把元素重新排列,不是随意乱改数据。

公式上,reshape 和转置可以写为:

更进一步的“张量积”(外积)则完全不同:它保留所有维度并让它们互相搭配,结果是一个更高阶的张量:

形状变换不增不减元素,只是换了个视角看同一堆积木。无论是把图片展平成向量送进全连接层,还是在注意力机制里调整维度顺序方便计算,都离不开这些“拆了再拼”的操作。

reshape: (2,3)→(3,2)\text{reshape: } (2,3) \rightarrow (3,2)
(A⊤)i,j=Aj,i(A^{\top})_{i,j} = A_{j,i}
  1. 张量积符号 \\(\otimes\\)外积,意思是“两块积木的每个凸点都要和另一块的每个凸点两两组合”。
    ⊗\otimes
  2. 原元素 \\(A_{i,j}\\) 与 \\(B_{k,l}\\)分别取自两块积木的任意位置。
    Ai,j,Bk,lA_{i,j}, B_{k,l}
  3. 两两相乘所有组合都相乘,生成一个 4 阶新张量,每个组合值占据新积木的一个独立位置。
    Ai,j×Bk,lA_{i,j} \times B_{k,l}

AI 应用场景

神经网络的全连接层

阶段:模型前向传播

解决的问题:全连接层要对一批样本同时做线性变换 \\(Y = XW^{\top} + b\\)。传统写法要嵌套循环遍历每个样本、每个特征,代码冗长且慢;用张量矩阵乘法一次算完所有样本,bias 通过广播自动加到每一行。

具体案例:在 PyTorch 中,输入 X 形状为 (batch, 784),权重 W 形状为 (128, 784),一句 X @ W.T + b 就完成了 128 个神经元的线性变换。b 形状是 (128,),广播机制自动把它平铺到 batch 个样本上。这正是全连接层每秒执行数百万次的底层操作。

图像批处理与归一化

阶段:数据预处理

解决的问题:训练时一次要处理几十上百张图片,每张图片是 \\((通道,高,宽)\\) 的三阶张量,拼在一起是四阶张量 \\((批大小,通道,高,宽)\\)。传统逐张处理既慢又容易出错;张量的逐元素运算和广播让“整批归一化”变成一行代码。

具体案例:对一批 CIFAR-10 图像做标准化时,用 (images - mean) / std,其中 mean 和 std 形状是 (3, 1, 1),通过广播自动应用到每张图、每个像素位置。与 for 循环遍历 10000 张图相比,速度提升几十倍,代码量减少一个量级。

注意力机制中的缩并

阶段:模型前向传播

解决的问题:Transformer 的注意力分数需要计算 Query 与 Key 的相似度 \\(\text{score} = QK^{\top}\\),这本质是批量矩阵乘法加缩并。传统实现要求手动管理多维下标,极易出错;张量 API 让高维缩并表达得清晰简洁。

具体案例:在自注意力中,Q 形状为 (batch, heads, seq_len, d_k),K 转置后与 Q 做批量矩阵乘法,得到形状 (batch, heads, seq_len, seq_len) 的注意力分数矩阵。其中每个分数都是两个向量的点积——一次缩并运算,把 d_k 维压缩成一个相似度值。整个 GPT 系列模型的“灵魂”就建立在这个操作上。

Python 演示

python41 行
import numpy as np # 张量初识: 构建一个3阶张量x = np.array([    [[1, 2], [3, 4]],    [[5, 6], [7, 8]]])print("X shape:", x.shape) # 逐元素运算: 对应位置相加a = np.array([[1, 2], [3, 4]])b = np.array([[5, 6], [7, 8]])print("a + b =\n", a + b) # 逐元素乘法(哈达玛积)print("a * b =\n", a * b) # 标量乘法: 每个元素乘3print("3 * a =\n", 3 * a) # 矩阵乘法: 行与列内积print("a @ b =\n", a @ b) # 缩并: 向量点积u = np.array([1, 2, 3])v = np.array([4, 5, 6])print("dot(u, v) =", np.dot(u, v)) # 广播: (3,1) 与 (1,4) 相加col = np.array([[1], [2], [3]])row = np.array([[10, 20, 30, 40]])print("col + row =\n", col + row) # 形状变换: reshape 与 转置c = np.arange(6).reshape(2, 3)print("c =\n", c)print("c.reshape(3, 2) =\n", c.reshape(3, 2))print("c.T =\n", c.T) # 增删维度print("c[None].shape =", c[None].shape)
目的:用 NumPy 把正文里讲的七类张量运算全部跑一遍,对照输出理解每种运算的“积木拼法”。
  1. x = np.array([[[1,2],[3,4]],[[5,6],[7,8]]])用嵌套列表构建 3 阶张量,等价于乐高立体块。
  2. print("X shape:", x.shape)shape 属性返回每个维度的长度,就是积木的“尺寸说明书”。
  3. a + b逐元素加法,要求形状一致,对应位置凸点直接相加。
  4. a * b逐元素乘法(哈达玛积),不是矩阵乘法,每个位置独立相乘。
  5. 3 * a标量乘法,3 这个“颜料”涂遍每个元素,形状不变。
  6. a @ b矩阵乘法,@ 运算符做行×列内积,要求内维匹配。
  7. np.dot(u, v)向量点积,属于缩并运算,两个 3 维向量压合成一个标量。
  8. col + row广播机制,(3,1) 和 (1,4) 自动扩展成 (3,4) 再相加。
  9. c.reshape(3, 2)重塑形状,6 个元素从 2×3 重排成 3×2,总数不变。
  10. c.T转置,交换两个轴,相当于积木旋转 90 度。
  11. c[None]在最前面增加一个长度为 1 的新轴,为广播做准备。

常见误区

误区我以为在 NumPy 里写 `A * B` 就是做矩阵乘法,结果算出来的数字全不对,还找不到原因。

正解A * B 是逐元素乘法(哈达玛积),只有对应位置的数字相乘,就像两块乐高积木逐颗凸点对碰。真正的矩阵乘法要用 A @ B 或 np.dot(A, B),它做的是“整行配整列、先乘后加”。两者一个是“颗粒对颗粒”,一个是“行槽对列销”,完全不是一回事。

为何常见:因为数学课上矩阵乘法通常直接写 \\(AB\\),大家先入为主地认为 * 就是矩阵乘,忽略了编程语言里运算符各有专门含义。

误区只要写 `A + B`,不管两个张量形状差多远,NumPy 都会自动帮我“对齐”成功。

正解广播有严格规则:从右往左对齐,某维度为 1 或缺失才可扩展,如果两个维度都大于 1 且不相等(比如 (3,2) 和 (2,3)),会直接抛 ValueError。广播不是万能胶,更像是“贴纸只能贴到形状兼容的位置,硬贴会撕坏图纸”。报错是保护你,不是系统不智能。

为何常见:网上教程都在强调广播“自动扩展”的便利,却很少强调它“会报错”的边界,导致初学者只记住了方便的一面。

误区一提张量我就想到立体的立方体,觉得至少得有长宽高三个维度才算张量。

正解张量是“多维数组”的统称,0 阶(标量)、1 阶(向量)、2 阶(矩阵)、3 阶及以上都叫张量。就像乐高积木既有 1×1 的方块也有立体件,它们都是积木家族成员。深度学习里连一个损失值(0 阶)、一组梯度(1 阶)、一层权重(2 阶)都叫张量。

为何常见:教科书插图总爱画立体张量,看多了自然以为张量必须“立体”,忽略了阶数从 0 开始的事实。

误区reshape 是万能的,我想把 (2,3) 变成 (4,2) 甚至 (5,5) 都行,数据会自动补齐。

正解reshape 的前提是元素总数完全一致——(2,3) 有 6 个元素,只能重排成各维度乘积为 6 的形状(如 (3,2)、(1,6)、(6,))。它只是“拆了重拼”,不会凭空多出或丢失凸点。想加元素得用拼接(concatenate),想减少得用切片(slicing)。

为何常见:reshape 用起来太顺手,一行代码就变形状,让人误以为它神通广大,忽略了它“不增不减”的本质约束。

面试题

Q1. 张量的“阶”指的是什么?

单选题 · easy

  • A.张量中元素的个数
  • B.张量维度的数量← 正确答案
  • C.张量中数值的大小
  • D.张量存储空间的字节数

答案:B。阶(rank)是张量的维度方向数,就像乐高积木有几个延伸方向。0 阶是标量,1 阶是向量,2 阶是矩阵。A 是元素总数,C 是数值大小,D 是存储量,都与“阶”无关。

Q2. 以下关于逐元素运算的说法正确的是?

多选题 · mid

  • A.要求两张量形状一致← 正确答案
  • B.对应位置独立运算← 正确答案
  • C.结果形状与输入不同
  • D.乘法用符号 @ 表示

答案:AB。逐元素运算像两块同尺寸乐高板逐颗凸点对碰,形状必须一致,结果形状也保持一致,所以 C 错。逐元素乘法用 *,矩阵乘法才用 @,D 错。只有 A 和 B 正确。

Q3. 在 NumPy 中,A * B 表示什么运算?

单选题 · easy

  • A.矩阵乘法
  • B.逐元素乘法← 正确答案
  • C.向量叉积
  • D.张量外积

答案:B。A * B 是哈达玛积,对应位置独立相乘,就像积木逐颗对碰。矩阵乘法要用 A @ B。叉积和外积都是完全不同的运算,分别针对三维向量和张量积场景。

Q4. 矩阵乘法 A(m,k) × B(k,n) 的结果形状是?

单选题 · easy

  • A.(m, n)← 正确答案
  • B.(k, k)
  • C.(m, k)
  • D.(k, n)

答案:A。矩阵乘法中内维 k 被“吃掉”(缩并),结果形状由两个外维决定,即 (m, n)。这就像行槽与列销咬合后,中间隔层消失,只剩外部轮廓。

Q5. 广播机制下,(3,1) 与 (1,4) 的两个张量相加,结果形状是?

单选题 · mid

  • A.(3, 4)← 正确答案
  • B.(3, 1)
  • C.(1, 4)
  • D.直接报错

答案:A。两个形状从右往左对齐:第 2 维 1 和 4 取 4,第 1 维 3 和 1 取 3,最终扩展成 (3,4)。竖条积木复制成 4 列,横条复制成 3 行,拼成完整平面。

Q6. 关于缩并运算,下列说法正确的是?

多选题 · mid

  • A.会使部分维度消失← 正确答案
  • B.向量点积是特例← 正确答案
  • C.运算后形状完全不变
  • D.只适用于一维向量

答案:AB。缩并沿某轴求和消去该维度,A 对。向量点积把一维压缩成标量,是缩并的最简特例,B 对。形状必然改变(维度减少),C 错。矩阵的迹、批量矩阵乘中的内维压缩都是缩并,不止一维向量,D 错。

Q7. 将形状 (2,3) 的张量 reshape 为 (3,2),前提条件是?

单选题 · easy

  • A.元素总数相同← 正确答案
  • B.行列数相同
  • C.维度数相同
  • D.无需任何条件

答案:A。reshape 只是“拆了重拼”,(2,3) 有 6 个元素,(3,2) 也有 6 个,总数一致才行。这就像乐高积木颗粒总数不变,只是排列方式变了。

Q8. 广播运算中,形状 (4,3) 与形状 (3,) 相加,结果形状是?

单选题 · hard

  • A.(4, 3)← 正确答案
  • B.(3, 4)
  • C.(12, 3)
  • D.无法直接广播

答案:A。从右对齐:(3,) 视为 (1,3),第 2 维 3 与 3 相等取 3,第 1 维 4 与缺失(视为 1)取 4,结果为 (4,3)。这相当于把一条“横条积木”复制 4 份叠在每行上。

Q9. 关于矩阵乘法性质,说法正确的有?

多选题 · hard

  • A.满足乘法结合律← 正确答案
  • B.满足乘法交换律
  • C.内维度必须相等← 正确答案
  • D.结果取外维形状← 正确答案

答案:ACD。矩阵乘法满足结合律 (AB)C=A(BC),A 对。但不满足交换律,AB 一般不等于 BA,B 错。左列数必须等于右行数(内维相等),C 对。结果形状由外维决定,D 对。就像榫卯咬合方向有讲究,正着插和反着插完全不同。

Q10. 广播 (3,1,1) 与 (1,4,2) 相加,结果的形状是?

单选题 · extreme

  • A.(3, 4, 2)← 正确答案
  • B.(3, 4, 1)
  • C.(3, 1, 2)
  • D.无法广播运算

答案:A。从右往左对齐三对维度:1 和 2 取 2,1 和 4 取 4,3 和 1 取 3,各维度均兼容(其中一方为 1 即可扩展),结果为 (3,4,2)。这是三维广播的典型例子,类似把“竖条”“横条”“厚片”三块积木拼成完整立体块。