Transformer 解码器为什么先做掩码自注意力,再做交叉注意力
围绕解码器三类子层的描述,解释目标前缀整理、源序列查询和 FFN 加工之间的先后关系。
相关工具
解码器一层为什么不只需要一种注意力
解码器同时面对两种信息:一边是目标序列已经生成的前缀,另一边是编码器整理好的源序列记忆。它既要知道自己已经说到哪里,也要知道源句中哪些内容值得读取。单独使用一种注意力,很难同时完成这两个方向的工作。
文中的经典解码器层包含掩码多头自注意力、Encoder-Decoder Attention 和位置前馈网络。三个子层按顺序处理:先整理目标前缀,再查询源序列,最后对融合结果做逐位置加工。

目标自注意力、交叉注意力和 FFN 按固定顺序组成一个解码器层。
第一步先整理目标前缀
解码器的掩码自注意力中,Query、Key、Value 都来自目标端。它先判断当前位置与已经出现的目标词之间有什么关系,并通过因果掩码排除未来目标位置。
这一步得到的是带有目标历史的表示。模型知道已经生成了哪些内容、当前位置在目标序列中的位置,以及目标前缀内部的依赖关系,但此时还没有根据源句选择信息。先整理目标端,可以让后面的 Query 更准确地表达“当前需要从源句寻找什么”。
第二步用目标表示查询源记忆
交叉注意力接收第一步得到的目标表示作为 Query,编码器输出作为 Key 和 Value。每个目标位置用自己的 Query 与源序列各位置的 Key 比较,再按权重汇总对应的 Value。
因为 Query 已经包含目标前缀信息,交叉注意力不只是盲目寻找源句中的相似词,而是在当前生成状态下提出问题。生成不同目标词时,Query 不同,关注的源位置也可能不同。

Query 来自目标端,Key 和 Value 来自编码器源记忆,完成两套序列之间的信息交换。
为什么不能先查询源句再整理目标前缀
如果交叉注意力先执行,当前 Query 还没有充分融合目标历史,解码器对“此刻需要什么源信息”的判断会更粗。它当然仍然可以读取源句,但信息查询建立在不同的目标表示上。
经典结构先让目标端形成受因果约束的上下文,再把这个上下文带到源记忆中查询。这样,源句读取与当前生成状态相连,交叉注意力输出也更适合继续进入 FFN 和下一层解码器。
第三步为什么还要经过 FFN
交叉注意力返回的是源信息与目标状态的加权组合,仍然需要在每个目标位置上做非线性加工。FFN 不再负责从别的位置选择信息,而是把已经融合的目标历史和源记忆重新组合成更适合输出的特征。
残差连接让目标端原有表示继续保留,LayerNorm 帮助不同子层的数值尺度稳定。经过 FFN 后,当前层输出再传给下一层,下一层会重复相似的目标整理、源查询和特征加工过程。

解码器先处理目标前缀,再读取源记忆,最后由 FFN 加工融合结果。
不同子层的掩码边界不同
掩码自注意力需要因果掩码,避免目标位置读取未来;如果目标批次中有 Padding,还需要同时忽略填充位置。交叉注意力读取的是源序列记忆,通常需要屏蔽源端 Padding,但不使用目标自注意力那种未来三角掩码。
把掩码放错位置会造成不同问题:目标自注意力没有因果限制会泄露答案,交叉注意力错误使用目标未来掩码则可能遮住本来应该读取的源信息。判断掩码时,要先看当前 Query、Key、Value 分别来自哪一侧。
训练和推理中的顺序保持一致
训练时,右移后的目标序列可以一次送入解码器。掩码自注意力保证每个位置只使用真实前缀,交叉注意力读取完整源记忆,FFN 逐位置加工,多个目标位置可以并行得到预测。
推理时,目标前缀随着生成逐步变长。每一轮仍然先整理当前前缀,再查询源记忆,再输出下一个词。计算可能通过缓存得到优化,但三类子层的职责和先后关系不变。
把解码器一层记成三个问题
第一步问:目标前缀已经包含了什么?这由掩码自注意力回答。第二步问:源序列中哪些内容和当前目标状态相关?这由交叉注意力回答。第三步问:融合后的信息如何变成更适合下一层或输出层的表示?这由 FFN 回答。
三类子层不是简单堆在一起,而是沿着“目标历史、源信息、特征加工”的顺序完成一次生成准备。理解这个顺序后,再看解码器堆叠、缓存和输出层,会更容易定位每个模块的作用。
常见问题
交叉注意力为什么要使用第一步的目标表示作为 Query?
第一步的目标表示已经包含当前目标前缀和因果上下文,交叉注意力可以据此判断此刻需要从源记忆中读取什么。
交叉注意力也需要遮住源序列未来吗?
源序列通常已经完整给定,不需要目标端那种因果掩码。它主要需要屏蔽源序列中的 Padding 位置。
FFN 为什么放在交叉注意力之后?
交叉注意力先把目标状态需要的源信息取回,FFN 再对融合后的每个位置做非线性加工,形成更适合下一层使用的表示。