注意力
一个词怎么知道该看句子里的哪个词?
2017 年,一篇翻译论文的标题写着“注意力就是你所需要的一切”[1]。从那以后,几乎所有大模型都建在这种结构上。
从词的坐标到注意力
短短四年里,处理语言的方式换了两次底座。
- 2013
word2vec:词变成向量
Mikolov 等,Google
- 解决了什么
- 过去的系统把词当成互不相关的编号,“猫”和“狗”之间没有任何联系。
- 带来了什么变化
- 用几百维的向量表示词,用法相近的词距离也近,还能做“国王 − 男人 + 女人 ≈ 女王”这样的类比[2]。
- 2014
序列到序列:读完再写
Sutskever 等,Google
- 解决了什么
- 翻译的输入和输出长度不同,很难用固定的结构处理。
- 带来了什么变化
- 编码器读完整句话并压成一个向量,解码器再逐词写出译文[3]。但长句子的信息很难全部塞进一个向量。
- 2014
注意力机制:回头看原句
Bahdanau、Cho、Bengio
- 解决了什么
- 长句翻译时,那个固定长度的向量成了瓶颈。
- 带来了什么变化
- 解码每个词时,回头查看原句的每个位置,按相关程度加权取用信息[4]。
- 2017
Transformer:只用注意力
Vaswani 等,Google
- 解决了什么
- 循环网络必须按顺序逐词计算,难以并行,也难以捕捉相隔很远的两个词之间的关系。
- 带来了什么变化
- 完全用注意力处理整句话,所有位置同时计算。训练更快、规模能做得更大,成了此后几乎所有大模型的基础结构[1]。
Token:模型读的是编号 Token · 词元
1一句话
模型不直接读文字。文字先被切成一个个片段,每个片段换成词表里的一个编号,这些片段就叫 Token。
2打个比方
像活字排版:常用的字和词各有一枚现成的字模,直接取用;字盘里没有的生僻字,就只能用更小的部件拼出来。
所以 Token 不等于“字”,也不等于“词”。一个常用词可能只占一枚,一个生僻字可能要三枚。
3动手试
规则只有一条:从左到右,每次取词表里能匹配上的最长片段。词表里没有的生僻字会被拆成 UTF-8 字节(灰色),一个字要占三个 Token。
4怎么做到的
真实的词表不是手写的,而是用算法从大量文本里统计出来。常见做法是字节对编码(BPE):从单个字符或字节出发,反复把最常一起出现的一对合并成新片段,直到词表达到预定大小[5]。GPT-2 在字节上做 BPE,词表共有 50,257 个 Token[6]。
在字节上做的好处是永远不会遇到“不认识的字”:任何文字最后都能退回到字节。代价是训练语料里少见的语言和字,会被切得更碎、占用更多 Token。
做不到什么
- 模型拿到的是 Token 编号,而不是字母或笔画,所以“这个单词里有几个 r”这类问题容易出错。
- 同一句话,不同语言消耗的 Token 数可能差好几倍,能放进窗口的内容和按 Token 计的费用也随之不同。
- 数字常被切成不规则的片段,这是早期模型做算术容易出错的原因之一。
Embedding:编号变成坐标 Embedding · 嵌入向量
1一句话
每个 Token 编号都对应一长串数字(向量),可以看成它在高维空间里的坐标;用法相近的词,坐标也相近。
2打个比方
像在一张地图上给每个词钉一枚图钉:“猫”和“狗”钉得很近,“猫”和“桌子”离得远。方向也有含义:从“男人”走到“女人”的那段路,和从“国王”走到“女王”的那段路几乎平行。
3动手试
点一个词,找它的邻居
或者做一道向量算术
选一个词,或点一道算式。
4怎么做到的
模型里有一张大表,每一行是一个 Token 的向量。表里的数字一开始是随机的,在训练中不断调整,最后用法相似的词会被推到相近的位置。2013 年的 word2vec 让这种表示流行起来,也展示了“国王 − 男人 + 女人 ≈ 女王”这样的向量类比[2]。
真实的维度很高:GPT-3 最大的模型里,每个 Token 的向量有 12,288 个数[7]。上面的二维地图只是示意。
在 Transformer 里,这张表只给出每个 Token 的起点。经过一层层注意力之后,同一个“苹果”在“吃苹果”和“苹果手机”里会变成不同的向量,这叫上下文相关的表示。
做不到什么
- 单个维度通常说不出明确含义,“这个数代表性别”之类的解读只是粗略的近似。
- 向量会把训练语料里的偏见一起学进去,比如职业和性别的刻板关联。
- 向量相近只说明用法相近,不说明可以互换:“北京”和“上海”离得很近,但答案里不能把一个换成另一个。
注意力:每个词都向整句话提问 Self-Attention · 自注意力
1一句话
注意力让句子里的每个词都去和其他所有词比较“谁和我相关”,再按相关程度,把其他词的信息按比例混进自己的表示里。
2打个比方
像开会时准备发言:你会回想在座每个人刚才说过的话,和你要说的事关系越大,就越多地参考那个人的说法。“它”要确定自己指谁,就会重点参考“小猫”和“桌子”,再看句尾是“累”还是“高”。
这个比方只说明“按相关程度加权参考”。模型里并没有谁在“理解”谁,只有一组组数字的乘法和加法。
3动手试
行:提问的词(Query) 列:被看的词(Key)
-
① 打分:「它」和每个词有多相关
-
② 归一化(softmax):变成加起来等于 100% 的权重
-
③ 加权汇总:按权重把各个词的“值”混进来
4怎么做到的
每个词的向量会被三组不同的权重分别变换,得到三个新向量:查询 Q(我在找什么)、键 K(我能被怎样找到)、值 V(我实际提供的内容)。一个词的 Q 和所有词的 K 逐一做点积,得到相关度打分;打分除以 √d(d 是向量维度)后经过 softmax 变成权重;最后用这些权重把所有词的 V 加起来,就是这个词新的表示[1]。
模型会并行地做很多组这样的计算,叫多头注意力。有的头偏向相邻的词,有的头偏向指代关系,分工是在训练中自己形成的;演示里的“指代头”和“邻近头”是为了讲解而手工设定的。
生成文字的模型(如 GPT 系列)使用因果遮罩:每个词只能看它前面的词,因为生成时后面的词还不存在。打开演示里的“只看前文”,就能看到「它」此时还无法判断指的是谁,这个判断要留给后面的词。
做不到什么
- 每个词都要和所有词打分,计算量随长度的平方增长:文本长度翻倍,注意力的计算量约变成四倍。
- 注意力权重高,不等于模型“因为这个词”才得出结论。用注意力图解释模型行为需要谨慎。
- 注意力本身不区分词的先后顺序,需要额外加入位置信息,例如原论文的正弦位置编码,或后来广泛使用的旋转位置编码 RoPE[8]。
上下文窗口:一次能看多长 Context Window
1一句话
上下文窗口是模型一次计算能放进来的 Token 数上限。超出的部分不会参与计算,就像从来没有出现过。
2打个比方
像排字盘的尺寸:盘子就这么大,字排满了,再往后排就得把最前面的字拿掉。对话太长时,最早说过的话会被挤出窗口。
3动手试
小明养了一只猫,名字叫年糕。它每天早上六点叫小明起床,吃完饭就趴在窗台上晒太阳。周末小明带它去公园,它一直躲在包里。问:小明的猫叫什么?
4怎么做到的
窗口大小由模型的结构和训练方式决定。最早的 GPT 窗口是 512 个 Token[9],GPT-2 扩大到 1,024[6],GPT-3 是 2,048[7]。后来,更省显存的注意力实现(如 FlashAttention[10])和新的位置编码方法,让窗口逐步扩大到几十万乃至上百万 Token,最新情况见第 09 章。
聊天软件里的“记忆”,多数并不是模型本身记住了什么,而是软件把之前的对话重新放进窗口;放不下时,就要截断、做摘要,或者到外部资料里检索(第 08 章)。
做不到什么
- 窗口变大不等于每一处都用得好:关键信息埋在很长的上下文中间时,模型可能用不上它。
- 窗口越长,计算量和费用越高。
- 窗口里没有的信息,模型只能依据训练中学到的规律去补全,这正是“幻觉”的来源之一。
层层叠印:Transformer 的整体 Transformer
1一句话
Transformer 把“注意力 + 一个小型前馈网络”作为一层,叠几十到上百层;每过一层,每个词的表示都结合上下文被改写一次。
2打个比方
像多色印刷:同一张纸要过好几块印版,每过一次就多叠一层颜色,最后的画面是所有印版共同作用的结果。每一层也不会擦掉前面的结果,而是在原来的基础上叠加修改,这叫残差连接。
3动手试
循环网络(RNN)0 步
Transformer0 步
4怎么做到的
2017 年的原始 Transformer 用于翻译,分为编码器和解码器两部分,各 6 层;基础版本的向量维度是 512,注意力头有 8 个[1]。它最重要的改变是可以并行:之前的循环网络(包括 LSTM[11])必须一个词接一个词地算,Transformer 让一整句话的所有位置同时计算,能充分利用 GPU。论文报告,大号模型在 8 块 P100 显卡上训练 3.5 天,就刷新了当时英德、英法翻译的最好成绩。
后来的 GPT 系列只保留解码器,BERT 只保留编码器[12]。今天的大语言模型绝大多数是“只有解码器”的结构。
做不到什么
- 结构本身没有长期记忆:每次计算只依赖窗口里的内容和训练好的参数。
- 层数和宽度越大,能力通常越强,但训练和运行成本也急剧上升(见第 04 章)。
- 层层叠加的计算很难逐步解释,“模型内部到底在算什么”仍是可解释性研究的难题。
这一章留下的问题
- 01
注意力的计算量随长度平方增长。能不能用更省的方式处理很长的文本,又不损失效果?
- 02
注意力权重只能部分揭示模型参考了哪些词,不足以完整解释它为什么这样输出。
- 03
Transformer 只是一种结构。真正让它变成“大模型”的,是之后在海量文本上做的预训练,这是下一章的内容。
本章参考文献
- [1] Ashish Vaswani et al.. Attention Is All You Need. NIPS 2017 (arXiv:1706.03762).提出完全基于注意力、不使用循环和卷积的Transformer架构,训练可高度并行,后来成为几乎所有大语言模型的基础结构。
- [2] Tomas Mikolov, Kai Chen, Greg Corrado, Jeffrey Dean. Efficient Estimation of Word Representations in Vector Space. ICLR 2013 Workshop (arXiv:1301.3781).提出CBOW和Skip-gram两种简单高效的模型(即word2vec),可在大规模语料上快速学习词向量,词向量之间的线性关系能反映部分语义和句法关系。
- [3] Ilya Sutskever, Oriol Vinyals, Quoc V. Le. Sequence to Sequence Learning with Neural Networks. NIPS 2014 (arXiv:1409.3215).用一个LSTM把输入序列编码成固定长度向量、再用另一个LSTM解码生成输出序列,在英法机器翻译上取得有竞争力的结果,确立了“编码器-解码器”范式。
- [4] Dzmitry Bahdanau, Kyunghyun Cho, Yoshua Bengio. Neural Machine Translation by Jointly Learning to Align and Translate. ICLR 2015 (arXiv:1409.0473).在编码器-解码器翻译模型中引入注意力机制,让解码器每生成一个词都能有选择地关注源句的不同位置,缓解了用固定长度向量表示长句的瓶颈。
- [5] Rico Sennrich, Barry Haddow, Alexandra Birch. Neural Machine Translation of Rare Words with Subword Units. ACL 2016, pp. 1715–1725 (arXiv:1508.07909).把字节对编码(BPE)压缩算法改造成子词切分方法,使神经机器翻译能用有限的词表处理罕见词和未登录词;BPE及其变体后来成为大语言模型分词器的常见做法。
- [6] Alec Radford, Jeffrey Wu, Rewon Child, David Luan, Dario Amodei, Ilya Sutskever. Language Models are Unsupervised Multitask Learners. OpenAI (technical report; announced in the blog post “Better language models and their implications”).在约800万个网页(WebText)上训练了最大15亿参数的GPT-2,显示语言模型无需针对任务训练也能零样本完成部分任务;OpenAI以担心被滥用为由分阶段公开了模型权重。
- [7] Tom B. Brown et al.. Language Models are Few-Shot Learners. NeurIPS 2020 (arXiv:2005.14165).训练了1750亿参数的GPT-3,展示只需在提示中给出少量示例(上下文学习,不更新参数)就能完成许多任务。
- [8] Jianlin Su et al.. RoFormer: Enhanced Transformer with Rotary Position Embedding. arXiv:2104.09864; later published in Neurocomputing, 568: 127063 (2024).提出旋转位置编码(RoPE),通过旋转查询和键向量把相对位置信息融入注意力计算,后被LLaMA等许多大语言模型采用。
- [9] Alec Radford, Karthik Narasimhan, Tim Salimans, Ilya Sutskever. Improving Language Understanding by Generative Pre-Training. OpenAI (technical report; announced in the blog post “Improving language understanding with unsupervised learning”).先在大量无标注文本上对Transformer解码器做生成式预训练,再针对具体任务做有监督微调,在多项自然语言理解任务上取得当时最好成绩,即后来所称的GPT-1。
- [10] Tri Dao et al.. FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness. NeurIPS 2022 (arXiv:2205.14135).通过分块计算减少GPU显存与片上SRAM之间的数据读写,在不做近似的前提下加快注意力计算并显著降低显存占用,使更长上下文的训练更加可行。
- [11] Sepp Hochreiter, Jürgen Schmidhuber. Long Short-Term Memory. Neural Computation, 9(8): 1735–1780 (Nov 1997).提出带门控记忆单元的循环神经网络结构LSTM,缓解了普通RNN因梯度消失而难以学习长距离依赖的问题。
- [12] Jacob Devlin, Ming-Wei Chang, Kenton Lee, Kristina Toutanova. BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding. NAACL-HLT 2019, pp. 4171–4186 (arXiv:1810.04805).用掩码语言模型等目标预训练双向Transformer编码器,再微调到下游任务,在11项NLP任务上刷新纪录,推动了“预训练+微调”范式的普及。
全部文献、素材与许可见 来源与许可。