多模态模型里常见这样一个配置:image patch 之间双向可见、text 之间 causal、text 又能看到全部 image patch。这套东西是 self-attention 还是 cross-attention?答案是:全部都是 self-attention,差异只在掩码矩阵。把 QKV 来源和掩码这两个正交维度理清,attention 的名词迷宫就通了。

区分 attention 家族只需要盯住两个维度:Q 与 K/V 是否同源,以及施加了什么掩码。前者把注意力分成 self 和 cross,后者把 self-attention 劈成 bidirectional 和 causal。下面从底层算子讲起。

Attention 的底层原语

几乎所有 attention 都建立在同一个算子上,Scaled Dot-Product Attention:

流程三步:线性变换得到 Q、K、V;用 softmax 归一化点积得到注意力权重;加权求和。 把点积的方差拉回 1—— 增大时点积随之变大,softmax 落入饱和区,梯度消失。

Self-attention 与 cross-attention 的分界线只有一条:Q 和 K/V 是否同源。Self-attention 的 Q、K、V 来自同一组输入(),处理同一序列内部元素间的关系,每个元素根据与其他元素的关系更新表示,能捕捉全局依赖且天然支持并行。Cross-attention 的 Q 来自 A、K/V 来自 B(,A≠B),查询序列通过 Q 向键值序列寻求信息——机器翻译的 encoder-decoder、图像-文本多模态都是这个结构。

类型Q 与 K/V 来源交互对象应用场景
Self-attention同一序列序列内部元素之间Transformer、BERT
Cross-attention不同序列查询序列 → 键值序列多模态、Encoder-Decoder

判定顺序

先看 QKV 是否同源,定 self/cross;再看掩码,定 causal/bidirectional。掩码是独立的第三维,self 和 cross 都能加。Causal 与 Bidirectional 不是两套计算逻辑,底层公式完全一样,差异只在 softmax 之前加不加上三角掩码。

掩码把 self-attention 劈成双向与因果

公式不变,差异只在 softmax 之前加不加一个上三角 掩码。

Bidirectional self-attention(即 non-causal self-attention)不加掩码,每个位置看序列里所有其它位置,原始 Transformer 的 encoder、BERT、ViT、DiT 和 image patch 都用它。Causal self-attention(即 masked self-attention)施加下三角掩码,位置 看不到 的未来 token,支撑自回归生成,Transformer decoder 第一层、GPT 和各类 LLM 文本 decoder 都走这条。它 QKV 依然同源,所以仍然是 self-attention。

Multi-head attention 只是包装层:把 QKV 切分成多组头、各自跑一遍 scaled dot-product attention、再拼接输出,内部可配成任意组合——MHA 无 mask 是 bidirectional,加 causal mask 是 causal,Q 与 K/V 不同源就是 cross。原始 Transformer 的三个模块正好各占其一:encoder 的 bidirectional self-attention、decoder 第一层的 causal self-attention、decoder 第二层的 cross-attention(Q 来自 decoder,K/V 来自 encoder)。

这里有一个高频坑:self-attention 不等于双向。初学者常默认 self-attention 就是 bidirectional,但 GPT 是 self-attention 且是 causal——self-attention 只约束 QKV 同源,不约束可见性。

Masked Self-Attention 与 Prefix Causal Attention

“masked attention” 是重灾区。mask 本是通用概念,但绝大多数论文里 Masked Self-Attention 专指 Causal Self-Attention;LLM 语境下提到 “masked attention”,几乎只指因果掩码,而不是任意加了 mask 的 attention。

两种 mask 完全不同,且可以同时叠加。Padding mask 屏蔽 <pad> 占位 token,双向和 causal 都能用,只是忽略无效位置。Causal mask 屏蔽时序上未来的位置,专用于自回归。

mask 的含义由上下文决定

双向 attention 也可以加 padding mask,但加了 padding mask 不叫 causal,判断是否 causal 只看有没有下三角掩码。causal self-attention 可以同时叠加 padding mask 与 causal mask。

Prefix Causal Attention 是多模态 VL 模型(Qwen-VL、LLaVA)的标准掩码范式。序列拼接成 [image_patch_1...image_patch_M][text_1...text_N],掩码按位置段设计:image patch 内部双向、互相可见;text 部分 causal、看不到后面的 text;text 的 query 可以看到全部 image patch(image 是前缀,属于历史);image patch 禁止看到后面的 text token。

图像段别套全局 causal

有人直接对整个拼接序列套一个全局 causal 掩码,结果 image patch 之间也变成 causal,图像性能明显下降。prefix causal 只是 causal self-attention 的定制掩码变种,不是新算子。

高效变体与 mask 正交

下面这些改的是注意力的计算逻辑,与 causal/bidirectional 属于两个正交维度。同一个算子(比如 FlashAttention)既能跑 causal 也能跑 bidirectional,取决于传入的 mask 标记。

  • FlashAttention / FlashAttention-2:IO 感知的 tiling,前向与反向都不物化完整注意力矩阵,省显存、加速,支持 causal 与 non-causal 两种模式
  • Sparse Attention:只对部分 token 计算 score(Longformer)
  • Sliding Window Attention(SWA):只看局部窗口(Mistral),可 causal 可双向
  • Grouped-Query Attention(GQA)/ Multi-Query Attention(MQA):KV 头分组共享,加速推理

头组织 ≠ 因果

GQA/MQA 是 Q/K/V 头的组织方式,不决定是否因果。底层仍是 scaled dot-product,causal、双向都能配。

顺手把另一条分类轴也交代了。score 的计算方式除点积外还有 additive(Bahdanau 用前馈网络算权重);按可微性分,soft attention 连续加权可微(NMT、图像描述),hard attention 离散选择不可微(图像标注);按交互范围分,global 与所有键交互、local 只看局部窗口、sparse 只选部分键值。

类型差异典型用途
Additive / Dot-productscore 计算:前馈网络 vs 点积Bahdanau / 主流 Transformer
Hard / Soft离散选择不可微 / 连续加权可微图像标注 / NMT、图像描述
Global / Local / Sparse交互范围:全部 / 局部窗口 / 部分键值短序列 / 长序列 / 超长序列

架构与掩码的映射

  • Encoder-only(BERT、ViT):所有层用 bidirectional self-attention
  • Decoder-only(GPT、LLM):所有层用 causal self-attention
  • Encoder-Decoder(T5、原始 Transformer):encoder 双向,decoder 第一层因果,decoder 第二层 cross-attention
  • 多模态 VL(LLaVA、Qwen-VL):decoder-only + prefix causal mask,模型本体还是 decoder,定制掩码让 image patch 内部双向

Causal 与 cross 也是高频混淆点:causal 是 QKV 同源加下三角掩码,属于 self-attention 子类;cross 的 Q 与 K/V 来源不同,跟 mask 无关。

极简对照表

名词QKV 来源掩码典型用途
Scaled Dot-Product Attention基础算子,不约束 QKV可选底层原语
Bidirectional Self-AttentionQKV 同一序列无 causal mask,可有 padding maskBERT、ViT、image patch
Causal Self-Attention(Masked Self-Attention)QKV 同一序列causal 下三角掩码GPT、文本自回归
Prefix-Causal Self-AttentionQKV 同一序列前缀双向、后面 causalVL 多模态 image+text 序列
Cross-AttentionQ 来自 A,K/V 来自 B自定义Encoder-Decoder、Diffusion、多模态
Multi-Head Attention(MHA)多头包装层可配任意 mask封装上面所有模式
GQA/MQAQKV 头分组优化不改变,可 causal/双向LLM 推理加速

回到开头的问题:text 用 causal、image patch 用 bidirectional,底层全部是 self-attention——QKV 来自同一个拼接序列 [img; text],只是自定义了一个 prefix-causal 掩码矩阵,在同一个 MHA 内部对不同位置设不同可见性。这不是两套注意力算子。

一个函数就能把三种模式收进同一份代码:

import math, torch
 
def scaled_dot_product_attention(q, k, v, mask=None):
    scores = q @ k.transpose(-1, -2) / math.sqrt(k.shape[-1])
    if mask is not None:  # None=双向;下三角掩码=causal;自定义=prefix-causal
        scores = scores.masked_fill(mask == 0, -1e9)
    return torch.softmax(scores, dim=-1) @ v

读 attention 代码时,第一件事永远是问三句:Q 来自哪、K/V 来自哪、mask 是哪种。三个答案都清楚,attention 就没秘密了。