Transformer 讲解

自注意力改的是序列表示与可并行训练。后来的 LLM 骨架从此处来,Agent 的决策核心与动作接口都长在这副计算图上。

论文解决了什么问题

2017 年的对象是序列转换,主要战场是机器翻译。编码器—解码器与注意力已经是常规附件,主干仍是 RNN(或卷积)。三条障碍绑在一起:样本内的顺序计算无法并行;任意两个位置之间的路径随长度线性增长,长程依赖难以学习;注意力仍接在循环网络上,不是转换模型的默认计算。

解法是更换计算图:缩放点积自注意力让每个位置一步看到全序列(路径 (O(1)),层内顺序操作 (O(1)));多头注意力避免单次平均抹掉子空间;位置编码补回被移除的词序归纳偏置;解码器自注意力加掩码以保持自回归。翻译分数是结果。被改写的是「一层如何表示一段序列」这一层机制。

论文没有把自身写成语言模型骨架,也没有工具、循环或停机。结论中指出的下一步是其他模态、局部注意力,以及让生成少一点顺序化。

关键术语:编码器与解码器

论文里的编码器与解码器,与今天 LLM 里被叫做「编码器」「解码器」的东西同名同源,但不是同一件事。区分有两条判据:有没有交叉注意力,注意力带不带因果掩码。

论文里两个组件的差别只在一层:

编码器 解码器
每层子层数 2 3
子层 自注意力、前馈 因果自注意力、交叉注意力、前馈
能看哪儿 全序列,双向 自己只看之前的位置,交叉注意力看编码器全部输出
生成 不生成 自回归,一次一个 token

关键是第三个子层。交叉注意力读的是编码器的输出,解码器每一步都回看源序列的表示——这才是「解码」二字的由来:把已经读进来的表示,逐个符号地解出来。

今天被叫做「编码器」「解码器」的有三样,用法并不相同。

编码器栈(BERT 一类):双向自注意力加前馈,两个子层,没有因果掩码,也不生成。它把整段文本读成一个表示。

解码器栈(GPT 一类):因果自注意力加前馈,也是两个子层,与 BERT 的层同为两层,区别只在掩码;交叉注意力被去掉了,因为没有编码器可供交叉注意。所以「GPT 只用解码器栈」是准确的,但不能读成「留了解码器、藏了编码器」——去掉第三个子层之后,解码器退化为带因果掩码的自注意力加前馈,名字留了下来,机制回到同一条流上。

多模态编码器(图像、语音):把别的模态投到 LLM 能读的输入空间里。它与论文里那个读源句子的编码器不是一回事,只是沿用了「先编码成表示」的思路。

另有一个同名而无关的用法:tokenizer 的 encode / decode,把字符串转成 token id 再转回来,与模型结构无关。

对后面的影响落在一处:决策核心是解码器栈,没有编码器,就没有一份「源序列表示」可以被反复交叉注意。上下文里的所有东西都是同一条流上的 token,当前观察、工具回执与历史对话彼此没有结构上的区分,只有位置与文字的差别。

对后续 LLM 的影响

第 4 节的复杂度表给出了后来一切的前提:层内可并行,任意两个 token 之间只有一条短路径。 循环网络每层要按位置串行,卷积要靠堆层数接通远处的位置,两条都挡住了「同时加深、加宽、加数据」。自注意力把这两条约束一起拿掉,剩下的事情交给规模。

论文给的是完整的编码器—解码器,后来的主流却收敛到只用解码器栈。这是工程合力的结果,不是论文的结论,至少四条原因叠在一起。下一个 token 预测不需要标注,互联网上任何文本都是训练数据,而编码器—解码器要为每个任务设计输入与输出的配对形式;任务本身被统一成格式问题,「把下面这段译成英文」写在提示里即可,不必为翻译单独留一个编码器;解码器栈每层只有两个子层,省掉了第二套栈与交叉注意力的显存和算力;KV cache 可以复用,生成时每一步只新增一个 token 的代价,多轮对话与 Agent 循环都吃这一条。

把这次转向读成架构上的必然,我认为会漏掉另一半事实。理解类任务(SuperGLUE 一类)上,编码器栈与编码器—解码器仍然占优;指令微调之后,编码器—解码器可以用明显更省的推理达到相近的少样本表现;嵌入与检索这一支至今主要用编码器栈。这次转向本身也缺少同算力下的严格对照,有研究把两类模型放到同一算力最优前沿上比较后指出,编码器—解码器的潜力可能被低估。真正的推动力更像是两件事撞在一起:生成类任务在 2019 年之后变得重要,而解码器栈最容易扩规模。

位置编码成为一条独立的研究线。论文第 3.5 节选正弦编码,理由是它可能外推到训练时未见的长度;后来的相对位置、RoPE、ALiBi 都在回答同一个问题,「第几步、哪一段」这个信息如何在不引入循环的前提下表达得更好。这条线一直通到长上下文模型。

表 1 里那行 (O(n^{2}\cdot d)) 也没有消失,只是被绕着走。FlashAttention 改的是显存读写顺序,不是复杂度;PagedAttention 改的是 KV cache 的碎片;滑窗与线性注意力用近似换更长的上下文;MoE 在规模一侧把参数量与算力解耦。这些手段搬动了常数与曲线,没有改变二次方这一项。

GPT-3 的上下文学习与 Codex 的代码生成,用的都是这副骨架上训练出的解码器语言模型。它们不是这篇论文的实验内容,但都预设了这篇论文改过的计算图。

对 AI Agent 的影响

AI Agent 需要的决策核心,要能读一段开放文本并生成下一步。Transformer 提供的是表示与自回归生成结构,不是策略循环;一次前向计算,是在已有 token 上预测后续 token。这个结构留下三件对 Agent 直接起作用的事实。

上下文就是工作集,KV cache 是它的物理载体。「当前观察」在实现上不是一份被解析出来的状态,而是窗口里的一段 token,以及为它们算好的注意力键值。会话继续,cache 就继续追加;换一条会话,整段前缀要重新计算。窗口大小因此不是界面上的一个参数,而是这个循环一次能看见多少环境回执的物理上限。

动作只能是 token。 模型唯一的输出面是下一个 token 的概率分布,它没有别的通道。要用工具、要调 API、要改文件,都必须先把动作序列化成它能生成的东西:早期是约定格式的文本,2023 年 6 月之后是可校验的 JSON 调用,也有把工具做成特殊 token、或把动作写进代码块的做法。工具调用长成今天这个形状,原因在这里——不是接口设计选中了文本,而是输出面只有文本。

成本结构决定了 Agent 的工程形状。 prefill 阶段的注意力成本随长度平方增长,decode 阶段受显存带宽限制,而多轮循环会反复重新计算同一段前缀。这就是为什么前缀缓存、KV 复用与上下文压缩在 Agent 系统里是基础设施而不是优化项:一个跑二十轮的循环,开销的主要部分往往不在生成新内容,而在反复读同一段历史。

论文里的机制 后来在 Agent 里对应的物理事实
自注意力一步连接全序列 当前观察可以整段进入上下文
掩码自注意力、自回归 下一步以文本(或后来的工具调用)逐 token 生成,动作只能序列化进这个通道
(O(n^{2})) 与有限窗口 一次循环能够容纳的回执有上限;超出后只能截断、检索或外挂记忆
KV cache 随会话增长 状态就是这段前缀;多轮循环反复重算同一段历史,前缀复用因此成为基础设施
位置编码 「第几步、哪一段」对模型而言不是免费的
训练可并行、模型可做大 核心的能力随规模上升;2022 年 CoT「规模足够大才有效」,前提正是这种结构

时间线把它标成底层能力里的范式更替:没有可扩展的条件生成器,后面就没有可讨论的 LLM 核心。

扩展阅读