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

Transformer 解码器为什么需要三类子层:掩码自注意力、交叉注意力与 FFN

围绕解码器结构,拆解掩码自注意力、Encoder-Decoder Attention 和位置前馈网络各自的输入、作用与执行顺序。

相关工具

解码器不是一个单独的生成按钮

在 Transformer 中,解码器负责根据目标序列已有的前缀,以及编码器对源序列形成的表示,逐步计算下一个词的概率。它并不是一个独立的生成按钮,而是一组按固定顺序组织起来的子层。经典结构中,一个解码器层通常包含掩码多头自注意力、Encoder-Decoder Attention(也常称为交叉注意力)和位置前馈网络三类子层。

三者分工很清楚:掩码自注意力只处理目标端已经出现的内容,交叉注意力从编码器输出中寻找与当前目标位置相关的源信息,FFN 则对融合后的表示做逐位置的非线性变换。每个子层外面还配有残差连接和 LayerNorm,多个解码器层再按同样的结构堆叠起来。

单层解码器的三类子层
单层解码器的三类子层

解码器层依次处理目标前缀、源序列记忆和逐位置特征变换。

掩码自注意力处理目标前缀

解码器的第一类子层是掩码多头自注意力。它的 Query、Key、Value 都来自目标端序列:训练时通常把目标句子右移一位,输入从起始标记开始;推理时则从起始标记或已有提示开始。这样,当前位置要预测的词不会提前出现在输入里。

掩码的作用是遮住当前位置之后的内容。第一个位置只能看到自己,第二个位置可以看到前两个位置,后面的词依次增加可见范围。注意力仍然可以在当前前缀内部建立联系,但不能偷看答案。这个约束让训练时的并行计算与生成时的从左到右过程保持一致,也解释了为什么解码器不能直接照搬编码器的双向自注意力。

交叉注意力读取源句记忆

经过掩码自注意力后,目标端的每个位置已经知道前缀上下文,但还不一定知道源序列中哪一部分最重要。交叉注意力就在这里发挥作用:Query 来自解码器当前的表示,Key 和 Value 来自编码器输出。解码器用自己的问题去查询源句记忆,再把相关的源信息带回来。

例如翻译一个较长的源句时,生成目标词的不同位置会关注源句的不同片段。注意力权重表达的是当前目标位置对各个源位置的相对关注程度,Value 则携带这些位置已经编码好的语义信息。它与自注意力最容易混淆的地方,在于输入来源不同:自注意力的三组向量来自同一侧,交叉注意力则把目标端作为 Query,把源端作为 Key 和 Value。

解码器三类子层的输入来源
解码器三类子层的输入来源

掩码自注意力使用目标前缀,交叉注意力连接目标表示与编码器记忆,FFN 对融合结果逐位置处理。

FFN 负责逐位置加工

在两次注意力操作之后,目标表示既包含了目标前缀之间的关系,也吸收了源序列记忆。位置前馈网络(Feed-Forward Network,简称 FFN)接着对每个位置的向量单独处理。典型形式是先把维度扩展到更大的中间空间,经过激活函数,再投影回模型维度:

FFN 不负责选择源位置,也不负责建立不同位置之间的直接联系;这些工作由两类注意力完成。它更像一个逐位置的特征加工器,通过非线性变换重新组合已经收集到的上下文特征。因为每个位置使用相同的参数,序列位置之间不会在 FFN 内部互相读取,但每个位置都能获得更丰富的表达能力。

为什么要按这个顺序执行

这三个子层的顺序可以理解成一个逐步收敛的问题。第一步先整理目标端已经生成的前缀,明确当前位置在目标序列中的上下文;第二步再拿这个上下文去查询源序列记忆,补上翻译、摘要或问答所需的外部信息;第三步对两侧融合后的表示做非线性加工,为输出层提供更适合分类和预测的特征。

如果把交叉注意力放到掩码自注意力之前,模型也可以被设计和训练,但它不再是 文中描述的经典 Transformer 解码器,信息融合的路径和归一化位置都会改变。实际阅读结构图时,应该同时关注子层顺序、残差连接和 LayerNorm 的位置。残差让每个子层只需学习增量,归一化则帮助不同层之间保持较稳定的数值尺度。

训练和推理中的三类子层

训练时,目标序列通常经过右移后一次性送入解码器。掩码自注意力用因果掩码限制可见范围,交叉注意力可以读取完整的编码器输出,FFN 对每个位置并行计算。虽然模型在一次前向过程中看到了整段目标输入,但每个位置仍只能使用当前位置之前的目标词,因此可以同时计算多个位置的损失。

推理时则必须从左到右循环:起始标记先经过三类子层,输出下一个词的概率;选出一个词并追加到目标前缀后,再次经过解码器。循环会在生成结束标记或达到长度上限时停止。训练与推理的主要差别在于目标前缀是否完整,而三类子层的职责并没有改变。

解码器的下一词预测流程
解码器的下一词预测流程

推理时,解码器反复读取已有前缀并预测一个新词,直到生成结束标记。

如何区分三类子层出了什么问题

如果训练损失下降得很快,但推理结果从第二三个词开始就混乱,首先应检查目标序列是否右移、因果掩码是否正确,以及推理时是否误把真实答案当成了输入。如果问题主要出现在长距离依赖上,则要进一步观察掩码是否覆盖了不该遮住的位置。

如果输出语法看起来正常,却总是没有抓住源句或给定资料中的关键信息,应检查交叉注意力的 Query、Key、Value 来源,源序列的填充位置是否被正确屏蔽,以及编码器输出是否确实传递到了每一层解码器。若上下文已经能够读到,但模型表达能力不足或训练不稳定,则可以从 FFN 的中间维度、激活函数、残差连接和归一化位置排查。

排查时不要只看最终输出。分别记录三类子层的输入形状、掩码形状和输出形状,往往比盯着一串损失值更容易定位问题。

把三类子层放回 Transformer 主线

回到 Transformer 的整体结构,解码器层其实是在反复完成三件事:从目标前缀中读取过去的信息,从源序列表示中选择当前需要的内容,再把这些信息加工成下一层可以继续使用的特征。掩码自注意力解决目标端的顺序问题,交叉注意力解决源端信息的对齐问题,FFN 负责非线性表达。

文中的解码器结构图画的是多个相同解码器层的堆叠,而不是三类子层只执行一次。每层都通过残差和归一化传递表示,最后由输出投影和概率分布完成下一个词的预测。记忆这条主线后,再看不同模型对归一化顺序、位置编码或缓存机制的改动,就不容易把局部实现误认为整体原理。

常见问题

交叉注意力也需要遮挡目标未来吗?

因果掩码主要用于目标端的掩码自注意力,交叉注意力读取的是编码器输出,不是在目标序列内部向未来读取。不过,源序列中的填充位置仍然需要用 Padding Mask 屏蔽。

交叉注意力中的 K 和 V 为什么来自编码器?

编码器输出保存了源序列的上下文表示。解码器用当前目标表示生成 Query,与源序列的 Key 计算相关性,再按权重汇总 Value,于是每个目标位置都能取回自己需要的源信息。

FFN 为什么不负责跨位置交互?

经典 Transformer 的 FFN 是逐位置计算的,同一组参数分别作用于每个位置。不同位置之间的交互由自注意力和交叉注意力完成,这样既保持了职责清晰,也便于并行计算。