Transformer:现代AI革命背后的核心模型

上一篇文章From Text to Large Language Models讲了如何用RNN、LSTM、GRU等模型来处理文本数据,但它们都存在一些问题。

  • 无法并行训练
  • 长距离依赖问题

探索 attention 和 self-attention

为了讲清楚上面的问题,用机器翻译这个例子来说明。因为机器翻译非常适合暴露旧模型的问题:

  • 输入和输出都是序列
  • 输入句子和输出句子长度可能不一样
  • 一个词的翻译,往往依赖很远处的词
  • 语法、代词、上下文一致性都很重要

比如英文翻法语时,一个词该怎么翻,可能要看句子前面很久以前出现的主语、时态、否定词。

seq2seq

当时研究人员尝试将现有的RNN等模型应用于机器翻译。其中有个叫seq2seq的系统,它把输入和输出都作为序列,然后通过一个编码器(encoder)和译码器(decoder)来处理。

它的思路是:

  • encoder 读入原句
  • 把整句压缩成一个表示
  • decoder 再根据这个表示,一步一步生成翻译后的句子

你可以把它理解成:

  • 编码器先"读懂原文"
  • 解码器再"复述成另一种语言"

这个想法本身很好,但很快遇到问题。下面是4个 seq2seq 的核心问题:

1. Alignment(对齐) 问题

输入词和输出词不是一一对应的。

比如一句英文,翻成法语后:

  • 词序可能变了
  • 一个词可能翻成多个词
  • 有些词在另一种语言里要补出来
  • 有些词要合并表达

所以不能简单假设:第 3 个输入词对应第 3 个输出词

这个叫 alignment problem,也就是"对齐问题"。

机器翻译真正难的地方之一,就是模型要知道:当前我在生成这个目标词时,源句里到底该看哪里?

2. Long-distance dependency(长距离依赖) 问题

RNN 是按顺序一个词一个词处理的。

理论上它能记住很长上下文,但实际上不行。

原因你前面已经学过了:

  • 信息要沿着时间步一步一步传
  • 早期信息会逐渐衰减
  • 会出现 vanishing gradient / exploding gradient
  • 即使 LSTM、GRU 有改进,也还是不够理想

所以一句很长的话里,句首的信息很难稳定地影响句尾。

这在翻译里就很致命,因为很多翻译决定依赖远距离信息。

3. 编码瓶颈问题

早期 seq2seq 常常让 encoder 把整句压缩成一个固定长度向量,再交给 decoder。

问题是:一整句话的信息,被硬塞进一个向量里,很容易丢信息。句子越长,这个问题越严重。

4. 不能并行

RNN 的天然结构决定了:

  • t 步必须等第 t-1
  • 训练和推理都很难并行
  • GPU 的优势吃不满

这在大规模训练时非常伤。

所以RNN 不只是效果还不够好 ,而且也不够高效

attention 的出现

attention 最初并不是为了"彻底替代 RNN"。它一开始是为了修复 seq2seq 的对齐问题。

关键思想是:

decoder 在生成当前词时,不要只看 encoder 最后压缩出来的那个总向量,而是动态去看源句中最相关的部分

简单举例来说:

假设你在翻一句话:

She doesn't like potatoes.

当模型生成不同目标词时,关注点应该不同:

  • 生成 she 时,重点看 She
  • 生成否定结构时,重点看 doesn't
  • 生成 potatoes 时,重点看 potatoes

也就是说:

不是整句里所有词都同等重要。不同生成时刻,重要的源词不同。

attention 做的就是这件事:

  • 给源句每个位置打分
  • 算出"当前时刻该关注谁"
  • 把这些关注结果加权汇总成当前上下文

所以 attention 的本质不是"记忆更多内容",而是:按需读取相关内容

这比让 RNN 把一切都死记在隐藏状态里聪明得多。

学术一点理解:

attention 先出现,是为了解决 seq2seq 翻译模型里的一个具体问题:解码器在生成当前词时,不能只靠一个压缩后的"整句摘要向量",而应该动态去看源句里哪些词最相关。

attention 解决的是"跨两段表示的对齐"。

在最早的机器翻译里:

  • 编码器产生源句的一串 hidden states
  • 解码器在生成第 t 个词时,用当前状态去和源句各位置做匹配
  • 然后决定现在应该重点看源句哪个部分

所以普通 attention 本质上是:

  • "我现在要输出这个词"
  • "那我去源句里找和它最相关的位置"

这是跨模块、跨序列的关注。也就是"decoder attend to encoder"(解码器看编码器)。

研究者很快发现,既然"动态挑重点"这么有效,就会自然追问一个更强的问题:

不是只有"解码器看编码器"才需要挑重点,输入句子内部自己是不是也需要这样做?

这就是 self-attention 出现的根本原因。

self-attention

最重要的发现:句子内部本身也存在大量依赖关系

研究者后来意识到,很多问题根本不只是"输出端该看输入端哪里",而是:

  • 输入句子里的每个词,本身就需要理解和它相关的其他词
  • 一个词的含义,常常依赖句内别的位置的信息

比如这句:

The animal didn't cross the street because it was too tired.

这里的 it 指的是谁? 模型必须看前面更远的位置,判断它和 animal、street 的关系。

再比如:

The book on the table near the window is mine.

要理解 is 对应的主语是谁,也要跨较远位置建关系。

所以研究者会发现:

RNN 是按时间一步一步传信息,但很多依赖其实不是"相邻传递"能高效表达的,而是"当前位置直接看全句其他位置"更自然。

于是就有了 self-attention:

不是"我拿 decoder state 去看 encoder outputs",而是句子里的每个 token 都可以直接看同一句子里的其他 token

更深的理解:

把 self-attention 理解成 attention 的一次抽象升级。

普通 attention 里,通常是两套不同来源:

  • query 来自 decoder
  • key/value 来自 encoder

而 self-attention 里,三者都来自同一个输入序列:

  • Q 来自当前序列
  • K 来自当前序列
  • V 也来自当前序列

所以它叫 self-attention。"self" 的意思不是"自己只看自己",而是同一个序列内部,彼此做 attention

也就是:

  • 每个 token 发出一个 query
  • 去和所有 token 的 key 做匹配
  • 再把匹配到的重要 value 加权汇总
  • 得到这个 token 的新表示

所以一个 token 的表示,不再只是它自己原本的 embedding,而是"它结合全句上下文之后"的表示。

self-attention轻松解决了RNN 的几个硬伤:

  1. 长距离依赖难学:一个词可以直接看全句,不必靠隐藏状态一层层传过去。
  2. 并行性差:RNN 必须按时间步一个个算;self-attention 可以整句同时算。
  3. 信息瓶颈:RNN 往往把信息压进一个不断传递的状态里;self-attention 允许每个位置都动态取用全局信息。 但是,self-attention 也有自己的问题:
  • 计算量对序列长度是平方级增长
  • 本身不自带顺序感

所以,这为后续的Transformer模型埋下了伏笔。

Transformer模型的介绍

Transformer 的出发点是谷歌的研究人员的一篇论文:《Attention is all you need》。既然 attention 这么有效,那能不能把 RNN 整个拿掉,只靠 attention 搭一个模型?

所以,Transformer 的核心是 self-attention。Transformer = 完全围绕 self-attention 构建的序列建模架构。

Transformer 的总思路

transformer 的第一步:先把 token 变成向量。和前一章一致,模型不能直接吃文字,只能吃向量。 所以输入流程还是:

  1. tokenization
  2. embedding
  3. 把 token 变成向量

但是在这之前,前面有一个self-attention的问题还没解决:self-attention不懂顺序。所以,经典 transformer 的做法是positional encoding位置编码。

详细来说是: 给每个 token embedding 再加上一份"位置向量"。也就是说,模型真正看到的不是单纯的 word embedding,而是:

token embedding + positional encoding

这样每个 token 的表示里,同时包含:

  • 它是什么词
  • 它在第几个位置

那么,现在就变成attention 只负责"看谁重要",position 负责"告诉它顺序"。

核心思路:transformer block

Transformer 不是一层 attention,而是很多层 block 叠起来。

每个 transformer block 主要有四个部件:

  • multi-head self-attention
  • feed-forward network
  • residual connection
  • layer normalization

这四个东西你要牢牢记住,因为后面所有 LLM,几乎都是这个骨架的变体。

  1. multi-head self-attention:从多个角度同时看上下文

同一句话,模型不只用一种方式去看 token 之间的关系,而是用多个"头"并行去看。

你可以把它想成:

  • 一个头擅长看语法关系
  • 一个头擅长看指代关系
  • 一个头擅长看长距离依赖
  • 一个头擅长看局部搭配

当然这些不是人工规定的,而是训练自己学出来的。

最后再把多个头的结果拼起来,形成更丰富的表示。

所以 multi-head 的价值是:

不是只问一个问题,而是同时从多个视角理解序列

  1. Feed-forward network:对每个位置再做一次非线性变换

attention 做完以后,还不够。

因为 attention 的核心是"信息混合"和"加权聚合",但它本身还不够强,不能单独完成复杂表征变换。

所以每个 block 后面还接一个 feed-forward network(FFN)。

它通常就是两层线性层加一个非线性激活。

你可以把它理解成:

attention 负责让 token 彼此交流,FFN 负责对每个 token 自己做更深的特征加工。

这两个配合起来,模型就既能看上下文,也能加工自身表示。

3.Residual connection:防止模型太深以后难训练

这是很重要的工程设计。

它的意思很简单:不要只保留"这一层算出来的新东西",而是把"输入"也直接加回去。

形式上就是:输出 = 子层结果 + 原输入

为什么这样做?

因为深层网络容易出现:

  • 梯度传不下去
  • 信息在层层变换中被破坏
  • 优化越来越困难

残差连接的本质作用就是:

给信息和梯度开一条捷径。

所以它让深层 transformer 能稳定训练。没有它,transformer 很难堆很多层。

你可以把 residual 理解成一句话:

模型每一层不是从零重写表示,而是在原表示基础上做增量修正

  1. Layer normalization:让训练更稳定

它做的事是把每层里的数值分布拉回一个相对稳定的范围。

为什么需要它?因为深层网络训练时,内部表示会不断漂移,数值可能忽大忽小,导致训练不稳定。

Layer norm 的作用就是:减少无意义的数值波动,让优化更平稳。

所以如果你把 transformer block 简化记忆:

  • attention:让 token 彼此看见
  • FFN:做局部非线性加工
  • residual:保留原信息、便于训练
  • layer norm:稳定训练过程

这就是一整个 block。

所以,一个 transformer block 到底在做什么?

现在你可以把一个 block 整体理解成四步:

csharp 复制代码
  第一步:self-attention

  每个 token 看整句,收集和自己相关的信息。

  第二步:add + norm

  把新信息和原输入合并,再做归一化。

  第三步:FFN

  对每个位置单独做进一步非线性加工。

  第四步:add + norm

  再次保留原信息并稳定训练。

所以一个 block 的本质不是"做一次复杂运算",而是:先全局交互,再局部变换。多个 block 叠起来后,表示会越来越抽象、越来越高级。

所以,在现代应用中,输入经过 embedding 和 position 编码之后,不是只过一层,而是会连续通过很多 transformer blocks。

每过一层,表示都会更抽象一点、更上下文化一点。

所以你可以这样理解层次变化:

  • 底层:更多局部词法、邻近关系
  • 中层:更多语法、依存、短程结构
  • 高层:更多语义、任务相关抽象

这也是为什么现代模型可以堆到几十层甚至更多。不是某一层神奇,而是层层堆叠让表示越来越强。

原始的Transformer

原始 transformer 不是今天常见的 GPT 那种纯 decoder,而是用于机器翻译的encoder-decoder 架构。

也就是两部分:

  • encoder:读输入句子
  • decoder:生成输出句子

比如英译法:

  • encoder 读英文句子
  • decoder

encoder 这一边主要是:

  • embedding
  • positional encoding
  • 多层 transformer block

它的目标是把输入序列编码成一组富含上下文的信息表示。

简单说:encoder 负责理解输入

decoder 做什么:

decoder 这边也有 embedding、position、多个 block,但它多了两个特殊点。

第一,decoder 不是直接看到完整未来答案。因为训练和生成时都不能作弊。

第二,decoder 不只是看自己前面已经生成的内容,还要看 encoder 的输出。

所以 decoder 里有两类 attention:

  • 对自己已生成部分的 attention
  • 对 encoder 输出的 attention(cross-attention)
  1. cross-attention

cross-attention就是让 decoder 去"看输入"

cross-attention 的本质是:decoder 在生成当前词时,不只参考自己前面生成了什么,还会去 encoder 那边找和当前生成最相关的信息。

所以:

  • Query 来自 decoder 当前状态
  • Key / Value 来自 encoder 输出

它的意义可以一句话说完:decoder 一边生成,一边回头查看输入内容。

这对翻译特别关键。因为法文当前该生成哪个词,要参考英文输入中哪个部分。

所以:

  • self-attention:在自己序列内部找关系
  • cross-attention:在输出序列和输入序列之间找关系

2.masked attention:为什么 decoder 要遮住即将生成的词

如果训练时让 decoder 看到未来词,那任务就变成作弊了。

例如要预测:

I love ...

如果模型已经看到了后面的 you,那它根本不需要学会语言建模。

所以 decoder 的 self-attention 必须加遮罩,只允许看:

  • 当前 token 之前的内容
  • 不允许看之后的 token

这叫 causal mask 或 masked attention。

本质上:生成模型必须只依赖过去,不能偷看未来。

这是 GPT 一类模型后面最关键的训练约束之一。

训练Transformer模型

Transformer 结构这么复杂,它到底是怎么训练出来的? 答案反而很朴素:

不给它人工标很多复杂标签,而是直接给它大量文本,让它学"下一个词该是什么"

这就是现代大模型训练最核心的起点。

训练目标:语言建模

Transformer 之所以强,不是因为人类手工教了它很多语法规则,而是因为:

  • 它有很强的表示能力
  • 互联网提供了海量文本
  • 我们可以设计一个"自监督"任务让它自己学

这个任务就是:

给前文,预测下一个 token。

比如输入:

to be or not to

模型要预测下一个词更可能是 be

所以训练时,模型本质上在学:一个词在上下文里出现的概率。

因为它看起来只是"猜下一个词",但本质上逼着模型学习很多更深的东西:

  • 语法
  • 搭配
  • 语义
  • 常识模式
  • 长距离依赖
  • 不同文本风格

所以训练目标虽然简单,但学出来的能力可以很复杂。

如果一个模型真的能持续准确预测"下一个词",那它就不可能只靠死记硬背局部模式。

它必须逐渐学会:

  • 这个句子现在在讲什么
  • 前面哪些词最关键
  • 当前 token 和更远位置的 token 有什么关系
  • 什么样的表达在真实语言里更自然

所以"预测下一个词"其实是一个自监督任务

重点在"自监督":

  • 不需要人工给标签
  • 文本本身就天然带标签
  • 前文是输入
  • 后一个词就是目标

这也是为什么互联网海量文本能直接拿来训练模型。

这就是语言模型。

transformer 的输出

前面我们讲过,Transformer block 的输入输出维度一直保持一致。

但训练时,我们真正想要的是:从当前上下文,预测整个词表里每个 token 的概率。

所以在 Transformer 最后,还要接两步:

  • 一个线性投影层:把最后的隐藏表示映射到词表大小。
  • 一个 softmax:把这些分数变成概率分布。

这一步书里把它叫做 unembedder。

为什么叫这个名字?

因为前面 embedding 是把 token 映射到向量空间;这里反过来,是把隐藏向量重新映射回"词表空间"。

也就是:

  • 输入:一个隐藏表示
  • 输出:对整个 vocabulary 的打分

这个打分向量通常叫 logits。再经过 softmax,就变成概率分布。

比如词表里有 50,000 个 token,那模型在某一步输出的就是:

  • cat 的概率
  • dog 的概率
  • run 的概率
  • ...
  • 所有 token 的概率

所以流程是:上下文 -> Transformer -> logits -> softmax -> 下一个 token 的概率分布

那拿到这个概率分布后,是为了做什么?为了解决训练时怎么知道模型预测得好不好。

拿模型预测的概率分布,和真实下一个 token 比。

如果真实答案是 be,模型却把 the 的概率给得最高,那就错了。

于是我们计算 loss,让模型更新参数。

这一过程会对句子里每个位置都做一遍。

比如一句话:

I love deep learning

训练时会变成很多个预测任务:

  • 看到 I,预测 love
  • 看到 I love,预测 deep
  • 看到 I love deep,预测 learning

最后把这些位置上的损失取平均。 这就是书里说的:final loss is the average of the loss of all the time steps

为什么transformer比RNN快

RNN 的问题是:

  • 必须一个词一个词往后算
  • 第 2 步要等第 1 步
  • 第 3 步要等第 2 步

所以天然串行。但 Transformer 不一样。

虽然任务仍然是"预测下一个词",但训练时我们可以把整句一起喂进去,并行算所有位置的预测。

你可以把它理解成:

  • RNN:一边读一边想
  • Transformer:整段都看到了,同时对每个位置做训练

所以它:

  • 更适合 GPU
  • 更容易扩展到大模型
  • 训练速度更快

这也是 Transformer 能统治现代大模型的现实原因之一。

一些经典训练方式:tearcher forcing

teacher forcing的意思是:训练时,模型在预测第 t 个词时,它前面的上下文不是它自己乱生成的,而是真实文本中的正确前文。

比如真实句子是:The cat sits on the mat

训练时预测 sits,给模型的前文是:The cat

而不是让模型先从头自己生成一个词,再接着往后。

所以:

  • 训练时:喂真实前文
  • 推理时:只能喂自己刚生成出来的词

因为训练初期模型很弱,如果一开始就喂它自己生成的错误结果,错误会一路累积,训练会非常不稳定。这也是训练和生成的一个重要区别。

所以 teacher forcing 的本质是:训练时走"标准答案轨道",让模型学会条件概率。

训练完成后,生成时怎么选词

训练时,模型会预测每个 token 的概率。生成时,它需要从这些概率中选一个。

通常有以下几种方式:

  • 最大概率(greedy decoding):选择概率最高的 token
  • 完全随机(Random sampling):从概率分布中随机选一个 token
  • top-k(Top-k sampling):只保留概率最高的前 k 个 token,再在这 k 个里面随机采样。
  • top-p(Top-p sampling):不是固定保留前 k 个,而是保留累计概率达到 p 的那一批 token。这个比 top-k 更自适应。
  • temperature(Temperature sampling):调整概率分布的形状,让模型更随机。

这里,你是不是看到了一些平时使用模型时需要填写的参数。

token的来源

为什么还要讲 token,而不直接讲"词"?

因为如果词表固定,那模型总会遇到没见过的新词。这就是 问题。

比如训练时见过:

  • big
  • bigger
  • small

但没见过 smaller。

那如果模型把最小单位定义成"整词",它就只能把 smaller 当未知词处理。

所以后来大家不再强依赖"整词词表",而是用 subword,也就是"子词",也就是token。

相关推荐
WolfGang0073214 小时前
代码随想录算法训练营 Day34 | 动态规划 part07
算法·动态规划
桂花饼4 小时前
AI 视频生成:sora-2 模型快速对接指南
人工智能·音视频·sora2·nano banana 2·claude-opus-4-6·gemini 3.1
Kk.08024 小时前
Linux(十一)fork实例练习、文件操作示例及相关面试题目分享
linux·运维·算法
GreenTea5 小时前
AI Agent 评测的下半场:从方法论到落地实践
前端·人工智能·后端
潇冉沐晴5 小时前
2026CCCC第三次模拟赛 部分题解
算法
冬奇Lab5 小时前
一天一个开源项目(第73篇):Multica - 把 AI 编程智能体变成真正的团队成员
人工智能·开源·资讯
WolfGang0073215 小时前
代码随想录算法训练营 Day32 | 动态规划 part05
算法·动态规划
天地沧海5 小时前
AI知识库集问答
人工智能