注意力机制
注意力机制
序列转导 (Sequence Transduction)
📖 核心概念
定义
序列转导 (Sequence Transduction) 指的是任何将输入序列 $X = (x_1, ..., x_n)$ 转换为输出序列 $Y = (y_1, ..., y_m)$ 的任务,且 $n$ 与 $m$ 可以不相等。典型应用包括机器翻译、文本摘要、对话系统等。
生活类比: 这就好比同声传译。译员听到一段中文(Input Sequence),在脑海中将其含义消化理解(Encoding),然后用英语重新表达出来(Decoding)。译员不需要听到一个字翻一个字,而是理解语意块之后再生成。
⚙️ Encoder-Decoder 架构
为了解决这类变长序列到变长序列的问题,经典的 Encoder-Decoder (编码器-解码器) 架构应运而生。
它包含两个主要部分:
- Encoder (编码器):负责"读"。将输入序列压缩成一个固定长度的上下文向量 (Context Vector)。 $$ z = \text{Encoder}(x_1, ..., x_n) $$
- Decoder (解码器):负责"写"。根据上下文向量 $z$ 和已生成的历史词,逐步生成下一个词。 $$ y_t = \text{Decoder}(z, y_{1}, ..., y_{t-1}) $$
瓶颈 (The Bottleneck)
固定长度的局限性
在引入 Attention 之前,Encoder 必须把整个句子的信息(无论多长)都压缩进一个固定长度的向量 $z$ 中。这就像强迫你用一张便利贴记下整本小说的摘要,不可避免会导致信息丢失,特别是对于长序列,解码器往往无法获取开头的细节。
Attention 机制
💡 核心思想:Q, K, V
Attention 的灵感来源于信息检索。想象你在图书馆(或搜索引擎)找书:
- Query (Q): 你手中的书单或搜索词(“我想找关于深度学习的书”)。
- Key (K): 图书馆每一本书的索引标签(“人工智能”, “深度学习”, “烹饪”)。
- Value (V): 每一本书的具体内容。
Attention 机制计算 Query 和各个 Key 的相似度(注意力分数),然后根据这个分数对 Value 进行加权求和。
- 如果 $Q$ 和某个 $K$ 很像,那对应的 $V$ 就很重要,权重就高。
- 最终输出是所有 $V$ 的加权混合。
📐 缩放点积注意力 (Scaled Dot-Product Attention)
这是 Transformer 中的底层数学运算单元。
$$ \text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V $$- Dot-Product $QK^T$:
- 计算 $Q$ 和 $K$ 的相似度。点积越大,越相似。
- $Q$是$N \times d$矩阵($N$是句子长度),$K^{T}$是$d \times M$。乘完后是$N \times M$的矩阵。
- 这就形成了一个关联矩阵:第$i$行第$j$列的值,表示第$i$个词和第$j$个词的相似度。
- Scaled $\frac{1}{\sqrt{d_k}}$缩放因子:
- 当维度 $d_k$ 很大时,点积结果会变的非常大,导致 softmax 函数进入梯度极小的饱和区(梯度消失)。
- 除以 $\sqrt{d_k}$ 将数值拉回均值0方差1的分布,稳定梯度。
- Softmax:
- 将分数归一化为概率分布(和为1)。
- 决定了我们要从$V$中提取多少信息。
- …$V$:
- 这是最后一步,根据刚才算出的重要性,混合所有词的信息,生成当前词的新表示(New Representation)。
🧩 多头注意力 (Multi-Head Attention)
为什么要多头?:就像你看一篇文章,既要关注语法结构(主谓宾),又要关注语义指代(它指谁),还要关注时态。一个头可能只关注一种关系,通过多头机制,模型可以将输入映射到不同的子空间(Subspaces),并行捕捉多种不同层面的依赖关系
Multi-Head 的做法:
- 把输入的向量切分成多份(或者映射到多个低维空间)。
- 独立做 Attention 计算。
- 最后把结果**拼接(Concat)**起来,再过一个线性层融合。
应用模式
自注意力 (Self-Attention)
“内省”: $Q, K, V$ 全部来源于同一个输入序列 $X$。
$$ \text{SelfAttention}(X) = \text{Attention}(XW^Q, XW^K, XW^V) $$- 来源: Encoder 的每一层,Decoder 的 Masked Self-Attention 层。
- 作用: 捕捉序列内部的依赖关系。不仅看当前词,还要看上下文。
- 例子: “The animal didn’t cross the street because it was too tired.”
- 当处理 “it” 时,Self-Attention 机制会关注到前面的 “animal”,从而明白 “it” 指代的是动物而不是街道。
交叉注意力 (Cross-Attention)
“对齐”: 连接 Encoder 和 Decoder 的桥梁。
- Query (Q): 来自 Decoder 的上一层输出(代表"我当前想生成什么")。
- Key (K) / Value (V): 来自 Encoder 的最终输出(代表"源句子的完整信息")。
- 作用: 让解码器在生成每个词时,都能"回头看"源句子中相关的部分。
- 例子: 机器翻译中,当生成英文单词 “Apple” 时,Cross-Attention 会重点关注中文源句中的 “苹果” 二字。
🚀 推理加速:KV Cache
⏳ 背景:自回归生成 (Autoregressive Generation)
Transformer 解码器(Decoder)在推理时是自回归的,即生成的词是一个接一个蹦出来的:
$$ \begin{aligned} \text{Step 1: } & \text{Input: } [BOS] & \rightarrow \text{Output: } y_1 \\ \text{Step 2: } & \text{Input: } [BOS, y_1] & \rightarrow \text{Output: } y_2 \\ \text{Step 3: } & \text{Input: } [BOS, y_1, y_2] & \rightarrow \text{Output: } y_3 \end{aligned} $$注意,当生成 $y_3$ 时,模型再次接收 $[BOS, y_1, y_2]$ 作为输入。在计算 Attention 时,它需要重新计算 $y_1$ 和 $y_2$ 的 Key 和 Value。这部分计算是完全冗余的,因为 $y_1$ 和 $y_2$ 在之前的步骤中已经计算过了,且它们的值只取决于之前的输入,不会改变。
💾 机制:空间换时间
为了消除冗余,我们引入 KV Cache。
- Idea: 把每一步计算出的 Key 和 Value 向量缓存在显存中。
- Process:
- 当生成第 $t$ 个 token $x_t$ 时,只需计算它自己的 Query, Key, Value ($q_t, k_t, v_t$)。
- 从 Cache 中读出之前的 $K_{1:t-1}$ 和 $V_{1:t-1}$。
- 拼接 (Concat) 得到完整的 $K = [K_{cache}, k_t]$ 和 $V = [V_{cache}, v_t]$。
- 计算 Attention: $\text{Attention}(q_t, K, V)$。
⚖️ 代价与权衡
- 收益 (Pros): 极大地减少了矩阵运算量 (FLOPs),推理速度提升显著,特别是长序列。
- 代价 (Cons): 显存占用剧增。
- 显存占用 $\approx 2 \times B \times L \times H \times D \times N_{layers}$ (2 for K&V, Batch, SeqLen, Heads, Dim, Layers)。
- 在长上下文 (Long Context) 场景下,KV Cache 往往是显存的瓶颈,限制了 Batch Size 的大小。
🔗 参考与扩展
- 原论文: Attention Is All You Need (Vaswani et al., 2017)
- FlashAttention: IO 感知的精确注意力算法,大幅加速计算。
- KV Cache: 推理阶段的加速关键技术。