2.1 自注意力、位置编码与前馈网络:Transformer 三件套一次搞懂

1 阅读8分钟

基于《大规模语言模型:从理论到实践(第2版)》第2章 大语言模型基础

爆款小标题:面试必考的 Transformer 核心,原书公式与直觉对照版


为什么这一节重要

Transformer 是现代大语言模型的骨架,而自注意力(Self-Attention)、**位置编码(Positional Encoding)前馈网络(FFN)**是构成 Transformer 块的三大核心组件。无论是读源码、做模型改动还是面试,都绕不开对这三者的准确理解:注意力如何实现「任意位置看任意位置」、位置编码为何必要、FFN 在块里扮演什么角色。本节结合原书第 2 章,用「直觉 + 公式」把三件套讲清,并点到长上下文与 RoPE 等工程上常遇的延伸,为后续 GPT/LLaMA 架构与长上下文扩展打基础。


学习目标

学完本节,你将能够:

  • 讲清 Self-Attention:用自己的话说明 Query/Key/Value 从哪来、注意力权重如何计算、输出如何得到,以及「关注任意位置」的直觉。
  • 理解位置编码:说明为什么需要位置编码、绝对与相对位置编码(含 RoPE)的大致思路,以及长序列扩展时的常见做法(如 NTK、YaRN)。
  • 掌握 FFN 的角色:说明前馈网络在 Transformer 块中的位置、典型结构(如中间维度 4x)以及与注意力的分工(注意力做交互、FFN 做逐点变换)。

一、Self-Attention:从直觉到公式(原书第 2 章)

直觉:如何让每个 token「看到」整个序列

在序列建模中,当前 token 的表示往往需要依赖上下文其他位置的信息。循环网络(RNN)是靠「一步步往后传」间接看到历史;而 Transformer 的诉求是:在一步内让每个位置都能直接访问序列中任意位置。自注意力做的就是这件事:对每个位置,用一套权重对所有位置做加权求和,权重由「当前问什么」(Query)和「别处提供什么」(Key)的匹配程度决定,实际取用的内容来自「别处的值」(Value)。

公式与计算流程(原书第 2 章)

设输入序列为 ( X \in \mathbb{R}^{n \times d} )(n 为序列长度,d 为模型维度)。经过三个线性层得到:

  • Query:( Q = X W_Q ),( W_Q \in \mathbb{R}^{d \times d_k} )
  • Key:( K = X W_K ),( W_K \in \mathbb{R}^{d \times d_k} )
  • Value:( V = X W_V ),( W_V \in \mathbb{R}^{d \times d_v} )

通常 ( d_k = d_v = d )(或 ( d/\text{head} ) 做多头)。注意力权重为 Query 与 Key 的点积再缩放并做 softmax:

[ \text{Attention}(Q,K,V) = \text{softmax}\left(\frac{QK^\top}{\sqrt{d_k}}\right) V ]

  • ( QK^\top ) 的 ((i,j)) 元素表示位置 (i) 对位置 (j) 的「匹配分」;除以 (\sqrt{d_k}) 是为了在 (d_k) 较大时避免 softmax 进入饱和区,梯度更稳定。
  • softmax 后得到每行和为 1 的权重矩阵,再右乘 (V),即对每个位置 (i),输出为「所有位置 (j) 的 (V_j) 的加权和」,权重由 (i) 对 (j) 的注意力决定。

因此,一次矩阵乘法 (QK^\top) 就能得到「每个 token 对序列中所有 token 的注意力权重」;再与 (V) 相乘即得到基于注意力的新表示。多头注意力(Multi-Head Attention)就是把 (d) 拆成多组独立的 (Q/K/V),各自做上述计算后拼接再经一层线性变换,以便从不同子空间学习不同性质的关系(原书第 2 章)。

工程上的对应:在阅读或修改 Transformer 代码时,能对应到「哪一步是 (Q/K/V) 投影」「哪里算 (QK^\top/\sqrt{d_k})」「哪里做 softmax 和乘 (V)」;若使用因果掩码(下一节会提到),会在 softmax 前把「未来」位置 mask 掉。


二、位置编码:为什么需要、常见方案与长序列(原书第 2 章)

为什么需要位置编码

上述注意力机制里,(Q、K、V) 只依赖 (X) 的内容,对 token 的顺序没有感知——打乱输入顺序,注意力权重矩阵只会同步打乱,输出与顺序无关。但语言和代码都依赖顺序(「不吃饭」和「饭不吃」含义不同),因此必须显式注入位置信息。位置编码就是在输入或每一层为每个位置加上与位置相关的向量,使模型能区分「第几个 token」。

绝对位置编码

最早在 Transformer 论文中使用的是正弦/余弦函数编码:对位置 (pos) 和维度 (i),用不同频率的 sin/cos 组合成固定向量,再与输入相加。其特点是无需学习、可外推到比训练更长的序列(但外推效果往往有限)。也有可学习的位置嵌入(如 BERT):为每个位置学一个向量,长度受限于训练时见过的最大长度。

相对位置编码与 RoPE

相对位置编码关注的是「两个 token 之间的相对距离」而非绝对位置,在长序列与外推上往往更稳。RoPE(Rotary Position Embedding) 被 LLaMA、GPT-NeoX 等广泛采用:不直接加向量,而是对 (Q、K) 按位置做旋转变换,使得注意力分数仅依赖相对位置差。好处是:相对位置关系在训练长度内一致,且对「长度外推」更友好,便于后续用 NTK、YaRN 等方式扩展上下文(原书第 2 章及长上下文相关讨论)。

长上下文扩展时的注意点

当需要比训练时更长的上下文时,常用做法包括:位置插值(把位置索引缩放)、NTK-aware 插值、YaRN 等。选型或阅读文档时,可关注模型是否使用 RoPE、默认最大长度是多少、是否支持上述某种扩展方式,以便在长文档、长对话场景下正确配置。


三、前馈网络(FFN)在块中的角色(原书第 2 章)

结构

Transformer 块中,在自注意力之后通常会接一个前馈网络(FFN),即两层线性变换加激活:

[ \text{FFN}(x) = \text{activation}(x W_1 + b_1) W_2 + b_2 ]

常见做法是中间维度为 (4d)(即 (W_1: d \to 4d),(W_2: 4d \to d)),激活函数在 LLaMA 等模型中多用 SwiGLU 等变体。原书第 2 章对 LLaMA 的 SwiGLU 有说明。

与注意力的分工

  • 注意力:做序列内不同位置之间的信息聚合,即「谁和谁相关、取多少」。
  • FFN:对每个位置独立做非线性变换,不跨位置,相当于「在已有表示上再做一层抽象与维度变换」。

二者配合:先通过注意力把上下文信息聚到当前表示里,再通过 FFN 做逐点非线性映射,形成「注意力 + 前馈」的块结构;多个这样的块堆叠成深层 Transformer。阅读代码时,能区分「这一层是 Attention」「这一层是 FFN」「这里加的是位置编码」即可快速理清结构。


四、工程实战要点

1. 读代码时对应到「三层结构」

在 Hugging Face、Megatron 或原书配套代码中,一个 Decoder Block 通常包含:LayerNorm(或 RMSNorm)→ Attention → 残差 → Norm → FFN → 残差。能对应到「哪里算 Q/K/V」「哪里做 mask」「哪里是 FFN 的两层线性」有助于调试与修改(例如改头数、改 FFN 中间维度)。

2. 长上下文选型时关注位置编码与扩展方式

若业务需要 8K、32K 甚至更长上下文,要确认:基座是否使用 RoPE、训练时最大长度、是否提供或支持 NTK/YaRN 等扩展。不同扩展方式对效果与算力影响不同,需结合文档与实测选择。


五、常见误区与避坑指南

误区一:只背公式不理解「为什么需要 Q/K/V」

若只记住 (QK^\top V) 而不理解「Query 问、Key 答、Value 取」,很难解释多头在做什么、以及如何改设计。避坑:从「如何让任意 token 看到整句并按相关性加权」出发,理解 Q 表示「当前要查什么」、K 表示「别处能提供什么」、V 表示「实际取用的内容」,公式就是这一直觉的数学实现。

误区二:忽略位置编码,以为 Transformer 天然懂顺序

未加位置编码的 Transformer 对序列顺序不敏感,效果会明显变差。避坑:在自实现或修改模型时,务必加入位置编码(或 RoPE 等),并确认其与基座一致(绝对 vs 相对、最大长度等)。

误区三:把「注意力权重」和「输出」混淆

注意力权重是 softmax((QK^\top/\sqrt{d_k})),形状为 ((n,n));最终输出是「权重 × V」,形状与 (V) 一致。避坑:分析或可视化时分清是在看「权重」还是「加权后的输出」,避免误读。


六、小结与衔接

本节紧扣原书第 2 章,梳理了 Transformer 三件套:Self-Attention 的 Q/K/V 与 (QK^\top V) 计算、「任意位置看任意位置」的直觉;位置编码的必要性与绝对/相对(RoPE)思路及长序列扩展;FFN 的结构与在块中「逐点变换」的角色。下一节将在此基础上看解码器-only的 GPT、LLaMA 与混合专家(MOE)架构,以及它们与 BERT 等编码器在训练目标与使用场景上的区别。


课后思考题

  1. 公式表达:在只允许使用一次矩阵乘法的前提下,如何用公式表达「某个 token 对序列中所有 token 的注意力权重」?(提示:即 (QK^\top) 的某一行经 softmax 前或后的结果。)
  2. RoPE 与长序列:RoPE 相比绝对位置编码,在长序列扩展时通常有什么优势?请结合「外推」简要说明。