编程与 AI14 分钟阅读更新于 2026-08-03

为什么 Transformer 各子层要保持统一维度:从 d_model 到残差连接

围绕张量流动和残差连接的内容,解释 d_model、注意力头、FFN 中间层与残差相加之间的尺寸关系。

相关工具

Transformer 里的向量为什么总能接起来

阅读 Transformer 结构图时,会发现词嵌入、注意力输出、前馈网络输出和残差相加似乎可以一路连接。它们之所以能够顺利传递,不只是因为模块排列得整齐,还因为大部分子层都遵守同一个模型宽度,也就是 d_model。

文中特别指出,为了进行残差连接,编码器和解码器中各子层以及嵌入层的输出维度需要保持一致。经典论文采用 d_model = 512。统一维度让每层都可以在原表示上增加一份更新,不必先把两条不同宽度的路径强行拼接或裁剪。

Transformer 各阶段张量形状沿 d_model 维度传递的示意图
Transformer 中的统一模型维度

词嵌入、注意力、FFN 和残差路径围绕同一个 d_model 传递表示。

d_model 代表什么

d_model 可以理解为每个词元在模型内部使用的表示宽度。输入词嵌入的每个位置有 d_model 个数值,编码器和解码器层中的隐藏状态也保持这个宽度。它不是词表大小,也不是序列长度,而是单个位置的特征维度。

当一个序列有长度 L 时,隐藏状态通常可以看成形状为 L × d_model 的矩阵;加入批次后,再多出一个 batch 维度。长度决定有多少个位置,d_model 决定每个位置能携带多少特征,两个概念不能混在一起。

模型增大 d_model,通常意味着每个位置有更宽的表达空间,但注意力投影、FFN 和输出层的计算量也会增加。它是模型规模的重要组成部分,却不能单独代表模型一定更强。

多头注意力为什么可以暂时变窄

多头注意力的输入和最终输出仍然使用 d_model,但每个头通常只处理其中一部分维度。若有 h 个头,常见设置是每个头的维度 d_k 或 d_v 约等于 d_model 除以 h。每个头分别计算自己的 Query、Key、Value,最后把各头结果拼接回来。

例如,d_model 为 512、头数为 8 时,每个头可以使用 64 维表示,八个头拼接后重新回到 512 维。这样既让不同头在不同子空间中学习关系,又让多头注意力的输出能够接回残差路径。头内维度变小并不是丢掉模型宽度,而是把宽度分给多个并行视角。

Transformer d_model、多头注意力维度和 FFN 维度关系图
d_model 与多头维度的关系

统一的模型宽度被分到多个注意力头中,计算后再拼接回 d_model。

FFN 为什么先扩大再缩回去

位置前馈网络通常先把 d_model 维向量投影到更大的中间维度 d_ff,经过激活函数后,再投影回 d_model。中间空间更宽,可以让每个位置完成更丰富的非线性特征组合;缩回模型宽度,则是为了把结果送回下一层和残差路径。

因此,FFN 的中间维度可以比 d_model 大,但它的最终输出仍要回到 d_model。扩大和缩回并不改变序列长度,也不让不同位置在 FFN 内直接互相读取;它改变的是每个位置内部的特征加工能力。

这也解释了为什么图中 FFN 看起来比输入向量更宽,却仍然能接回原来的 Transformer 层。真正需要与残差相加的是 FFN 的最终输出,而不是中间激活结果。

残差连接为什么要求两条路径同宽

残差连接的基本动作是把子层输出加回子层输入。如果输入是 d_model 维,输出也必须是 d_model 维,逐元素相加才有明确含义。统一宽度让每个子层可以学习一个更新量,原来的表示则沿着残差路径继续保留下来。

如果两条路径宽度不同,就不能直接相加,需要额外的线性投影把其中一条变换到另一种宽度。这样的设计并非绝对不可行,但会增加一层转换,也会让结构图和数值路径变得更复杂。经典 Transformer 通过保持子层输出一致,简化了层与层之间的连接。

Transformer 残差连接中输入输出维度一致并进行相加的示意图
残差相加需要相同维度

子层输入和输出保持 d_model 宽度,才能与残差路径进行逐元素相加。

交叉注意力也要回到同一个宽度

交叉注意力的 Query 来自解码器,Key 和 Value 来自编码器。两侧的原始表示需要经过各自的线性投影,映射到适合计算相关性的空间。即使编码器和解码器内部都使用 d_model,Query、Key、Value 在头内仍可能使用较小的投影维度。

多头计算结束后,交叉注意力的输出通常再次投影回 d_model,才能进入解码器的残差连接和后续 FFN。于是,源序列和目标序列可以在注意力内部建立联系,但各自的主干表示仍然保持统一宽度。

输出层为什么可以暂时变成词表大小

Transformer 最后的线性输出层会把 d_model 映射到词表大小 |V|,因为模型需要为每个词元给出一个分数。这里是有意的出口变化,不是主干层之间的尺寸不一致。Softmax 后得到词表概率,生成一个词元;下一次解码时,词元又会通过嵌入回到 d_model 维。

因此可以把 d_model 看成模型内部主干宽度,把词表大小看成输出空间宽度。两者在最后的 Linear 层连接,职责不同。不要因为输出 logits 的长度等于词表大小,就认为解码器内部每层都使用词表维度。

从形状角度重新看一遍 Transformer

一段长度为 L 的输入先变成 L × d_model 的嵌入矩阵,位置编码加入后形状不变;注意力在序列位置之间交换信息,输出仍回到 L × d_model;FFN 在每个位置内部先扩展到 d_ff,再缩回 d_model;残差和归一化继续沿着统一宽度传递。

多头注意力的头内维度、FFN 的中间维度和最终词表维度都可以暂时变化,但每次离开这些局部计算,都要回到主干约定的 d_model。把这条形状主线记住,阅读复杂模型结构时就不容易被局部矩阵大小带偏。

常见问题

d_model 就是词向量的维度吗?

在经典 Transformer 中,输入词嵌入的宽度通常就是 d_model,编码器和解码器主干也保持这个宽度。但不同模型可能在词嵌入层与主干之间加入额外投影,因此要结合具体结构判断。

为什么 FFN 中间层可以比 d_model 大?

FFN 的中间层用于扩大每个位置的特征加工空间,最终输出仍会投影回 d_model,以便接入残差路径和下一层。

所有注意力里的 Query、Key、Value 都必须是 d_model 维吗?

不一定。它们通常由 d_model 表示投影到每个头的较小维度,完成多头计算后再拼接并投影回 d_model。