Transformer与大语言模型:第13章 Decoder

第13章 Decoder

本章目标:

理解 Decoder 的 Mask 机制,为什么不能偷看未来,以及 Causal Attention 的实现。


13.1 为什么 Decoder 不能偷看未来?

假设我们在训练一个翻译模型:

输入(英文): I love AI
目标(中文): 我 爱 AI

训练时,Decoder 的输入是目标序列(右移一位):

Decoder 输入:  [START] 我 爱
Decoder 输出:  我 爱 AI

如果 Decoder 可以看到未来的 Token:

预测"我"时,看到了"爱"和"AI" → 作弊!

这样训练出来的模型,推理时(没有未来 Token)会完全失效。

所以必须用 Mask 遮住未来的 Token。


13.2 Causal Mask(因果掩码)

Causal Mask 是一个上三角矩阵,用于遮住未来的 Token:

序列长度 = 4

Mask:
     t=1  t=2  t=3  t=4
t=1 [ 0   -∞   -∞   -∞ ]
t=2 [ 0    0   -∞   -∞ ]
t=3 [ 0    0    0   -∞ ]
t=4 [ 0    0    0    0 ]
  • 0:可以看到(不遮住)
  • -∞:不能看到(遮住,Softmax 后变为 0)

Attention Score
[seq, seq]

加上 Causal Mask
上三角为 -∞

Softmax
-∞ 变为 0

Masked Attention Weight
只看当前和之前的Token


13.3 Causal Mask 的效果

以序列 [我, 爱, AI] 为例:

没有 Mask(BERT 风格):

     我    爱    AI
我  [0.5  0.3  0.2]  ← 我可以看到"爱"和"AI"
爱  [0.2  0.6  0.2]  ← 爱可以看到"我"和"AI"
AI  [0.3  0.3  0.4]

有 Causal Mask(GPT 风格):

     我    爱    AI
我  [1.0  0.0  0.0]  ← 我只能看到自己
爱  [0.4  0.6  0.0]  ← 爱只能看到"我"和自己
AI  [0.3  0.3  0.4]  ← AI可以看到所有

13.3.1 为什么 Mask 值是 -∞ 而不是 0?

这是初学者最常问的问题。答案和 Softmax 的数学性质有关。

如果把未来位置的 Score 设为 0:

Score:     [3,  0,  0]
Softmax:   [0.91, 0.045, 0.045]  ← 未来位置仍然分到了4.5%的权重!

因为 e0=1e^0 = 1e0=1,所以 Score=0 在 Softmax 中不代表概率为零,它仍然会分到权重。模型还是"偷看"了未来。

如果把未来位置的 Score 设为 -∞:

Score:     [3,  -∞,  -∞]
Softmax:   [1.0, 0, 0]  ← 未来位置权重严格为零

因为 e−∞=0e^{-\infty} = 0e=0,Softmax 后这些位置的概率精确为零

13.3.2 为什么用加法而不是乘法?

另一个常见疑问:为什么不直接把 Score 乘以 0?

❌ 乘法方案:Score × Mask = [3, 0, 0]
   → Softmax 后:[0.91, 0.045, 0.045]  ← 没有真正遮住!

✅ 加法方案:Score + Mask = [3, -∞, -∞]
   → Softmax 后:[1.0, 0, 0]  ← 完全遮住

加法的优势

  • 允许看的位置加 0(不改变原始 Score)
  • 需要遮住的位置加 -∞(Softmax 后精确为 0)
  • 不会像乘法那样遇到"负数×(-∞)=+∞"的数学问题

💡 实际代码中,-∞ 通常用 -1e9torch.finfo(dtype).min 来近似,保证 Softmax 后的值足够接近 0。

13.3.3 Mask 没有删除 Token

一个重要认识:Mask 不会删除任何 Token、Embedding 或 Value。它只修改 Attention Score

Token、Q、K、V → 全部正常计算,一个不少
Score = QK^T   → 正常算出完整的 [seq, seq] 矩阵
Score + Mask   → 只在这一步把未来位置变成 -∞
Softmax        → 未来位置的权重自然变成 0
Weight × V     → 未来位置对输出的贡献为 0

所以 Mask 的本质是:让未来 Token 在 Attention 权重竞争中失去资格,而不是物理删除它们。


13.4 Causal Mask 的实现

import tensorflow as tf

def create_causal_mask(seq_len):
    """
    创建因果掩码(上三角矩阵)
    返回: [1, 1, seq_len, seq_len],1表示遮住,0表示不遮住
    """
    mask = 1 - tf.linalg.band_part(tf.ones((seq_len, seq_len)), -1, 0)
    return mask[tf.newaxis, tf.newaxis, :, :]  # [1, 1, seq, seq]

# 测试
mask = create_causal_mask(4)
print(mask[0, 0])
# [[0. 1. 1. 1.]
#  [0. 0. 1. 1.]
#  [0. 0. 0. 1.]
#  [0. 0. 0. 0.]]

# 在 Attention 中使用
def masked_attention(Q, K, V, mask=None):
    d_k = tf.cast(tf.shape(K)[-1], tf.float32)
    scores = tf.matmul(Q, K, transpose_b=True) / tf.math.sqrt(d_k)

    if mask is not None:
        scores += (mask * -1e9)  # 遮住的位置加 -∞

    weights = tf.nn.softmax(scores, axis=-1)
    return tf.matmul(weights, V)

13.5 Decoder 的完整结构

原始 Transformer 的 Decoder Block 有三个子层:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值