Heng's Blog
04 04

Transformer Decoder 在自回归生成中接收已经右移的目标序列,并结合 Encoder 输出预测下一个 token。与 Encoder Block 相比,它多了一层 cross-attention,同时 self-attention 必须使用 causal mask。

本文整理自 hengproject/ML_recall 中的 transformers/deocder.ipynbDecoder.pyModel.py。Encoder 实现见上一篇

Decoder Block 的三层结构#

本文继续采用 Pre-LN。一个 Decoder Block 包含:

  1. Masked self-attention:目标序列内部建模,只允许关注当前位置及其之前的位置。
  2. Cross-attention:以 Decoder 状态作为 Query,以 Encoder 输出作为 Key 和 Value。
  3. Feed-forward network:对每个目标位置独立执行两层 MLP。

每个子层前都做 LayerNorm,子层输出经过 Dropout 后与输入形成残差连接:

Masked Self-Attention#

Self-attention 的 QQKKVV 都来自 Decoder 当前状态。它同时使用两种 mask:

  • tgt_padding_mask 遮蔽目标序列中的 padding Key;
  • causal mask 遮蔽当前 Query 右侧的未来 Key。

若不使用 causal mask,训练时每个位置都能直接看到未来的目标 token,模型会发生信息泄漏。推理时没有未来 token 可看,训练和推理行为将不一致。

Cross-Attention#

Cross-attention 连接 Encoder 与 Decoder:

Q=Xdecoder,K=V=Hencoder.Q = X_{decoder}, \qquad K = V = H_{encoder}.

因此 Query 长度为 ntgtn_{tgt},Key/Value 长度为 nsrcn_{src},注意力权重形状为:

(B,h,ntgt,nsrc).(B,h,n_{tgt},n_{src}).

这里使用源序列的 memory_padding_mask,而不是目标序列的 mask。Cross-attention 不需要 causal mask,因为完整源序列在编码阶段已经可用。

Decoder Block 实现#

这里要求 MultiHeadAttention 支持不同长度的 Query 与 Key/Value。Self-attention 中三者长度相同,而 cross-attention 中 ntgtn_{tgt}nsrcn_{src} 可以不同。

堆叠 Decoder Block#

无论堆叠多少层,Decoder 的外部形状都保持 (B,ntgt,dmodel)(B,n_{tgt},d_{model})

组合完整 Encoder-Decoder#

源序列与目标序列分别经过输入嵌入。Encoder 输出称为 memory,Decoder 输出再投影到词表维度,得到每个目标位置的 logits:

输入输出形状为:

张量形状
source_ids(B,nsrc)(B,n_{src})
target_ids(B,ntgt)(B,n_{tgt})
Encoder memory(B,nsrc,dmodel)(B,n_{src},d_{model})
Decoder output(B,ntgt,dmodel)(B,n_{tgt},d_{model})
logits(B,ntgt,V)(B,n_{tgt},V)

形状测试#

训练与生成时还缺什么#

上面的模块完成了核心前向传播,但一个可训练、可生成的序列模型还需要:

  • 将目标序列右移,以起始 token 作为 Decoder 的第一个输入;
  • 用未右移的目标序列计算交叉熵,并忽略 padding 位置;
  • 决定输入嵌入与输出投影是否共享权重;
  • 在生成时实现 greedy decoding、beam search 或 sampling,并维护停止条件;
  • 对全部被 mask 的行做保护,避免 softmax 产生 NaN
  • 根据任务分别管理源词表、目标词表与特殊 token。

Decoder 的核心逻辑可以概括为:先在已生成的目标前缀中建模,再从 Encoder memory 中检索源信息,最后通过 FFN 更新每个目标位置的表示。

Transformer - Transformer Decoder
https://heng-blog.pages.dev/blog/transformer-decoder
Author 杨苏恒
Published at April 30, 2025