[论文速通]旧文重读之Attention Is All You Need

也是突然想起了这篇老文章。

可以说是现代大模型的鼻祖级文章之一。

之前大四闲得没事的时候看过一次,但是完全不知所云。

什么 QKV,什么 Attention,完全看不懂。

看了一两天之后就放弃了。

现在回头看,连带着数学,一个小时就看得差不多了。

可以说是成功对 Transformer 祛魅。

或者说,这一年以来的工程实践和学习,让我对很多以前不知道的东西有了新的认知。

那学术小白兼工程蒟蒻就来献丑了,浅谈一下自己读 *Attention Is All You Need* 的过程与感受吧。

纯属脸滚键盘,自己读完之后留档罢了。

如果能够帮助到某些读者,那自然是极好的。

---

# 0. 写在前面

本文只讨论最原始的 Transformer,也就是论文中提到的翻译任务。

后续那些花里胡哨的东西,不在本文讨论范围之内。

首先,翻译问题。

词表翻译太呆了,但是要解决一个词在不同上下文中语义不同的问题,一直是很费劲的事情。

LSTM、RNN 等模型尝试维护一个不断更新的隐藏状态,根据前面的状态继续处理或生成下一个单元。

但随着序列变长,远距离信息需要经过很多步状态传递,长期依赖仍然很难处理。

同时,这种一步接一步的结构也天然难以并行。

一个天然的想法就是:

**改变历史信息的权重。**

当年的一种思路,就是给 RNN 加入 Attention,以区分不同信息的重要程度。

重要的信息权重大一点,不重要的信息权重小一点。

并且,还有另外一种方法:

把 RNN 换成 CNN,不就能跨区域提取特征了吗?

虽然实现方法不同,但 Attention、CNN、RNN 本质上都在试图解决一个问题:

> **跨区域整合信息。**

RNN 靠状态一步一步传递;

CNN 靠不断堆叠卷积,逐渐扩大感受野;

那能不能直接让任意位置之间交换信息?

于是,一步到位:

> **Attention Is All You Need!**

---

# 1. Attention 与 Transformer

## 1.1 什么是 Attention

先看论文里的公式:

$$
\operatorname{Attention}(Q,K,V)
=
\operatorname{softmax}
\left(
\frac{QK^T}{\sqrt{d_k}}
\right)V
$$

这就是 Attention。

很多文章都在写什么 Query、Key、Value,看完之后反而更加不明所以。

其实我觉得可以先用一句话理解:

> **Attention 就是当前 token 看整个序列时,按照重要程度,把自己需要的信息拿回来。**

从数学形式上看,它很像一种对信息的**加权期望**。

为什么这么说呢?

首先拆开来看,Q、K、V 分别是什么。

### Q:Query

Q 是查询。

它表示:

> **当前 token 想要寻找什么信息。**

### K:Key

K 是 Key。

它表示:

> **当前 token 拿出来,用于和别人的 Q 进行匹配的“索引”或者“标签”。**

### V:Value

V 是 Value。

它表示:

> **当前 token 真正能够提供出去的信息。**

于是先计算:

$$
QK^T
$$

学过矩阵乘法的都知道,两组向量做点积以后,可以得到一个矩阵。

这个矩阵表示的就是:

> **每个 Query 与其他 token 的 Key 的匹配程度。**

或者换个我自己比较习惯的说法:

**它看起来很像一个协方差矩阵,尤其是在归一化以后。**

文章中的描述其实也很直接,就是计算每个 Query 与 Key 的 compatibility,也就是匹配程度。

接下来再经过:

$$
\operatorname{softmax}
\left(
\frac{QK^T}{\sqrt{d_k}}
\right)
$$

把这些匹配程度变成 Attention Weight。

这里为什么还要除一个:

$$
\sqrt{d_k}
$$

原因也很简单。

维度比较高的时候,Q 和 K 的点积数值可能会变得很大,容易把 Softmax 推到梯度很小的区域。

所以除以 $\sqrt{d_k}$,把数值压一压。

这也是为什么论文中的 Attention 全名叫:

> **Scaled Dot-Product Attention**

得到 Attention Weight 之后,再乘上:

$$
V
$$

也就是:

> **当前 token 根据 Attention Weight,从其他位置的 V 中把信息拿回来。**

如果整个序列有 $n$ 个 token,那么 Attention 之后仍然有 $n$ 个位置。

例如单个 Attention Head 的 Value 是 $64$ 维,那么最终输出就是:

$$
n\times64
$$

也就是说:

**token 数量没有改变,但每个 token 的表示已经融合了其他 token 的信息。**

所以 Attention 干的事情其实非常朴素:

> **决定当前 token 应该去哪里拿信息,以及拿多少。**

这就是 Attention。

---

## 1.2 什么是 QKV

其实上面已经说得差不多了。

但是还是得单独说一下:

**QKV 到底是怎么计算出来的?**

首先,文字进入 Tokenizer,被转换成一个个 token ID。

例如:

```text
我 -> 123
喜欢 -> 456
苹果 -> 789
这些数字本身没有办法直接做 Attention。

所以接下来还需要经过 Embedding,把每个 token 转换成一个向量。

在原始 Transformer 中:

\[ d_{\text{model}}=512 \]

假设一句话有 $n$ 个 token,那么经过 Embedding 和位置编码之后,可以得到:

\[ X\in\mathbb{R}^{n\times512} \]

然后通过可训练的线性投影矩阵计算 Q、K、V。

对于第 $i$ 个 Attention Head:

\[ Q_i=XW_i^Q \]\[ K_i=XW_i^K \]\[ V_i=XW_i^V \]

其中原始 Transformer 使用:

\[ W_i^Q,W_i^K,W_i^V \in \mathbb{R}^{512\times64} \]

所以:

\[ n\times512 \rightarrow n\times64 \]

注意,这里的 $512\rightarrow64$:

不是把 512 维硬生生切出前 64 维。

而是用一个 $512\times64$ 的矩阵,把完整的 512 维信息重新投影到一个 64 维空间。

所以 $W_Q$、$W_K$、$W_V$ 是 Transformer 中非常重要的一组可训练参数。

模型通过反向传播逐渐学会:

应该怎样查询信息;
应该怎样匹配信息;
应该怎样传递信息。
但 Transformer 当然不只训练这些 W。

后面还有 FFN、$W_O$、Embedding、LayerNorm 等大量可训练参数。

1.3 什么是 Encoder 和 Decoder

首先还是要回到 Attention 的作用:

Attention 负责跨 token 的信息组合。

那么问题来了:

从其他 token 那里把信息拿过来以后,应该怎么处理?

作者用了一个非常简单粗暴的方法:

全连接网络,FFN。

对,就是这么简单粗暴。

Attention 已经负责把其他 token 的信息拿回来了。

而 FFN 的作用,就是对当前 token 已经融合好的信息继续进行非线性加工。

所以我觉得可以这样理解:

Attention 负责“信息从哪里来”。

FFN 负责“这些信息拿回来以后怎么算”。

原论文中的 FFN 是:

\[ \operatorname{FFN}(x) = \max(0,xW_1+b_1)W_2+b_2 \]

也就是:

\[ 512 \rightarrow 2048 \rightarrow 512 \]

中间经过一次 ReLU。

所以 FFN 并不会继续让 token 之间交流。

它是对每个 token 分别进行特征加工。

也就是:

Attention:token 与 token 之间交流

FFN:单个 token 内部的特征加工
Transformer 由:

6 层 Encoder
6 层 Decoder
组成。

Encoder 每一层主要包括:

Multi-Head Self-Attention
Add & Norm
FFN
Add & Norm
这里还有残差连接和 LayerNorm,不过不是本文重点,就不展开了。

Decoder 稍微复杂一点。

除了自己的 Masked Self-Attention 和 FFN 之外,还多了一层:

Encoder-Decoder Attention

用来读取 Encoder 的输出。

同时 Decoder 的 Self-Attention 需要加 Mask。

原因也很简单:

生成当前 token 的时候,不能偷看后面的答案。

所以 Encoder 和 Decoder 结构并不完全一样。

但整个 Transformer Layer 干的事情,在我看来其实非常直观:

不断进行跨 token 的信息交换,再对每个 token 内部的信息进行非线性加工。

一层不够?

那就再来一层。

再来一层。

最后让这些表示逐渐变成某种人类很难直接解释的高维特征。

这个感觉其实和 CNN 等深度网络也有一点异曲同工之妙。

1.4 多头注意力

如果只有一个 Attention Head,那么所有的信息关系都得挤在同一个 Attention 空间里面。

确实很专注。

但是也容易丢失 Attention 的多样性。

所以论文提出了:

Multi-Head Attention

原始 Transformer 使用了:

\[ h=8 \]

也就是 8 个 Attention Head。

这里一开始非常容易产生一个误解:

是不是把原来的 512 维向量切成:

1~64 -> head 1
65~128 -> head 2
...
其实完全不是。

每一个 Head 都会看到完整的 512 维输入。

只是每个 Head 有自己独立的一套:

\[ W_i^Q,\quad W_i^K,\quad W_i^V \]

把同一个 512 维输入分别投影到不同的 64 维空间:

\[ 512\rightarrow64 \]

所以本质上可以理解为:

在 8 个不同的表示空间里面分别做 Attention。

每个 Head:

\[ \operatorname{head}_i = \operatorname{Attention} \left( QW_i^Q, KW_i^K, VW_i^V \right) \]

最终得到一个 64 维输出。

然后把 8 个 Head 拼起来:

\[ \operatorname{Concat} ( \operatorname{head}_1, \ldots, \operatorname{head}_8 ) \]

于是:

\[ 8\times64=512 \]

整个过程大概就是:

\[ 512 \rightarrow 64 \rightarrow 64\times8 \rightarrow 512 \]

拼接以后还会再经过一个输出矩阵:

\[ W^O \]

完整公式就是:

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

这样,不同 Attention Head 就有机会学习不同的信息关系。

可能某个 Head 更关注局部关系;

某个 Head 更关注远距离关系;

某个 Head 又学到了其他东西。

当然,模型并没有规定:

“你负责语法,你负责指代,你负责位置。”

它们只是拥有不同的参数和不同的表示空间。

至于最后会不会分工、怎么分工,全靠训练自己学。

所以多头注意力在我看来,本质上就是:

用多个不同的视角,同时观察同一个序列。

1.5 位置编码

Attention 确实可以让任意两个 token 之间直接交换信息。

但是它却有一个硬伤:

它自己不知道顺序。

“我吃苹果”和“苹果吃我”,如果只有 token 本身,而没有位置信息,那么 Attention 并没有天然的时间顺序可以依赖。

RNN 的顺序是写死在网络结构里面的:

1 -> 2 -> 3 -> 4
Transformer 把这个结构扔掉以后,就必须通过另外一种方式告诉模型位置。

所以 Transformer 在 Embedding 上额外加入了:

Positional Encoding

也就是告诉模型:

你不仅要知道“你是谁”,还要知道“你在第几个位置”。

原论文使用的是正弦和余弦位置编码:

\[ PE_{(pos,2i)} = \sin \left( \frac{pos}{10000^{2i/d_{\text{model}}}} \right) \]\[ PE_{(pos,2i+1)} = \cos \left( \frac{pos}{10000^{2i/d_{\text{model}}}} \right) \]

最后直接加在 Embedding 上:

\[ X = X_{\text{embedding}} + X_{\text{position}} \]

于是 Transformer 虽然扔掉了 RNN 的递归结构,但没有扔掉“顺序”本身。

只是把顺序:

从网络结构里面拿了出来,显式编码进输入。

1.6 如何训练

曾经,我以为 Attention 是某种神奇的东西。

真的会像莫队或者 LCA 一样,在数据里面跳来跳去。

但是并非如此。

拆开以后会发现:

Transformer 依旧脱离不开:

矩阵乘法;
全连接层;
Softmax;
激活函数;
残差连接;
LayerNorm。
那就很好理解了。

掏出我们的:

反向传播大法。

Transformer 中需要学习的东西其实很多。

比如:

Embedding;
$W_Q$;
$W_K$;
$W_V$;
Multi-Head 后面的 $W_O$;
FFN 中的 $W_1$、$W_2$;
LayerNorm 中的参数;
最后的输出层。
这些东西说到底全部都是参数。

模型完成一次翻译,计算 Loss,然后反向传播。

梯度一路从输出往前传:

Loss
输出层
Decoder
FFN / Attention
WQ / WK / WV / WO
Embedding
然后更新这些参数。

再来一遍。

再来一遍。

重复很多很多遍。

于是最后,这些看起来完全没有人工规定语义的矩阵,居然真的学会了:

什么信息应该被什么 token 查询、匹配和利用。

所以 Transformer 虽然看起来很神秘,但真正拆到底以后:

依旧是矩阵,依旧是神经网络,依旧是反向传播。

2. 一些碎碎念

经过这一年以来的积累。

或者说强行积累吧。

也是对很多概念有了更加直观的认识。

所以现在回看 Transformer,会觉得非常亲切。

很多以前零散的东西也终于串起来了。

什么:

KV Cache;
上下文窗口;
稀疏注意力;
多头注意力;
Embedding;
Position Encoding。
以前看到这些名词,感觉都是一个个独立的黑盒。

现在再回头看,会发现很多东西其实都能从最原始的 Transformer 一路顺下来。

想当年大四想啃强化学习,部署了一下午环境没部署好。

然后跑去看理论。

看了半天也没明白到底在干什么。

现在回头看,好像也就是云淡风轻了。

当然,能看懂一篇经典论文,也不代表真正懂了多少东西。

求学之路还很长。

同志仍需努力啊。
```
posted @ 2026-08-11 10:31  阿基米德的澡盆  阅读(8)  评论(0)    收藏  举报