面向 AI 的向量加法:残差更新如何组合信号
逐分量学习向量加法,探索其平行四边形几何,并在 NumPy 中识别形状、广播和特征对齐错误。
一个神经网络层接收一个包含三个坐标的状态
并计算出一个更新量
。
残差连接不会在旧状态和更新量之间二选一。它会把对应坐标相加,得到 。 第一个坐标下降,第二个坐标上升,第三个坐标上升;同一条规则处理全部三个变化。
完成本课后,你将能够逐分量相加向量,把同一运算理解为位移或特征更新,使用 NumPy 验证运算,并拒绝那些形状碰巧可用、但坐标含义没有对齐的加法。
**学习成果:**逐分量相加向量,并解释所得的位移或特征混合。
第 14 课:作为 AI 数据的向量说明,向量是一种有序表示:坐标 承载特定特征或学习到的信号。向量加法依赖这种顺序。官方 Mathematics for Machine Learning 配套网站在第 2.2 节介绍行向量、列向量和矩阵逐元素加法。本课把这条规则专门应用于向量;其中的模型状态示例、推导、代码、交互式几何图形和练习题均为原创。
一条坐标规则组合整个向量
设 是两个具有相同正维度 的实向量。将它们的坐标写作 和 ,其中 从 1 取到 。
“对应坐标”这个说法包含两个要求。第一,向量必须具有相同维度。第二,每一对 必须指向同一个坐标系统:相同的特征顺序、单位和表示约定。数学说明维度要求;数据管道还必须执行语义要求。
加法不会把两个向量连接起来。连接 和 会得到一个四坐标向量,而相加仍然保留两个坐标:
。
不跳过任何坐标地跟踪一次残差更新
回到开头的向量。假设三个位置都属于同一个学习表示空间。逐行计算和:
| 坐标 | 现有状态 | 更新量 | 输出 |
|---|---|---|---|
| 1 | 2.0 | −0.5 | 1.5 |
| 2 | −1.0 | 1.5 | 0.5 |
| 3 | 0.5 | 1.0 | 1.5 |
正更新量会提高坐标,负更新量会降低坐标,零更新量则保持坐标不变。这些是算术描述,而不是对内部神经元坐标“意味着什么”的语义解释。学习到的表示可以把信息分散到许多坐标中,因此单凭这个和不能揭示一个人类可读的概念。
对角线和两步路径抵达同一点
在二维空间中,向量可以画成从原点出发的箭头。要从几何上把 和 相加,可以沿着 走,然后把 的副本放在它的箭头端点。终点是 ,因为水平位移是 ,垂直位移是 。
也可以反过来。先沿着 走,再沿着平移后的 副本走,同样会抵达这个终点。两条路径构成平行四边形的相邻边;从原点出发的对角线就是这个和。移动下面的四个坐标,测试同向、反向、平行以及相互抵消的方向。
两条首尾相接的路径都在和这一行的坐标处结束。虚线平移 b 箭头从 a 出发;点线平移 a 箭头从 b 出发。
| 向量 | 水平坐标 | 垂直坐标 | 几何角色 |
|---|---|---|---|
| 向量 a — 实线箭头 | +3 | +1 | 第一个位移,也是其中一条边 |
| 向量 b — 虚线箭头 | -1 | +2 | 第二个位移,也是其中一条边 |
| 和 a + b — 粗对角线 | +2 | +3 | 最终端点和对角线 |
图中使用两个坐标,是因为平面可以显示它们。分量规则并不依赖图形:对于 中的向量,即使 大到无法绘制,也要把全部 个对应坐标相加。
三个代数事实逐坐标成立
向量加法继承实数加法的熟悉性质。原因是局部的:每条向量恒等式都可以在坐标 处检验。
**交换顺序不会改变和。**因为对实数有 ,
。
所有坐标都相同,所以 。这就是交换律,平行四边形也把同一事实显示为通往一个端点的两条路径。
**分组不会改变三个向量的和。**对于另一个向量 ,
。
这个结合律保证无论怎样分组,得到的数学向量都完全相同。改变许多次加法的顺序时,有限精度代码可能累积略有不同的舍入误差。数学结合律或数值接近,都不允许混用坐标系统。
**零向量什么也不改变。**令 。则
,
所以 。返回零向量的残差分支在该加法位置不会造成数值变化。
残差连接使用的正是这种加法机制
原始 ResNet 论文把残差块写成 :学习分支计算 ,而捷径把 带到加法处。作者说明这是逐元素加法,并且两项需要具有相同维度。维度不匹配时,其架构可以在相加前对捷径使用学习到的投影。
原始 Transformer 提供了另一个具体例子。它的编码器在每个子层周围应用残差连接:
。
在该架构中,嵌入和子层输出使用相同的 维度,因此可以定义逐坐标的和。求和之后的归一化是另一种运算;向量加法本身在 处结束。
这些例子支持一条范围狭窄的实现结论:残差连接用逐元素加法组合兼容的输入和更新量。仅凭这个方程,不能证明每个输入特征都原样保留,不能证明每个坐标都有孤立含义,也不能证明任意两个等长数组都是有效的残差对。
NumPy 加值并广播形状
NumPy 的 add 运算逐元素相加参数。对于形状相同的一维数组,np.add(state, update) 和 state + update 都直接实现分量规则:
import numpy as np
state = np.array([2.0, -1.0, 0.5])
update = np.array([-0.5, 1.5, 1.0])
if state.shape != update.shape:
raise ValueError("A residual update must match the state shape")
combined = np.add(state, update)
print("state shape:", state.shape)
print("update shape:", update.shape)
print("combined:", combined)
验证后的输出是
state shape: (3,)
update shape: (3,)
combined: [1.5 0.5 1.5]
一个批次的每一行保留一个状态。形状为 (2, 3) 的匹配数组会把每个更新量加到对应状态上:
batch = np.array([
[2.0, -1.0, 0.5],
[0.0, 3.0, -2.0],
])
updates = np.array([
[-0.5, 1.5, 1.0],
[ 1.0, -1.0, 0.5],
])
print("batch shape:", batch.shape)
print("batch sums:\n", batch + updates)
验证后的输出是
batch shape: (2, 3)
batch sums:
[[ 1.5 0.5 1.5]
[ 1. 2. -1.5]]
第一行输出就是上面的演算示例。第二行来自 。
成功的数组运算仍可能是错误的加法
NumPy 有意支持广播:如果形状不同但满足其兼容规则,较小数组可以作用于较大数组。把形状 (3,) 的更新量加到形状 (2, 3) 的批次上会成功,并把同样的三个值应用到两行:
broadcast_update = np.array([0.5, 0.0, -0.5])
result = batch + broadcast_update
print("broadcast shape:", result.shape)
print("broadcast sums:\n", result)
broadcast shape: (2, 3)
broadcast sums:
[[ 2.5 -1. 0. ]
[ 0.5 3. -2.5]]
这可能正是有意设计的运算,例如让一个共享更新量作用于批次中的每一行。但它不是两个形状相同的单独向量之间的加法;当额外的扩展是意外发生时,它就很危险。应验证模型要执行的契约,而不只是验证 NumPy 接受的形状。
形状匹配也不够。考虑以下数组:
其中 的顺序为 , 的顺序为 。
NumPy 返回 ,但它的第一次计算把 clicks 加到了 returns 上。没有任何数值形状检查能够找回缺失的标签。应在相加前把一个向量重新排列为另一个向量的坐标约定,或者拒绝该运算。
现在,向量加法不只是一个公式:它是坐标契约、几何路径,也是残差块内部的组合运算。下一课将通过标量乘法控制一个向量的强度;今天的和提供了这些缩放信号最终汇合时所需的运算。
检查你的理解
问题 1
将 a = [3, −2, 1]ᵀ 与 b = [−5, 4, 0.5]ᵀ 相加。展示每个坐标的计算,并说明结果的维度。
显示分步解答
两个输入都有三个坐标,所以如果逐坐标计算,它们的和也属于 。
。
按原来的顺序收集结果:
。
加法改变了数值,但没有插入或删除坐标。
问题 2
对于 a = (2, 1) 和 b = (−1, 3),跟踪先走 a 再走 b 的首尾相接路径。它在哪里结束?为什么这个点是平行四边形的对角线端点?
显示分步解答
从原点 出发。沿着 走到 。然后沿平移后的 改变水平坐标 ,改变垂直坐标 :
。
反过来走则得到
。
两条路径是平行四边形的两组平行边。由于两条路径都抵达 ,从原点到 的箭头就是它的对角线,表示 。
问题 3
对于任意 a, b ∈ ℝⁿ,逐坐标解释为什么 a + b = b + a。不要只依赖二维图形。
显示分步解答
任选坐标 。根据向量加法的定义,
。
实数加法满足交换律,所以 。反向应用向量定义得到
。
因此,两个和在任意选定的坐标 上相等。这个论证对每个坐标都成立,所以向量相等:。这个推理适用于任何有限维度,包括无法画出的维度。
问题 4
一个残差分支对状态 x ∈ ℝ⁴ 返回 [0, 0, 0, 0]ᵀ。计算 x + 0,并说出在声称该分支没有产生有意义的变化之前所需的假设。
显示分步解答
写作 。逐坐标相加得到
。
所以该加法位置没有造成数值变化。称其为“没有有意义的变化”还需要假设状态和零更新量使用同一个四坐标表示,并且之后没有其他运算(例如归一化)改变数值。
问题 5
[1, 2]ᵀ + [3, 4, 5]ᵀ 能成为向量和吗?诊断问题,然后说明对于维度不匹配的残差块,一种架构层面的补救方法。
显示分步解答
第一个向量属于 ,第二个属于 。逐分量相加需要为每个输出坐标找到对应的第二个输入,但第一个向量没有第三个坐标。因此,按当前写法向量和没有定义。
残差架构可以先把一个分支映射到另一个分支的维度。例如,投影 可以把 变换为 。随后,只要该投影也建立了预期的坐标语义,就可以定义 。填充是另一种依赖具体架构的选择,但默默丢弃或凭空添加坐标都不是向量加法。
问题 6
两个形状为 (3,) 的数组使用特征顺序 (clicks, purchases, returns) 和 (returns, clicks, purchases)。为什么按位置相加无效?应该如何准备第二个数组?
显示分步解答
形状相等会把位置 1 与位置 1 配对,但标签显示这会把 clicks 加到 returns 上。位置 2 和 3 也没有对齐。该运算会产生没有一致特征解释的数字。
先把第二个数组的每个值与其标签绑定。然后按照第一个数组使用的约定
重新排列这些带标签的值。只有两个数组在维度、顺序和单位上都一致后,才能执行按位置相加。NumPy 无法从不带特征标签的纯数字数组中完成这项语义检查。
问题 7
一个批次的形状为 (4, 3),更新量的形状为 (3,)。NumPy 接受 batch + update。输出形状是什么,执行了什么计算?程序员在信任它之前必须回答哪个问题?
显示分步解答
NumPy 比较末尾维度。最后的维度都是 3,而 update 缺失的前导维度视为 1,并可以扩展到批次的四行。因此输出形状是 (4, 3)。
对于每个行索引 和坐标 ,NumPy 计算
。
程序把同一个三坐标更新量应用到全部四行。程序员必须判断:是否确实有意让一个共享更新量复用于每个批次项。广播成功只证明符合 NumPy 规则的形状兼容;它不证明模型契约要求在所有项目间复用一个更新量。
问题 8
一个子层接收 x = [1, −2, 3]ᵀ,并返回 F(x) = [0.5, 2, −1]ᵀ。计算残差和,然后精确解释算术证明了什么、没有证明什么。
显示分步解答
把对应坐标相加:
。
该算术证明兼容的输入和子层输出已按坐标组合为一个三坐标结果。它没有确定任一坐标的人类含义,没有证明原始信息可以完全恢复,也没有说明后续归一化或层将做什么。这些属于学习到的表示和周围架构的性质,而不是加号本身的结果。