Transformer 块
Transformer 块通过自注意力和逐位置前馈网络,更新一组 token 向量。本课采用 pre-norm(前置归一化) 结构:先对每个子层的输入做归一化,再把子层的输出加回残差流。
你可以把它想成反复修改一份草稿。注意力根据上下文给出修正,前馈网络再分别调整各个位置的表示,然后交给下一个块。展开加法时,原始输入仍是其中一项;不过,后续修正可能抵消它,所以跳连并不保证能从最终向量还原所有原始信息。
残差流的两次更新
残差流保存着每个 token 当前的向量表示。一个块会更新它两次:
- 将残差流的归一化副本送入自注意力,得到修正量
Δ_attn,再更新x = x + Δ_attn。 - 对更新后的残差流再次归一化,送入两层前馈网络:先扩展维度,经过 ReLU,再缩回原来的维度。得到修正量
Δ_ffn后,更新x = x + Δ_ffn。
注意力负责混合不同 token 的信息。前馈网络则对每个位置应用同一个函数,各位置独立计算,不在这一步交换信息。这两次更新可以写成:
x = x + attention(norm(x))
x = x + ffn(norm(x))
h = embed(tokens) + positional
for _ in range(num_layers):
h = block(h)
经过 N 个块,结果可以展开为 x_N = x₀ + Σ Δ。每个 Δ 都依赖前面的状态,因此这只是把实际算出的修正量相加,并不意味着各块独立计算。pre-norm 是一种常见结构;原始的 2017 年架构把归一化放在残差相加之后,不能直接套用这个累加式。代码中的位置加法只是示意,其他模型也可以使用相对位置或旋转机制。
逐步演示
默认演示跟踪 by the river bank 中的 bank,经过三个块,开启残差连接。为了方便读数,这里手动设置了四维向量,四个维度大致对应“地理、金融、功能词、bank 身份”。这些含义只用于本例,真实模型的各个坐标并没有这样的通用标签。
- 输入:
x₀ = [0.3,0.3,0,1.0],前两维的值相同,尚未偏向某个含义;第四维用来标记这个词是 bank。 - 块 1 注意力:bank 更多地关注 river,得到的修正量约为
[0.7,−0.3,−0.2,0]。加回输入后,向量变为[1.0,0.0,−0.2,1.0],第四维仍为一。 - 块 1 前馈:修正量约为
[0.3,−0.1,−0.2,0.2],相加后得到[1.3,−0.1,−0.4,1.2]。 - 块 2:再次计算注意力和前馈网络;每个子层都先归一化,再把输出加回残差流。这个块结束时,向量约为
[2.3,−0.6,−0.6,1.4]。 - 块 3:重复同样的步骤,得到约
[3.4,−1.2,−0.8,1.5]。地理维依次为0.3 → 1.3 → 2.3 → 3.4,表示 bank 身份的那一维在一附近变化。 - 核对加法:最终向量等于输入加上六次修正,每个块贡献两项。深度图画的就是这个和:灰蓝色的
x₀带一直延伸到最右端,每个块上的绿色柱高度对应到该块为止累计的修正量(‖stream − x₀‖)。修正叠在上面,底下的输入一直都在。
关闭 残差连接,每次更新就从 x = x + Δ 变为 x = Δ:直接用子层输出替换当前向量,不再加上输入。把深度调到六个块,深度图里的 x₀ 带在入口处就被剪断,每个块上的红色小柱只表示它最新输出的大小,最终向量只取最后一次较小的修正量。但修正量本身仍由输入算出,公式里没有 x₀ +,不等于所有输入信息都已丢失。
残差为何有用
跳连让输入可以绕过子层,直接参与最后的相加。这条恒等路径有助于深层网络的优化:子层 x+F(x) 的雅可比是 I+J_F,其中的恒等项来自跳连。不过,导数项仍可能相互抵消,梯度在逐层传播中也可能缩小或放大。因此,残差连接不保证梯度永不消失;没有残差连接的网络也并非一定无法保存信息。
本例关闭残差后,归一化仍会把子层输入调到稳定的尺度,残差流的向量长度保持在约 0.4,没有降到零。这个长度对应最后一次修正量的大小,而用来表示 bank 身份的分量已经减弱。范数只能告诉你向量有多长,不能据此判断它保留了什么内容。归一化负责调整尺度,跳连提供恒等路径,两者不能互相替代。
如果只看一个块,本例中开启和关闭残差的差别较小,但残差连接对单个块也可以有影响。增加深度是否有益,取决于参数、训练和任务。本课没有训练过程,不能用这个对照推断深层网络能学到多少东西。
边界情况
- 只有一个块:本例中两种设置的差别较小,不能据此判断残差连接无效。
- 前馈网络:各位置独立应用同一个函数;不同 token 之间的信息交换发生在注意力子层。
- 向量长度稳定:关闭残差也可能得到稳定的长度,这不足以证明词的身份信息仍然保留。
- 权重共享:本课所有块复用同一套手设权重,便于观察反复修正的过程。许多真实 Transformer 的各层会独立学习参数,也有共享层参数的结构。
- 词序:本课的注意力没有加入位置信息。如果把 token 及其向量一起重排,输出也会按同样的方式重排,这叫置换等变。示意代码中的
+ positional是引入位置的一种方式;真实模型也可以把位置信息加入注意力分数,或用于 Q/K 旋转。
常见错误
- 认为只要做加法,原始信息就能永远原封不动地保留。恒等路径确实存在,但修正量可能抵消已有分量。
- 把 Transformer 块等同于注意力,漏掉前馈网络、残差连接和归一化。
- 把残差连接当成单纯的提速技巧。它会改变信息和梯度的传播路径,但既不是所有模型都必须具备的条件,也不保证模型一定能学好。
- 把归一化与残差连接混为一谈。前者调整尺度,后者提供恒等路径。
- 认为堆叠更多块就一定更好。本课只演示向量如何更新,没有测试训练效果或任务性能。
模型范围
本课使用四维向量、一个注意力头和小型前馈网络,各个块共享手动设置的权重。归一化只显示为一个计算步骤,没有逐个分量展开。实际模型的头数、向量维数、前馈网络宽度、激活函数、dropout、权重共享方式和深度各不相同,位置机制也不只一种。本课不区分编码器、带因果掩码的解码器和编码器—解码器结构,只展示 pre-norm 结构如何把子层输出加回残差流。