深度学习入门站 · 理解深度学习
首页 › 第 12 章

Transformers

注意力机制是什么?为什么它统治了 NLP 和大模型时代。
图 12-1:Transformer 自注意力:每个词关注所有词
图 12-1:Transformer 自注意力:每个词关注所有词

这一章讲的是 Transformer——如今几乎所有大语言模型(GPT、BERT 都是它的直系后代)的底层架构。它的核心思想只有一个:注意力机制。处理句子里的每个词时,模型不是只盯着眼前,而是"回头看"整句话,找出哪些词跟当前词关系最密切。学完这一章,你会明白为什么循环网络读长文吃力、注意力公式 $\text{softmax}(QK^\top/\sqrt{d_k})V$ 到底在算什么,以及为什么 Transformer 靠"并行"统治了大模型时代。

循环网络为什么"读"长文吃力?

在 Transformer 之前,处理语言的主力是循环神经网络(RNN)。它的工作方式像一个人逐字朗读:读第一个词,把理解记进一个"小本子"(隐藏状态);读第二个词时,把小本子上的旧内容和新词一起处理,再更新小本子……一路接力下去。用公式说,每一步都是:

$$h_t = g(h_{t-1}, x_t)$$

意思是:第 $t$ 步的新记忆 $h_t$,由旧记忆 $h_{t-1}$ 和当前词 $x_t$ 共同决定。旧记忆是"转述"来的,转述多了,细节就丢了。

这种"逐字接力"有三个硬伤:第一,难并行——第 10 个词必须等前 9 个词算完才能开始,像流水线只能一件一件过,GPU 完全使不上劲;第二,会"忘事"——信息要一路传几十上百步,"三年前欠我钱"这种话读到"钱"时,"三年前"早就被冲淡了;第三,远距离依赖难——句子里"它"指代的是二十个词之前的"餐馆",逐字接力很难搭起这么长的联系。

注意力:处理每个词时"回头看"

注意力的想法朴素得多:处理某个词时,与其靠"接力传下来的二手记忆",不如直接回头看整句话,问一句:"这些词里,谁跟我关系最铁?"关系近的多参考,关系远的少参考。比如处理"它"时,回头看,"餐馆"和"三明治"都可能是它指代的对象,模型就根据上下文给它们分配不同的"关注度"。

这种"关注度"就是注意力权重(attention weight):一组非负、加起来恰好等于 1 的数。处理每个词时,把整句话所有词的内容按权重加权平均,就得到这个词的新表示。妙处在于:每个词都能直接"看到"所有词,不管隔着多远——远距离依赖问题当场解决。这就像开会:每个人发言时都扫一眼全场的反应,而不是只听见隔壁邻居说的话。

查询 Q、键 K、值 V:注意力公式拆解

权重怎么算?这里引入三个角色:查询(Query)、键(Key)、值(Value),它们都借自图书馆检索的术语。对每个词,模型用学出来的变换算出三个"身份":查询 Q 代表"我现在想找什么";键 K 代表"我能提供什么"(每个词贴的标签);值 V 代表"我实际的内容是什么"。

📚
生活类比
自注意力就像在图书馆查资料:你带着一个问题(查询 Query),扫过一排排书架上的书名(键 Key),书名和你的问题越对得上,这本书越值得读;最后你从最相关的书里摘抄内容(值 Value)。而且翻每一本书时,其他所有书都还在你的视野里——不会有哪本被"遗忘"。

注意力打分分三步:先拿当前词(第 $n$ 个)的查询 $q_n$,去跟每个词(第 $m$ 个)的键 $k_m$ 做点积——点积就是两个向量对应位置相乘再相加,结果越大说明越"对得上";再除以 $\sqrt{d_k}$ 防止分数过大;最后用 softmax 把分数变成一组和为 1 的权重:

$$\alpha_{n,m} = \text{softmax}_m\!\left(\frac{k_m^{\top} q_n}{\sqrt{d_k}}\right)$$

这个式子意思是:对第 $n$ 个词来说,权重 $\alpha_{n,m}$ 就是它"回头看"第 $m$ 个词时的关注度——所有词的权重加起来等于 1,最相关的词拿大头。最后用这些权重去加权混合所有词的值 $v_m$,就得到第 $n$ 个词的新表示。

把整句话的所有词排成矩阵,三步可以一口气写成:

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

这看起来吓人,其实只是刚才三步的"打包":$QK^\top$ 一次算出所有词两两之间的相似度,softmax 对每一行(每个查询)做归一化,再乘上 $V$ 加权求和。之所以要除以 $\sqrt{d_k}$,是因为维度高时点积容易很大,会把 softmax 推到"一边倒"的极端区,梯度变得极小,模型就学不动了。这一行"打包"正是 Transformer 能并行的关键——整句话一起算,而不是逐字接力。

💡
**核心思想**:注意力 = "按相关程度加权平均"。Q 提出需求,K 表明身份,点积衡量"配不配",softmax 把分数变成权重,最后按权重混合 V。每个词都能直接看到所有词,所以长距离依赖不再可怕。

用 NumPy 写一个简化版,亲手看看注意力打分长什么样(真实模型里 Q、K、V 是学出来的,这里先用输入自己充当):

import numpy as np

# 一句话 4 个词,每个词用一个 3 维向量表示(模拟词嵌入)
X = np.array([[1.0, 0.0, 0.5],   # 词 1:"我"
              [0.0, 1.0, 0.2],   # 词 2:"爱"
              [0.5, 0.0, 1.0],   # 词 3:"深度学习"
              [0.0, 0.8, 0.3]])  # 词 4:"!"
d = X.shape[1]                   # 向量维度 d = 3

# 简化演示:直接用输入充当 Q、K、V(真实模型中是学出来的线性变换)
Q = K = V = X

# 第一步:打分。Q 与所有 K 做点积,衡量每对词的相似度
scores = Q @ K.T
# 第二步:除以 √d 防数值过大,再用 softmax 变成和为 1 的权重
weights = np.exp(scores / np.sqrt(d))
weights /= weights.sum(axis=1, keepdims=True)

# 第三步:按权重加权混合 V,得到每个词的新表示
out = weights @ V
print(np.round(weights, 2))      # 看看每个词分别"关注"了谁

跑完你会发现:每个词的新表示都吸收了"整句话"的信息,权重矩阵的每一行就是它"回头看"的分配方案——这就是自注意力的全部秘密。

🧠
真实模型里的 Q、K、V 并不是输入本身,而是输入经过三套学出来的线性变换得到的。上面代码用 X 直接充当,只是为了让你看清"打分 → 归一化 → 加权混合"这三步。

多头注意力与位置编码

多头注意力(Multi-Head Attention)就是同时开 $H$ 个注意力"小组",每组用自己的一套 Q/K/V 变换,从不同角度看句子:一个头盯着语法关系,一个头盯着指代关系,一个头盯着情感色彩。最后把各组结果拼起来,再做一次线性变换合并。就像开会请了几位不同领域的专家,各抒己见后再汇总成一份综合意见。多头机制被认为是注意力效果好用的关键——它让模型对"坏初始值"更稳。

但还有个致命问题:自注意力对顺序不敏感——把句子里的词打乱顺序,计算结果一模一样。可"女人吃了浣熊"和"浣熊吃了女人"意思完全相反!解决办法是给每个位置配上位置编码(positional encoding),直接加到词向量上:

$$X' = X + \Pi$$

意思是:词的内容 $X$ 加上位置标记 $\Pi$,模型就分得清"第 1 个词"和"第 2 个词"了。位置编码可以是预先算好的正弦波,也可以是训练中学出来的。

Transformer 结构:编码器、解码器与并行化的胜利

把零件组装起来:多头自注意力让词与词互相"对话",接着是一个逐词处理的全连接网络;每一块外面都套上残差连接(把输出加到输入上,防止梯度消失)和层归一化。这样一个 Transformer 层叠上几十上百层,就是大模型的骨架。按用途分有三种形态:编码器(Encoder)把整句话读一遍,输出每个词的理解——BERT 是代表,预训练时挖掉句子里的词让模型猜,从而学会语言规律;解码器(Decoder)只能看自己前面的词(遮掩自注意力,防止偷看答案),一步预测一个词——GPT 是代表,本质是"根据前面的话猜下一句";编码器-解码器先读源语言再生成目标语言,用于机器翻译。

为什么 Transformer 成了大模型时代的基石?答案就两个字:并行。RNN 必须逐字处理,Transformer 却一次性把整句话读进来,所有词两两之间的关系用矩阵乘法同时算完——而 GPU 最擅长的恰恰是大规模矩阵运算。于是模型可以堆到几千亿参数、喂进数千亿词的数据,规模效应让能力一路暴涨。代价是计算量随句子长度平方增长,但那是"幸福的烦恼"。

🎯 小测验

1. 循环网络(RNN)处理长文本时,为什么容易"忘事"?
2. 自注意力公式 $\text{softmax}(QK^\top/\sqrt{d_k})V$ 中,$QK^\top$ 衡量的是什么?
3. 为什么 Transformer 需要位置编码?