想象你是一支合唱团的指挥。高声部站成 2 排、每排 3 人,低声部只有 3 个人。乐谱要求每个声部同时唱完每个小节——可低声部人数不够,怎么唱?你正想给低声部重新编曲,经验丰富的老指挥拦住你:“别急,让低声部自动'分身',第一排唱一遍、第二排再唱一遍。”人还是那 3 个人,声音却覆盖了整个声部。这个“自动分身对齐声部”的智慧,就是数值计算框架中的广播(Broadcasting)机制。 在 AI 的世界里,张量就是合唱团的声部。NumPy、PyTorch 等框架在处理不同形状的张量时,不会粗暴地报错或要求你手动复制数据,而是像那位老指挥一样,让形状自动对齐、让维度为 1 的张量逻辑扩展,最终以极少的代码完成复杂的批量运算。学会广播,你就掌握了张量运算中最优雅的“分身术”。

岗位关联

广播是 AI 从业者必须刻进直觉的运算规则:它能让你用一行代码替代三层 for 循环,是特征归一化、批量距离计算等高频操作的性能基石。

目录
  1. 可视化演示
  2. 广播本质
  3. 形状对齐
  4. 兼容判定
  5. 维度扩展
  6. 算术运算
  7. 广播陷阱
  8. 实战应用
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

展示广播形状对齐规则(右向左比较)、维度扩展过程(4→1×4→3×4)与矩阵归一化应用(减均值除标准差),帮助理解张量广播核心机制。

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

'+captions.rules+'

广播本质

让我讲一个合唱团的故事。你是指挥,带领一支合唱团。高声部有 2 排、每排 3 人,低声部只有 3 个人。乐谱要求每个声部同时唱完四个小节。按照常识,你得让低声部的 3 个人重新编排成 6 个人的效果,或者让他们每排都跑一遍。但老指挥并不着急——他挥了挥手,低声部的 3 个人“分身”站到了每一排,人没变,声音却覆盖了整个声部区域。这就是广播。NumPy 的广播机制,就是那个聪明的老指挥。

在数值计算的世界里,张量就是合唱团里的声部。有的张量是矩阵,形状记作 (2, 3),表示 2 行 3 列;有的张量是向量,形状记作 (3,),只有 3 个元素。当它们相加时,普通的做法是先把向量复制成 2 行,再逐位相加。但复制要额外占用内存,效率低。广播则像那位指挥家:不实际复制数据,只在逻辑上“分身”,让不同形状的张量对齐后直接运算。

广播规则的核心在于:运算前,框架会检查两个张量的形状,判断能否对齐。如果对齐成功,较小的张量会被“虚拟地”扩展成较大的形状,然后执行逐元素运算。整个过程不产生真实的数据拷贝,因此既省内存又省时间。NumPy、PyTorch、TensorFlow 等主流框架都原生支持广播,这意味着学会广播,就掌握了跨框架的通用技能。

你看,合唱团里低声部 3 个人站在 2 排位置上的画面,正是广播在张量世界中的投影。它把“人少”的声部自动补齐到与“人多”的声部一致,不换人、不加人,却让整场合唱听起来天衣无缝。

shape(A)=(2,3),shape(B)=(3,) ⟹ shape(A+B)=(2,3)\text{shape}(A)=(2,3),\quad \text{shape}(B)=(3,)\ \Longrightarrow\ \text{shape}(A+B)=(2,3)
这个公式说明:一个 2 行 3 列的矩阵与一个长度为 3 的向量相加,向量被广播扩展后,结果仍是 2 行 3 列。
  1. 矩阵 A 的形状(2, 3) 表示 A 是 2 行 3 列的矩阵,共 6 个元素,行号 i 取 0 或 1,列号 j 取 0、1、2。
    shape(A)=(2,3)\text{shape}(A)=(2,3)
  2. 向量 B 的形状(3,) 表示 B 是长度为 3 的向量,只有 3 个元素,列号 j 取 0、1、2。
    shape(B)=(3,)\text{shape}(B)=(3,)
  3. 广播后的结果A 与 B 相加,结果 C 的形状仍是 (2, 3)——B 被广播扩展为 2 行,每行都是自己的 3 个元素。
    shape(A+B)=(2,3)\text{shape}(A+B)=(2,3)

形状对齐

合唱排练继续。指挥家走到低声部面前,发现一个问题:高声部站成 2 排 3 列,低声部只排了 1 排 3 人。怎样才能让两个声部对齐?指挥家不假思索:“都从右边对齐!”——所有人以最右侧为基准站齐,低声部自动补到高声部的位置。这就是广播的“从右向左”规则。为什么从右?因为张量维度的语义中,越靠右的维度往往越“细节”——列对应特征,行对应样本,对齐时要先保证细节一致。

在 NumPy 中,广播的形状对齐遵循同样的顺序:从最后一个维度(最右侧)开始,逐个向左比较。举例来说,矩阵 A 的形状 (2, 3) 与向量 B 的形状 (3,),右对齐后,B 的维度 3 与 A 的最后一维 3 对齐;B 左侧没有维度,自动补为 1。于是比较变成 (2, 3) 与 (1, 3)。

为什么补 1?因为向量的形状 (3,) 本质上是 (1, 3) 的简化写法——在缺失的维度上补 1,是为了让两个张量具有相同的维数(ndim),方便逐维比较。补 1 不是随便选位置,而是严格从左端补齐:一个形状为 (4, 5) 的矩阵与 (3, 4, 5) 的张量对齐时,(4, 5) 会被补成 (1, 4, 5),而不是 (4, 5, 1)。方向错了,整个广播结果都会错。

就像低声部原本只站了 1 排,指挥说“左边空位补上”,于是那 1 排被逻辑上标记为可与 2 排对齐的阵型。补 1 不是真实的加人,而是给对齐一个“可扩展”的起点。

(2,3) ⟷ (3,)⟹(2,3) ⟷ (1,3)(2,3)\ \longleftrightarrow\ (3,)\quad\Longrightarrow\quad(2,3)\ \longleftrightarrow\ (1,3)
这个式子展示了右对齐的过程:向量 (3,) 先与矩阵的最后一维对齐,再在左侧补 1,变成 (1, 3)。
  1. 右端对齐把 B 的最后一个维度 3 与 A 的最后一维 3 对齐,两个数值相等,第一关通过。
    (2,3)↔(⋅,3)(2, 3) \leftrightarrow (\cdot, 3)
  2. 缺失补 1B 在左侧没有维度,按规则补为 1,形状变成 (1, 3)。
    (2,3)↔(1,3)(2, 3) \leftrightarrow (1, 3)
  3. 对齐完成此时两个形状维数相同,都是二维,可以进入下一步兼容性判定。
    (2,3) vs (1,3)(2, 3) \ \text{vs}\ (1, 3)

兼容判定

指挥家现在要裁定:两个声部能不能站到一起?他查看花名册,规则只有两条:要么人数完全相同,要么其中一方只有 1 人(可分身)。如果高声部 12 人、中声部 5 人,且中声部也不是 1 人队——那这场排练就无法进行,只能改乐谱。广播的兼容性判定,正是这位指挥家的裁决逻辑。

逐维比较中,每一对维度 (d_a, d_b) 只要满足以下三个条件之一,就判定为兼容:第一,d_a == d_b,两维度相等;第二,d_a == 1,A 的这一维度为 1,可扩展为 d_b;第三,d_b == 1,B 的这一维度为 1,可扩展为 d_a。三者都不满足,则整个广播失败,抛出 ValueError。

注意判定的顺序和“逐个维度”的特性。广播不是只看整体形状是否“差不多”,而是每一维都必须兼容。以 (3, 4) 与 (3,) 为例:右对齐后,第一对比较是 4 与 3——4 ≠ 3,4 不为 1,3 也不为 1,于是立刻失败。即便左侧维度还没有比较,整个运算已经报错。这也是初学者最容易踩的坑:以为“维度数多就能广播”,其实每一维都是独立的关卡。

指挥家的裁决简单而严格:“要么一样多,要么你只有一个人。”正是这条规则,保证了合唱团里每一个位置都有人唱,每一个维度都有数可算。

da=db或da=1或db=1d_a = d_b \quad \text{或} \quad d_a = 1 \quad \text{或} \quad d_b = 1
这是广播兼容性的“三条生路”:每一对维度只要能满足其中任意一条,这一维就算过关。
  1. 条件一两个维度数值相等,天然对齐,无需扩展。
    da=dbd_a = d_b
  2. 条件二A 的这一维度为 1,可沿该方向拉伸到 d_b 的长度。
    da=1d_a = 1
  3. 条件三B 的这一维度为 1,可沿该方向拉伸到 d_a 的长度。
    db=1d_b = 1

维度扩展

低声部只有 1 个人,站在 2 排的合唱队里怎么办?指挥家微微一笑,让他“分身”:第一排唱一遍,第二排再唱一遍。人还是那个人,声音却覆盖了两排。这就是维度为 1 时的扩展——一个元素在逻辑上被重复使用,而指挥家并没有真的去克隆一个歌手。

在广播中,当某维长度为 1 时,该维会被“虚拟复制”到目标长度。以上一节的 (1, 3) 与 (2, 3) 为例,(1, 3) 的行维度是 1,目标行数是 2,于是这一维从 1 扩展为 2,变成逻辑上的 (2, 3)。涉及的数据只有 3 个元素,复制行为不产生新的内存块,而是通过步长(stride)为 0 的视图技巧实现。

扩展到任意长度都遵循同一规则:1 → N(N 为目标维长)。标量(0 维张量)更特殊——它没有形状,广播时被视为所有维度都为 1 的“万能声部”,可以与任意形状的张量运算。比如给矩阵所有元素加 1,matrix + 1 这个 1 就会被广播到矩阵的每一维、每一个位置。

1 个人分身成 2 排,是这个比喻里最魔幻也最真实的一幕。广播的扩展从不“真复制”,它只在计算时让同一个元素出现在多个位置——像指挥家脑海中的回声,一遍遍响起,却不消耗额外的歌手。

(1,3) → 扩展  (2,3)(1,3)\ \xrightarrow{\ \text{扩展}\ }\ (2,3)
这个式子表示:形状 (1, 3) 在行维度上从 1 扩展为 2,成为逻辑上的 (2, 3),数据不拷贝。
  1. 补 1 后的形状原始向量 (3,) 补为 (1, 3),行维度为 1。
    (1,3)(1, 3)
  2. 目标形状与 (2, 3) 比较后,行维度目标长度为 2。
    (2,3)(2, 3)
  3. 逻辑复制第 0 行的 3 个元素在逻辑上复制到第 1 行,数据不拷贝。
    row1[j]=row0[j],j=0,1,2\text{row}_1[j] = \text{row}_0[j], \quad j = 0, 1, 2

算术运算

合唱进入正式排练。指挥家要求:每个声部同时开唱,同一时刻各声部对应位置的人要唱同一个音符。低声部虽然人少,但通过分身,每个位置都有了对应的人。于是整首曲子像被“逐拍对齐”——这就是广播下的逐元素运算:两个张量的对应位置逐个相加、相减、相乘、相除。

广播不仅适用于加法,也适用于减法、乘法、除法以及 np.exp、np.sqrt 等逐元素函数。凡是逐元素的运算,都可以享受广播带来的形状自动对齐。更妙的是,广播对归约操作同样意义重大:比如 X.sum(axis=0) 得到一个形状为 (3,) 的均值向量,此时若想再从 X 中减掉它,广播会自动把 (3,) 扩展回 (2, 3) 逐行相减。

归约操作配合 keepdims 参数能进一步发挥广播的威力。X.mean(axis=0, keepdims=True) 的结果形状是 (1, 3),保留了长度为 1 的维度,后续减法直接与 (2, 3) 广播;而默认的 keepdims=False 得到 (3,),虽然也能广播,但在更复杂的多维场景中,保留维度会让形状关系一目了然,避免意外。

指挥家用“同一时间各位置唱同一个音”的方式,让合唱团的每一次呼吸都整齐划一。广播的逐元素运算正是这种整齐:你不需要为每个声部单独编排队形,只需要按照规则站好,音符自然对齐。

Ci,j=Ai,j+Bj,i∈{0,1}, j∈{0,1,2}C_{i,j} = A_{i,j} + B_{j},\quad i\in\{0,1\},\ j\in\{0,1,2\}
这个公式展示了广播下的逐元素加法:B 只有列索引 j,行索引 i 由广播自动补上。
  1. 逐元素索引结果 C 的每个位置由 A 的对应位置与 B 的某个元素相加。
    Ci,j=Ai,j+BjC_{i,j} = A_{i,j} + B_{j}
  2. B 的广播索引B 只有列索引 j,行索引 i 被广播扩展——同一列的不同行使用相同的 B_j。
    Bj→广播Bi,j=BjB_{j} \xrightarrow{\text{广播}} B_{i,j} = B_{j}
  3. 完整展开每一行重复使用同一个 B,形成逐行相加的效果。
    Ci,j=Ai,j+Bj,∀iC_{i,j} = A_{i,j} + B_{j}, \quad \forall i

广播陷阱

排练并非总是顺利。有一次,指挥家让低声部(3 人)与一个 4 人小组配合,低声部死活对不上。指挥家检查花名册:4 vs 3,不相等,且 3 ≠ 1、4 ≠ 1——没有一个人是“1 人队”,无法分身。指挥家只能宣布:“这场配合取消。”NumPy 的回答更直接:抛出一个 ValueError。

广播的陷阱大多源于对“从右向左”和“兼容条件”的忽视。最典型的错误:形状 (3, 4) 的矩阵与形状 (3,) 的向量相加。直觉上似乎“差不多”,但右对齐后,最后一维是 4 vs 3,直接不兼容。另一个常见陷阱是“意外广播”:本想把 (3, 1) 与 (3,) 逐行相加,结果 (3,) 被广播成 (3, 3),得到完全错误的结果。

还有一类陷阱与性能有关:过度依赖广播会让中间结果膨胀。比如多个 (1, n) 向量参与复杂运算时,逻辑视图虽不占内存,但某些操作(如 np.broadcast_to 后接 np.copy)会触发真实复制,导致内存暴涨。调试时,建议先用 arr.shape 和 arr.ndim 确认形状,必要时用 np.broadcast_shapes(a, b) 静态检查广播结果,再用小样例验证。

指挥家学会了在排练前先看一眼花名册。聪明的工程师也学会了在写代码前先检查形状——广播是一个强大的工具,但工具用错地方,就会变成事故现场。

(3,4) 与 (3,)⟹4≠3, 4≠1, 3≠1 ⇒ ValueError(3,4)\ \text{与}\ (3,)\quad\Longrightarrow\quad 4 \neq 3,\ 4\neq 1,\ 3\neq 1\ \Rightarrow\ \text{ValueError}
这个式子展示了广播失败的原因:最后一维 4 与 3 既不相等,又没有一个是 1,三个兼容条件全部落空。
  1. 第一对比较右对齐后,最后一维是 4 与 3。
    4 vs 34 \text{ vs } 3
  2. 三条件检查4 ≠ 3、4 ≠ 1、3 ≠ 1,一个都不满足。
    4≠3,4≠1,3≠14 \neq 3,\quad 4 \neq 1,\quad 3 \neq 1
  3. 报错该维度不兼容,整个广播失败,抛出 ValueError。
    ValueError: operands could not be broadcast together\text{ValueError: operands could not be broadcast together}

实战应用

演出终于到来。合唱团的“自动对齐”能力让指挥家在编排上省下了大量精力——不用为每个声部单独写谱,不用手动调整站位,所有声部一站上台,自然形成和谐的阵型。在 AI 实战中,广播同样是那个让代码简洁高效的幕后功臣。

特征归一化是最常见的广播应用。假设 X 是 (n, d) 的特征矩阵,n 个样本、d 个特征。我们需要对每个特征减去均值 μ、除以标准差 σ——μ 和 σ 都是形状 (d,) 的向量。直接写 (X - mu) / sigma,广播会将其自动扩展为 (n, d) 逐元素运算,无需任何 for 循环。

批量距离计算是另一个高频场景。给定 (N, d) 的查询点集和 (M, d) 的参考点集,要计算 N×M 的距离矩阵。利用广播:points[:, None, :] - centers[None, :, :] 将两个张量分别视为 (N, 1, d) 和 (1, M, d),广播后得到 (N, M, d) 的差向量,再对最后一维求平方和开方,一次性得到完整距离矩阵。深度学习中的偏置项添加(如全连接层 W @ x + b)也依赖广播:b 的形状 (d,) 自动扩展到 batch 的每一行。

指挥家看着台上整齐的声部,感慨万千:明明每个声部人数不同,却因为“自动对齐”的智慧,让整场演出行云流水。AI 代码中的广播,正是这样的智慧——用最少的代码,做最优雅的计算。

Xnorm=X−μσ,μj=1n∑i=1nXi,j,σj=1n∑i=1n(Xi,j−μj)2X_{\text{norm}} = \frac{X - \mu}{\sigma},\qquad \mu_j = \frac{1}{n}\sum_{i=1}^{n} X_{i,j},\quad \sigma_j = \sqrt{\frac{1}{n}\sum_{i=1}^{n}(X_{i,j}-\mu_j)^2}
这是标准分数归一化公式:每个特征减去自身的均值、除以自身的标准差,全程由广播驱动,无显式循环。
  1. 计算统计量μ_j 是第 j 个特征的均值,σ_j 是第 j 个特征的标准差。
    μj=1n∑i=1nXi,j\mu_j = \frac{1}{n}\sum_{i=1}^{n} X_{i,j}
  2. 广播减法(n, d) 减去 (d,),(d,) 自动补为 (1, d) 再扩展为 (n, d)。
    X−μ⇒Xi,j−μjX - \mu \quad\Rightarrow\quad X_{i,j} - \mu_j
  3. 广播除法逐元素除以标准差,完成归一化。
    Xi,j−μjσj\frac{X_{i,j} - \mu_j}{\sigma_j}

AI 应用场景

图像数据归一化与预处理

阶段:数据预处理

解决的问题:训练神经网络前需要将图片像素归一化到零均值单位方差。传统做法需要 for 循环遍历每个通道做缩放,代码冗长且易错。广播让 (image - mean) / std 一行完成,mean 和 std 是通道统计量(形状 (3,) 或 (1, 3, 1, 1)),自动广播到整个图像批次。

具体案例:在 ImageNet 分类任务中,对 RGB 三通道分别减去 mean=[0.485, 0.456, 0.406] 并除以 std=[0.229, 0.224, 0.225]。一张 (3, 224, 224) 的图像直接减 (3,) 向量,每通道独立完成归一化,推理速度提升数倍。

KNN 批量距离计算与检索

阶段:模型推理与预测

解决的问题:K 近邻分类需要计算查询样本与所有训练样本的距离。朴素双重 for 循环复杂度为 O(N×M),且无法利用向量化加速。广播一次性构建 (N, M) 距离矩阵,配合 argpartition 选出近邻。

具体案例:人脸识别系统中,将待识别的 1000 张人脸 embedding(512 维)与注册库 10000 张 embedding 做比对,用 q[:, None, :] - r[None, :, :] 广播出差值张量,平方求和开方后得到距离矩阵,毫秒级完成全量比对。

注意力机制中的分数掩码

阶段:模型构建与前向传播

解决的问题:自注意力中 score = QKᵀ 的形状是 (B, H, T, T),需要加上 attention mask(形状 (T, T))以屏蔽无效位置。手动扩展 mask 到 4 维需要多次 unsqueeze 和 expand,广播让 (T, T) 自动对齐到 (B, H, T, T)。

具体案例:在 GPT 系列模型的因果掩码中,上三角掩码矩阵 (T, T) 与每一层的注意力分数相加,依靠广播同时对 batch 和 head 维度生效,无需复制内存。

Python 演示

python43 行
import numpy as np def broadcast_shape(shape_a, shape_b):    """模拟广播引擎:从右向左逐维判定,返回广播后的形状"""    ndim = max(len(shape_a), len(shape_b))    a = [1] * (ndim - len(shape_a)) + list(shape_a)    b = [1] * (ndim - len(shape_b)) + list(shape_b)    out = []    for da, db in zip(a, b):        if da == db:            out.append(da)        elif da == 1:            out.append(db)        elif db == 1:            out.append(da)        else:            raise ValueError("形状不兼容: {} vs {}".format(shape_a, shape_b))    return tuple(out)  cases = [((2, 3), (3,)), ((2, 3), (1, 3)),         ((4, 1), (1, 3)), ((3, 4), (3,))]for s_a, s_b in cases:    try:        print("{} 广播 {} -> {}".format(s_a, s_b, broadcast_shape(s_a, s_b)))    except ValueError as e:        print("{} 广播 {} -> 报错".format(s_a, s_b))  # 实战1:特征归一化(利用广播)X = np.random.randn(3, 4)mu = X.mean(axis=0)sigma = X.std(axis=0)X_norm = (X - mu) / sigmaprint("归一化后均值:", X_norm.mean(axis=0)) # 实战2:批量距离计算(利用 None 插入维度触发广播)points = np.array([[1, 2], [3, 4], [5, 6]])centers = np.array([[0, 0], [1, 1]])diff = points[:, None, :] - centers[None, :, :]dist = np.sqrt((diff ** 2).sum(axis=-1))print("距离矩阵:")print(dist)
目的:手写一个广播形状计算引擎,并用真实 NumPy 演示特征归一化与批量距离计算两个经典场景。
  1. a = [1] * (ndim - len(shape_a)) + list(shape_a)在形状左侧补 1,让两个形状长度一致,对应“缺失维度补一”。
  2. if da == db:维度相等直接兼容,这是第一条判定规则。
  3. elif da == 1:A 的维度为 1,可以扩展到 B 的维度。
  4. else: raise ValueError(...)三个条件全不满足,广播失败。
  5. X_norm = (X - mu) / sigma一行完成归一化,mu 和 sigma 由广播自动扩展。
  6. diff = points[:, None, :] - centers[None, :, :]插入新维度把形状变为 (3,1,2) 与 (1,2,2),广播出 (3,2,2) 的差值张量。
  7. dist = np.sqrt((diff ** 2).sum(axis=-1))对最后一维求和再开方,得到距离矩阵。

常见误区

误区“广播的时候,NumPy 会把小数组复制成和大数组一样的形状,所以会占用更多内存。”

正解广播的核心是“逻辑视图零拷贝”。NumPy 通过设置步长为 0 的视图,让同一个内存位置在逻辑上出现在多个索引处,不实际复制。只有当显式调用 np.broadcast_to(...) 后接 .copy() 时才产生真实拷贝。

为何常见:从结果看,广播后元素确实“出现”在多个位置,初学者容易误以为是物理复制。

误区“两个张量维度数一样,就应该能直接相加。比如 (3, 4) 和 (4, 3) 都是二维,肯定能广播。”

正解广播不看“维度数相同”,而是看“每一维是否兼容”。维度数相同只是必要条件,远非充分条件。每个维度都要满足相等或为 1 的条件,逐维判定。

为何常见:人们习惯用整体形状“看起来像不像”来判断,忽略了广播是从右向左逐维检查的机制。

误区“只要把某个维度改成 1,它就能自动变成任何形状。比如把 (3,) reshape 成 (3, 1) 就能和 (4, 3) 广播。”

正解维度为 1 的扩展必须发生在“从右向左对齐后”的对应维度上。(3, 1) 与 (4, 3) 右对齐后比较的是 1 vs 3(兼容)和 3 vs 4(不兼容),仍然报错。位置的对应关系决定了扩展方向,不能想当然。

为何常见:只记住了“1 可以扩展”,忽略了“必须在对齐的维度上扩展”这一前提。

误区“keepdims=True 和 False 只是打印出来的形状不同,对后续计算没影响。”

正解影响很大。X.mean(axis=0) 得到 (4,),keepdims=True 得到 (1, 4)。在多维广播中,(1, 4) 能明确保留维度位置,避免与 (2, 4) 或 (2, 1, 4) 对齐时出现歧义或意外广播。

为何常见:简单场景下两种写法结果相同,让人忽视了维度位置在复杂场景中的关键作用。

误区“既然广播这么智能,任何形状应该都能算,报错一定是框架的 bug。”

正解广播报错(ValueError)恰恰是保护机制——它阻止了本就不合理的形状运算,避免静默产生错误结果。报错信息 operands could not be broadcast together with shapes... 会明确指出两个形状,是调试的第一线索。

为何常见:广播的“自动对齐”让人产生“万能”错觉,实际上它有严格的边界条件。

面试题

Q1. 广播的形状对齐从哪个方向开始?

单选题 · easy

  • A.从最左边开始对齐
  • B.从最右边开始对齐← 正确答案
  • C.从中间位置向外对齐
  • D.从任意方向开始对齐

答案:B。广播的对齐总是从最后一个维度(最右侧)开始,逐个向左比较。这就像合唱团以最右侧为基准站齐,先保证“细节维度”一致,再扩展左侧的“结构维度”。

Q2. 形状 (3,) 的向量与 (2, 3) 的矩阵相加,结果是?

单选题 · mid

  • A.报错无法进行运算
  • B.得到形状 (2, 3) 矩阵← 正确答案
  • C.得到形状 (3,) 向量
  • D.得到形状 (6,) 向量

答案:B。右对齐后 (3,) 补为 (1, 3),行维度 1 与 2 兼容并被扩展,最终形状为 (2, 3)。这与合唱团低声部 3 人“分身”成 2 排的效果一致。

Q3. 形状 (4, 1) 与 (1, 3) 广播后结果是?

单选题 · mid

  • A.形状 (4, 3) 的矩阵← 正确答案
  • B.形状 (1, 1) 的标量
  • C.形状 (5, 4) 的矩阵
  • D.无法进行广播运算

答案:A。逐维比较:第一维 4 与 1 兼容(1 扩展为 4),第二维 1 与 3 兼容(1 扩展为 3),最终得到 (4, 3)。两个维度各自“分身”,就像两个方向的声部同时补齐。

Q4. 以下哪些形状能与 (2, 3) 广播兼容?

多选题 · mid

  • A.形状 (3,) 的一维向量← 正确答案
  • B.形状 (2, 1) 的列向量← 正确答案
  • C.形状 (1, 3) 的行向量← 正确答案
  • D.形状 (4, 3) 的矩阵

答案:ABC。A 右对齐 3=3 兼容;B 比较 2=2、1 与 3 兼容(1 扩展);C 比较 1 与 2 兼容、3=3 兼容;D 比较 3=3 但 4 与 2 不相等且都不为 1,不兼容。

Q5. 关于广播的数据处理方式,正确的是?

单选题 · easy

  • A.实际复制数据占用内存
  • B.逻辑视图方式零拷贝← 正确答案
  • C.直接修改原始数据结构
  • D.强制转换数据类型对齐

答案:B。广播通过步长为 0 的视图实现逻辑扩展,不产生真实数据拷贝,因此省内存、省时间。它既不修改原始数据,也不强制转换数据类型。

Q6. 标量(0 维张量)与任意形状张量运算?

单选题 · easy

  • A.能广播,标量视为全 1← 正确答案
  • B.不能广播,维度为零
  • C.仅能与向量进行广播
  • D.仅能与矩阵进行广播

答案:A。标量没有形状,广播时被视为所有维度都为 1 的“万能声部”,可与任意形状张量运算。比如 matrix + 1 中的 1 会广播到每个位置。

Q7. 关于 keepdims,正确的说法是?

多选题 · hard

  • A.True 保留长度为 1 的维度← 正确答案
  • B.False 会删除长度 1 维度← 正确答案
  • C.归约后便于再次广播← 正确答案
  • D.对广播行为没有影响

答案:ABC。keepdims=True 保留长度为 1 的维度(如 (4,) 变 (1, 4)),False 则删除,二者影响后续广播的维度对齐方式,所以 D 错误。保留维度能明确位置,方便与高维张量继续运算。

Q8. 形状 (2, 3, 4) 与 (4,) 广播后结果是?

单选题 · easy

  • A.形状 (2, 3, 4) 的张量← 正确答案
  • B.形状 (4,) 的一维张量
  • C.形状 (2, 3) 的矩阵
  • D.直接抛出形状错误

答案:A。从右向左对齐,(4,) 与最后一维 4 相等;左侧缺失维度补 1,(1, 1, 4) 每一维都与 (2, 3, 4) 兼容,最终广播为 (2, 3, 4)。

Q9. 广播在 AI 实践中的典型场景?

多选题 · hard

  • A.特征矩阵减去均值向量← 正确答案
  • B.批量距离计算加维度← 正确答案
  • C.权重矩阵加偏置向量← 正确答案
  • D.用 for 循环逐样本处理

答案:ABC。A 是特征归一化((n,d) 减 (d,));B 是批量距离矩阵(插入 None 触发广播);C 是全连接层 W @ x + b 的标准实现。D 是低效的替代方案,不是广播。

Q10. 下述哪段代码利用广播最恰当?

单选题 · mid

  • A.for 循环逐行缩放数据
  • B.数据矩阵除以标准差向量← 正确答案
  • C.手动复制向量为矩阵再减
  • D.用 list 存储所有样本结果

答案:B。B 直接利用广播完成逐列归一化,一行代码且高效。A 和 D 用循环与 list 放弃向量化,C 手动复制浪费内存——三者都没有发挥广播“零拷贝逻辑扩展”的优势。