从 RNN 爬到 Transformer 山顶

第一次听到 Transformer 的时候,我脑子里闪过三个画面:

  • 物理书里的“变压器”
  • 变形金刚
  • 导师嘴里那句:“现在大部分大模型都是这个架构……”

然后我去翻论文《Attention is All You Need》,翻开第一眼:
公式一堆、结构图一堆,我当场关掉 PDF,默默记住一个结论:

这个东西以后肯定逃不过,但今天先不学。

直到后面真的要用到它,我才开始系统地啃。下面的内容可以看作是我这个初学者把 Transformer 从“听过名字”到“勉强理解”的过程整理。


一、先说结论:Transformer 到底干了件什么事?

如果只能用一句话来概括 Transformer,我现在会这样说:

以前我们处理一句话,是按时间步从左到右递推;
Transformer 改成了:整句一起看,通过自注意力让每个位置和所有位置建立联系。

更具体一点:

  • RNN:依次处理每一步依赖前一步的隐状态$(h_{t-1})$;
  • Transformer:把整段序列表示成矩阵,一次性送进若干层自注意力和前馈网络中,在每一层里,任意两个位置都可以直接交互信息

它的两个核心优势:

  1. 计算上不再严格串行,可以很好地并行
  2. 任意距离的依赖都可以通过注意力直接建模,长依赖不再需要“层层传递”

剩下的公式、结构设计,基本都是围绕这两点展开的工程实现细节。


二、以前的我们都是怎么处理“序列”的?

在遇到 Transformer 之前,主流的序列建模方法是 RNN / LSTM / GRU。

典型形式是:

每个时间步的隐状态依赖当前输入和上一个隐状态。从直觉来看,这非常符合“按顺序处理”的想法。

问题也很典型:

  • 序列一长,早期的信息要一层层往后传,容易衰减(梯度消失/信息稀释);
  • 每一步要等前一步算完,并行度有限
  • 想把模型做大、把序列拉长,训练成本会明显上升。

简单说,RNN 系列的结构在“表达序列依赖”和“与现代硬件的计算模式”之间,存在一个天然的矛盾。

Transformer 的思路就是把这个矛盾拆开:顺序感不靠递推来体现,而交给其他机制(位置编码),序列关系不靠链式传递,而用注意力做全局建模。


三、Self-Attention:一句话里的词怎么“互相看”?

3.1 一个具体例子

来看一句中文:

“昨天我在公园看到一个人,他牵着一只看起来像猫的狗。”

在理解这句话时:

  • 看到“他”,大多数人会自然地把它和前面的“一个人”对应起来;
  • 看到“像猫的狗”,会把“像猫”和“狗”关联,而不是“公园像猫”。

也就是说,人类在理解语句时,并不是只盯着当前位置,而是会参考整句中其他相关的位置。

Self-Attention 做的事情就是:
让模型在计算每个位置的表示时,可以访问整个序列,根据“相关性”来决定该从哪些位置获取信息。

3.2 Q / K / V 到底在干什么?

一开始看到 Q/K/V 我也一头雾水,后来把它们简单地整理成三个角色:

  • Q(Query):查询向量,表示当前这个位置“想要什么信息”;
  • K(Key):键向量,表示序列中每个位置可以被“匹配”的特征;
  • V(Value):值向量,是真正要被加权聚合的信息。

自注意力的计算形式是:

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

逐步理解一下:

  1. 对序列每个位置 $(i)$,利用线性变换得到它的 $(Q_i, K_i, V_i)$;
  2. 对于位置 $(i)$,计算它的$ (Q_i)$ 与所有位置 $(j)$ 的 $(K_j) $的点积,得到一串相关性分数;
  3. 对这些分数做 $softmax$,得到一组权重$ ( \alpha_{ij} )$;
  4. 用这组权重对所有 $(V_j)$ 做加权求和,得到位置$ (i) $的新的表示。

Self-Attention = 每个位置用自己的 Q,去匹配全序列的 K,得到权重后对全序列的 V 做加权求和。

相比 RNN 这种“链式传递”,Self-Attention 允许任意位置之间直接发生交互。


四、多头注意力:为什么要搞那么多“头”?

多头注意力(Multi-Head Attention)刚听上去有点吓人,其实做的事情非常机械:

  1. 把输入向量先通过线性变换,分成 (h) 份不同的子空间(head);
  2. 每个 head 在自己的子空间里独立完成一遍 Self-Attention;
  3. 把所有 head 的输出在最后一个维度拼接起来,再经过一次线性变换。

形式上是:

$[
\text{head}_i = \text{Attention}(QW_i^Q, KW_i^K, VW_i^V)
]$

$[
\text{MultiHead}(Q,K,V) = \text{Concat}(\text{head}_1,\dots,\text{head}_h)W^O
]$

直观含义:

  • 不同的 head 在不同的子空间中建模“相关性”,可以捕捉到不同类型的模式(比如局部关系、长距离关系、语法结构等);
  • 多个 head 并行计算,不会增加时间复杂度量级,只是扩大了宽度。

所以,可以简化地记住:

多头注意力 = 多个自注意力并联,在不同子空间里建模,再合并。


五、顺序去哪了?——位置编码出场

上面说的 Self-Attention 有一个明显问题:
它本身对序列的顺序不敏感,只关心向量值,而不关心“第几个位置”。

如果不给模型额外的位置信息,“我 在 昨天 公园”和“公园 昨天 在 我”在它眼里只是向量排列的变化。

解决方法就是位置编码(Positional Encoding)
在送入 Transformer 之前,为每个位置添加一个专门的“位置向量”。

常见做法有两类:

  1. 固定位置编码(正弦/余弦)
    论文中的做法是用不同频率的正弦、余弦函数生成位置向量,例如:

这样做的一个好处是:不同位置之间的“差值”在空间中有一定结构,且可以泛化到训练长度以外的序列。

  1. 可学习位置编码 / 旋转位置编码(RoPE)等

    • 可学习位置编码:把位置当成一种特殊的 embedding,训练时一并更新;
    • RoPE 等:通过在注意力计算中引入位置相关的旋转结构,更适合长序列。

从初学者角度,先记住一句话就够:

Transformer 自己不带顺序感,顺序信息是通过位置编码显式加进去的。


六、一个标准 Transformer Block 长什么样?

把前面的这些组件组合起来,一个标准的 Transformer 编码层大致包含:

  • 多头自注意力(Multi-Head Self-Attention)
  • 前馈网络(Feed Forward Network, FFN)
  • 残差连接(Residual Connection)
  • LayerNorm(层归一化)

简化结构:

1
2
3
4
5
6
7
8
9
10
11
输入 x

[ 多头自注意力 ]

残差连接 + LayerNorm

[ 前馈网络 FFN ]

残差连接 + LayerNorm

输出

稍微展开一下:

  1. 多头自注意力:输入序列经过 Q/K/V 投影和 attention 计算,得到新的序列表示;
  2. 残差 + LayerNorm:把 attention 输出与原输入相加,再做归一化,缓解梯度问题;
  3. FFN:位置独立的前馈网络,一般是两层全连接,中间带激活(如 GELU),维度通常放大 4 倍再压回去;
  4. 残差 + LayerNorm:再叠加一次,形成一层完整的 Block。

多层这样的 Block 堆叠,就构成了我们常说的 Transformer Encoder/Decoder 主体结构。


七、Encoder / Decoder / GPT

原始论文里的 Transformer 是为机器翻译设计的,因此有 Encoder 和 Decoder 两部分:

  • Encoder:多层 Transformer Block,输入为源语言序列,输出为一系列上下文表示;
  • Decoder:同样是多层 Block,但每一层包含:

    • 对已经生成的目标序列做 Masked Self-Attention;
    • 对 Encoder 输出和当前目标序列做 Encoder-Decoder Attention。

整体流程大致是:

1
输入序列 → [多层 Encoder] → 中间表示 → [多层 Decoder] → 输出序列

后来,在具体任务中出现了几种简化/变体:

  1. 只用 Encoder(例如 BERT)

    • 擅长“理解型”任务:分类、匹配、抽取、检索等。
  2. 只用 Decoder(例如 GPT 系列)

    • 使用 Masked Self-Attention,从左到右自回归预测下一个 token;
    • 擅长“生成型”任务:对话、续写、代码生成等。
  3. Encoder + Decoder

    • 仍然主要用于翻译、摘要这类“输入一句话 / 文档,输出一句话 / 文档”的 Seq2Seq 任务。

作为初学者,我给自己定的目标是:

先把 Self-Attention、多头、位置编码、Transformer Block 这几件事搞清楚,
然后能大概说清:

  • BERT 用的是 Encoder;
  • GPT 用的是 Decoder,自回归预测下一个 token。

做到这一点,就已经从“只听过名字”走出了好几步。


八、为什么大家都在用 Transformer?(一点点宏观视角)

从一个新手的角度回头看,Transformer 成为主流架构,大致有这几点原因:

  1. 计算模式和硬件高度匹配

    • 主体运算是矩阵乘法和点积,可以很好地利用 GPU/TPU 的并行能力;
    • 不需要严格按时间步串行,训练长序列和大模型都更高效。
  2. 表达能力强

    • 自注意力允许任意两个位置直接交互,而不是依赖链式传递;
    • 多头 + 多层堆叠,可以学习复杂的语言结构、依赖模式。
  3. 形式统一,适配多模态

    • 文本天然是 token 序列;
    • 图像可以被切成 patch,当成“视觉 token”(比如 ViT);
    • 声音、视频等也可以编码成序列,再喂给 Transformer。

从学习者视角看,最大的收益是:

理解一套结构,可以看懂一大批模型的整体框架。

小结:Transformer 神坛

最后简单收个尾。

对我这种初学者来说,现在对 Transformer 的认识大概是:

  • 它的确是这一批模型的基础架构,值得花时间;
  • 但它并不是玄学,而是一套很符合现代硬件和大规模数据场景的工程设计
  • 不需要一口气啃到各种长序列技巧、KV Cache、MoE 才算入门。

我现在给自己的要求只有这几条:

  • 知道 为什么会出现 Attention/Transformer
  • 能解释清楚 Self-Attention + 多头 + 位置编码 在做什么;
  • 能画出一个 Transformer Block 的大致结构;
  • 大概知道 BERT / GPT 和原始 Transformer 之间的关系。

做到这一步,再回头看那篇论文标题 Attention is All You Need,感觉就不再只是一个“标题党”,而是能从工程和建模的角度理解它在说什么。