Encoder / Decoder · 三大派系
2017 年原版 Transformer 是一个"左脑 + 右脑"的结构——左边 Encoder(编码器)负责读懂,右边 Decoder(解码器)负责生成。它是为翻译任务量身打造的。但后来的研究者们发现:这两半脑其实可以拆开单独用——于是分化出三大派系:BERT(只用左脑)、GPT(只用右脑)、T5(左右并用)。今天你用的所有 LLM,都属于其中一派。
想象你正在做一部英文电影的中文字幕:
有一个人负责看英文原文——从头到尾读完、反复看,把每句话的意思、语气、隐含意图都吃透。他是"阅读理解型选手",可以自由地前后翻阅,不必按顺序。
另一个人负责写中文译文——他一边参考理解者的笔记,一边一个字一个字地把中文写出来。写下一个字的时候,只能看已经写过的字,不能"偷看"后面还没写的。他是"顺序输出型选手"。
这两个角色,分别对应 Transformer 里的 Encoder(编码器) 和 Decoder(解码器)。
三种架构 = 三种考生 · 先建立一个稳固的直觉
在钻进技术细节之前,先给你一个能扛住整篇文章的直觉框架。把三种 Transformer 架构想成同一场考试里的三类考生,你就再也不会混淆它们了。
- 阅读理解型考生 = Encoder-only他手上是一篇已经印好的文章,题目是"这篇文章的主旨是什么""第三段的'它'指代什么""作者的态度是褒还是贬"。他可以前后随意翻看,读第一段时可以先跳到最后一段看结论。他的输出很短——一个选项、一个标签、一个位置。他极擅长判断,但你让他续写文章,他不会。
- 写作型考生 = Decoder-only题目是"以下是作文的开头,请续写八百字"。他必须一个字一个字往下写,写第五百个字时只能看自己已经写下的四百九十九个字,后面是空白。他的输出可以无限长。他极擅长生成,而且只要把题干换个说法,他也能顺手做阅读理解——因为"回答问题"本身也是一种写作。
- 翻译型考生 = Encoder-Decoder题目是"把左边这段英文译成中文"。他的工作分两个明确阶段:先把左边整段反复读透(可以随意前后翻),再在右边一个字一个字写出译文(写的时候只能看自己写过的,但可以随时抬头再瞄一眼左边的原文)。他在"输入输出是两段不同文本"的任务上最专业,但结构复杂,不如写作型考生百搭。
这三类考生的差别,归根到底只有一件事:注意力允许看的范围不一样。阅读理解型全都能看,写作型只能往回看,翻译型是两个人配合、一个全看一个往回看外加互相看一眼。就这一个开关的三种设置,分化出了整个大模型世界的三大门派。请把这三个考生的形象记牢,本篇后面所有内容都可以挂回到他们身上。
先辨清一个关键区别 · 双向 vs 单向
Encoder 和 Decoder 都由多层 Multi-Head Attention 堆成,但它们的 Attention 能看的范围不一样——这一点差异,决定了两种架构的不同用途。
- Encoder · 双向 Attention每个词可以同时看到句子里所有位置的其他词——包括自己前面的和后面的。适合"理解",因为理解一个词经常需要看它后面的上下文。
- Decoder · 掩码单向 Attention每个词只能看自己和前面的词,不能偷看后面还没生成的词。适合"生成",因为写字的时候你还不知道后面要写什么。
那个"不能偷看"的机制有个专业名字叫 Causal Mask(因果掩码)——在 Attention 打分矩阵里,把"未来位置"的分数强行设成负无穷,softmax 之后就变成 0,模型就"看不见未来"了。这个简单的技巧,让 Transformer 能干"逐字生成"的活儿。
Encoder = 阅卷老师——他手里已经是一份写完的答卷,可以自由地前后翻阅、对照检查、综合理解。
Decoder = 考生答题——他在写第 100 字时,只能回头看已经写的 99 个字,不能偷看第 101 字(因为还没写呢)。
这就是为什么"理解型任务"要 Encoder、"生成型任务"要 Decoder。
派系一 · Encoder-only · BERT 家族
2018 年,Google 发布 BERT(Bidirectional Encoder Representations from Transformers)——名字里就写着两个关键词:Bidirectional(双向)+ Encoder。它做的选择是:砍掉 Decoder,只保留 Encoder,堆很多层,做"理解型 AI"。
BERT 的训练方法叫 Masked Language Model(MLM)——随机遮住句子里 15% 的词,让模型根据前后文猜出被遮的词是什么。因为它可以看到前后所有词(双向),这个任务对它来说就是"完形填空"。做几千亿次完形填空之后,它对语言的理解力惊人。
| 能力 | 典型应用 |
|---|---|
| 文本分类 | 情感分析、垃圾邮件判定、意图识别 |
| 命名实体识别 | 从文本里抽取人名、地名、公司名 |
| 问答(抽取式) | 从一段文字里找出答案所在的位置 |
| 相似度判断 | 两句话意思相不相近 |
| 语义搜索 | 把文档变成向量,做向量检索(RAG 的核心) |
但 BERT 不会"写"——它没有 Decoder,无法生成连贯的一段话。你不能让它给你写一篇作文,它只能理解你写的作文。这个短板决定了它在 ChatGPT 时代之后逐渐让位。
代表:BERT、RoBERTa、DeBERTa、ALBERT、ELECTRA、中文的 ERNIE / MacBERT。今天它们仍在搜索引擎、语义检索、RAG 系统里大量使用——因为这些场景不需要生成、只需要理解。
BERT 的两个训练任务 · 完形填空 + 判断上下句
BERT 的训练细节值得掰开看,因为它是"为什么后来输给了 GPT"这个问题的答案所在。它同时做两道题。
第一道题是 MLM(Masked Language Model,掩码语言模型)——所谓掩码语言模型,说白了就是做完形填空:把句子里 15% 的词用一个特殊符号 [MASK] 盖住,让模型猜盖住的是什么。因为它能看到前后所有词,这道题对它来说信息很充分。
第二道题是 NSP(Next Sentence Prediction,下一句预测)——所谓下一句预测,说白了就是判断两段话是不是原文里连着的:喂给它句子 A 和句子 B,一半时候 B 真的是 A 的下一句,一半时候 B 是从别处随便抓来的,让它判断"是"或"不是"。设计意图是教模型理解句子之间的关系。这道题后来被证明帮助很小——RoBERTa 干脆把它删了,效果反而更好。
BERT 的 MLM 训练样本长什么样
原句: 今天 天气 很 好 , 我们 去 公园 散步 吧
↓ 随机挑 15% 的位置动手
处理后:今天 [MASK] 很 好 , 我们 去 [MASK] 散步 吧
目标: 第 2 个位置 → "天气",第 8 个位置 → "公园"
15% 的位置里还要再细分(这是 BERT 论文里的一个精妙设计):
80% 换成 [MASK] → 今天 [MASK] 很好
10% 换成一个随机词 → 今天 苹果 很好
10% 原封不动保留 → 今天 天气 很好
为什么要搞这么复杂?
因为真正用模型的时候,输入里是不会出现 [MASK] 这个符号的。
如果训练时 100% 都是 [MASK],模型会形成一个坏习惯:
「只在看到 [MASK] 时才认真思考」,一到真实场景就懈怠。
掺进随机词和原词,是逼它对「每一个位置」都保持警觉。
这相当于:老师批改作业时,不只检查你画了圈的地方,
而是随机抽查任何一处 —— 你就不敢只应付标记处了。
【最要命的问题在这里】
一个 512 词的句子,只有 15% ≈ 77 个位置提供了学习信号。
剩下 85% 的位置,模型「看了但没被考」,白读了。
对比 GPT:同样一个 512 词的句子,
每一个位置都在被考「下一个词是什么」→ 512 个学习信号。
数据利用率:BERT 约 15%,GPT 100%。
在「数据是硬约束」的时代,这个差距是致命的。
那个 15% 的数字不是随便定的,是一个权衡:盖太少,一句话里学到的东西太少,训练效率低;盖太多,剩下的上下文残缺不全,模型没法根据线索推断。想象做完形填空,一句话十个词挖两个空你能填,挖八个空就只能瞎猜了。15% 是"信息量够用"和"学习信号够多"之间的一个折中,而这个折中本身就是 Encoder-only 路线的结构性天花板。
还有一个更微妙的问题叫训练与推理不一致(train-test mismatch)。BERT 训练时看到的输入里带着 [MASK] 这种人造符号,可实际使用时的输入是干净的自然文本,从没有 [MASK]。训练环境和考试环境长得不一样——好比你一直在有格子的稿纸上练字,考试却给你一张白纸。GPT 那套"预测下一个词"完全没有这个毛病:训练时怎么做,推理时就怎么做,严丝合缝。这是后来 Decoder-only 胜出的又一个隐形优势。
派系二 · Decoder-only · GPT 家族
OpenAI 走了另一条路:砍掉 Encoder,只保留 Decoder,堆很多层,做"生成型 AI"。这就是 GPT(Generative Pre-trained Transformer)系列——从 GPT-1 到 GPT-4、再到 ChatGPT。
GPT 的训练方法叫 Causal Language Model(CLM)——给它一段话的前半截,让它预测下一个词。这么简单的任务,就是它的全部训练目标。奇迹在于——当参数规模够大、数据够多,光靠"预测下一个词"这个任务,模型就涌现出对话、翻译、编程、推理、写代码等一大批能力。
| 能力 | 典型应用 |
|---|---|
| 对话 | ChatGPT、Claude、豆包、DeepSeek Chat |
| 代码生成 | Copilot、Cursor、Trae |
| 创意写作 | 写小说、写文案、写邮件 |
| 推理 / 数学 | o1、DeepSeek-R1、Claude Sonnet Thinking |
| 指令跟随 | 翻译、总结、改写、格式转换 |
Decoder-only 的最大优势——极其通用。任何任务只要能表达成"输入一段文字、输出一段文字",就能用同一个模型做。翻译?"把下面这句英文翻成中文:...";总结?"把下面这段总结成三句话:...";写代码?"用 Python 写一个快速排序:..."——统统是"续写"。这种"一个模型打天下"的通用性,让 Decoder-only 成了 2023 年后所有大模型的默认选择。
代表:GPT-3、GPT-4、Claude、LLaMA、Qwen、DeepSeek、Kimi、豆包 全部都是 Decoder-only。
GPT 的家谱 · 从被 BERT 碾压到一统天下
今天回看 GPT 系列的胜利像是必然,但在 2018 到 2019 年,这条路线是被公认为"输了"的。把时间线摆出来,你会看到一个非常反直觉的过程。
| 版本 | 时间 | 参数量 | 关键变化 | 当时的处境 |
|---|---|---|---|---|
| GPT-1 | 2018.06 | 1.17 亿 | 首次提出"无监督预训练 + 有监督微调" | 发布 4 个月后被 BERT 全面超越,几乎无人问津 |
| BERT | 2018.10 | 3.4 亿 | 双向 + MLM | 11 项任务刷新纪录,学术界一片倒向 Encoder |
| GPT-2 | 2019.02 | 15 亿 | 不微调,直接零样本做任务 | 因"太危险"分批发布,被讥为营销;但已显露端倪 |
| GPT-3 | 2020.05 | 1750 亿 | In-Context Learning 大规模涌现 | 震动全行业——原来只要够大,不微调也能干活 |
| InstructGPT | 2022.01 | 1750 亿 | 加入人类反馈强化学习(RLHF) | 解决了"会说但不听话"的问题 |
| ChatGPT | 2022.11 | —— | 包装成对话产品 | 两个月一亿用户,Encoder 路线彻底退场 |
| GPT-4 | 2023.03 | 传闻万亿级 MoE | 多模态 + 大幅推理提升 | 确立 Decoder-only 为唯一主流 |
请注意 2018 年到 2020 年这段"至暗时期"。当时几乎所有论文都在 BERT 上做改进,GPT 路线看起来是明显的失败者——因为在需要微调的标准评测上,它就是打不过 BERT。OpenAI 坚持下去的理由,事后被总结成一句话:他们赌的不是"哪个架构在当前规模下更强",而是"哪个架构在规模放大一千倍之后更强"。这个赌注的核心依据,就是我们下面要讲的数据利用率和任务统一性。
顺便说清一个术语,你在各处会反复见到它。自回归(Autoregressive,自回归)——所谓自回归,说白了就是"把自己刚说出口的话,当成下一句话的开头,再接着说"。写文章时你就在做这件事:写完一句,读一遍,再顺着往下写。GPT 的生成方式完全是这样:吐出一个词,把它接到输入末尾,重新算一遍,再吐一个词。它没有草稿、没有大纲、没有"我打算这段写三百字"的规划——只有一步接一步地往下接。这个性质既是它流畅自然的原因,也是它容易"说着说着跑偏"的原因。
派系三 · Encoder-Decoder · T5/BART 家族
还有一批模型保留了原版 Transformer 的"完整双脑"结构,代表是 Google 的 T5(Text-to-Text Transfer Transformer)和 Facebook 的 BART。它们的思路是:Encoder 先读懂输入,Decoder 再基于理解生成输出——两阶段清晰分工。
这种结构天然适合"输入 → 输出"是两段不同文本的任务:
- 机器翻译Encoder 读英文,Decoder 写中文——原版 Transformer 就是干这个的。
- 文本摘要Encoder 读长文,Decoder 写短摘要。
- 问答生成Encoder 读文档 + 问题,Decoder 写答案。
- 语音识别Encoder 读音频特征,Decoder 写文本(Whisper 就是这种)。
Encoder 和 Decoder 之间通过一种叫 Cross-Attention 的机制沟通——Decoder 在生成每一个词时,不仅看自己已经生成的部分(Self-Attention),还额外看一眼 Encoder 输出的全部内容(Cross-Attention)。像考生答题时不断翻回原文找依据。
Encoder-Decoder 就像同声传译——
Encoder:戴耳机专注听源语言(英文),构建对整句意思的完整理解;
Cross-Attention:翻译时随时"闪回"看一眼刚才听懂的原文点,确认没漏;
Decoder:用目标语言(中文)一个词一个词流畅地讲出来。
这个流水线在专门做"翻译/摘要"这类任务时非常自然,但通用对话反而不是它的强项——多了一层结构,反而不如 Decoder-only 灵活。
T5 的贡献 · "万物皆可文本到文本"
T5 这个模型今天用的人不多了,但它留下了一个影响至今的思想。它的全名 T5(Text-to-Text Transfer Transformer,文本到文本迁移变换器)——所谓文本到文本,说白了就是不管什么任务,输入都写成一段文字,输出也是一段文字。
在 T5 之前,做不同任务要接不同的"输出头":分类任务后面接一个分类层,序列标注接一个标注层,回归任务接一个数值层。T5 说:别接了,全部用文字表达。
T5 的"任务前缀"设计:靠一句话切换任务
翻译: 输入 "translate English to German: That is good."
输出 "Das ist gut."
分类: 输入 "cola sentence: The course is jumping well."
输出 "not acceptable" ← 连标签也是文字!
相似度: 输入 "stsb sentence1: A plane is taking off.
sentence2: An airplane is taking off."
输出 "5.0" ← 连数字也是文字!
摘要: 输入 "summarize: 一大段新闻正文……"
输出 "三句话的摘要"
同一个模型,同一套权重,靠输入前面那句提示词切换职能。
这个设计现在你每天都在用 —— 你对 ChatGPT 说
「帮我把下面这段翻译成英文」,走的就是同一条思路。
只不过 T5 需要在训练时把前缀写死,
而 GPT-3 之后的模型连训练都不需要,直接用自然语言指挥。
【T5 的另一个贡献:一次极其昂贵的对照实验】
T5 论文(2020)本质上是一篇「把所有选择都试一遍」的实验报告:
· 三种架构(Encoder-only / Decoder-only / Encoder-Decoder)
· 多种训练目标(MLM / CLM / 片段去噪 / 打乱还原)
· 多种掩码比例、片段长度、数据集大小
在当时的规模(最大 110 亿参数)下,它的结论是
「Encoder-Decoder + 片段去噪」最好。
这个结论在那个规模上是对的 ——
但规模再放大两个数量级后,结论翻转了。
这是 AI 研究史上一个很好的教训:
小规模下的对照实验结论,不一定能外推到大规模。
T5 的训练目标叫片段去噪(Span Corruption)——所谓片段去噪,说白了就是把连续的一小段词整块挖掉换成一个占位符,让模型把整段补回来。它比 BERT 的单词级完形填空更接近"生成",因为要补的是一串词而不是一个词。你可以把它看成 MLM 和 CLM 之间的过渡形态:既有双向理解,又要求连续生成。这个设计相当聪明,它在 2020 年确实是最优解——只是没能扛住规模化的考验。
还有一个当下仍活跃的例子值得一提:Whisper(OpenAI 的语音识别模型)就是标准的 Encoder-Decoder。Encoder 读音频的频谱特征,Decoder 写出文字。为什么这类任务至今仍用 Encoder-Decoder?因为输入和输出是两种完全不同的东西(声音 vs 文字),硬塞进一个单向序列里反而别扭——就像同声传译天生就该是"一只耳朵听、一张嘴说"的双通道结构,让一个人边听边把听到的也说出来才是奇怪的。这也提示我们:Decoder-only 赢了通用对话,但不等于赢了一切场景。
三派对比总表
| Encoder-only | Decoder-only | Encoder-Decoder | |
|---|---|---|---|
| Attention 方向 | 双向 | 单向(掩码) | Encoder 双向 + Decoder 单向 |
| 核心训练目标 | 完形填空 (MLM) | 预测下一个词 (CLM) | 掩码片段填空 / 去噪 |
| 擅长 | 理解 / 分类 / 抽取 | 生成 / 对话 / 创作 | 翻译 / 摘要 / 转写 |
| 不擅长 | 写连贯长文 | 纯理解任务(大材小用) | 灵活性略差 |
| 代表 | BERT / RoBERTa / DeBERTa | GPT / Claude / LLaMA / Qwen / DeepSeek | T5 / BART / Whisper / mT5 |
| 参数规模 | 1 亿 ~ 10 亿 | 10 亿 ~ 万亿 | 1 亿 ~ 百亿 |
位置编码的三代演进 · 从贴号码牌到让号码牌带角度
这里必须补上一个前面几篇一直没提、但绝对不能少的东西。Attention 本身是"不知道顺序"的——这句话听起来很荒谬,但确实如此。回看打分公式:每个词跟每个词点积,算出一张座位表。如果你把句子里的词顺序完全打乱,算出来的注意力矩阵只是行列被同样地重排了,每个词得到的输出内容一模一样。
用大白话说:对 Attention 来说,"猫追球"和"球追猫"是同一句话。这显然不行。所以必须额外告诉模型每个词的位置,这个额外信息叫位置编码(Positional Encoding,位置编码)——所谓位置编码,说白了就是给每个座位贴一个号码牌,让模型知道谁坐第一排、谁坐第十排。
第一代 · 正弦绝对位置编码(2017 原论文)
做法:给每个座位贴一张写着绝对编号的牌子——"你是第 1 位""你是第 2 位"。技术上用一组不同频率的正弦余弦波来生成这些牌子,好处是任意长的位置都能算出牌子来。
问题:模型真正关心的往往不是"你是第 37 位",而是"你离我几个位子"。绝对编号要靠模型自己去做减法推算相对距离,费劲且不稳。而且训练时只见过 512 号以内的牌子,突然给它 2000 号,它就懵了。
第二代 · 可学习绝对位置编码(BERT / GPT-2)
做法:干脆不用公式算了,把"第 1 号牌""第 2 号牌"……每张牌的内容都做成可训练参数,让模型自己学该往牌子上写什么。
问题:牌子的数量是写死的。训练时准备了 512 张牌,你想处理 1000 个词——第 513 张牌根本不存在,模型无从下手。这就是早期模型"上下文长度改不了"的根本原因:座位号牌是印死的,加座位就没牌可贴。
第三代 · RoPE 旋转位置编码(2021,今天的绝对主流)
做法变了个思路:不再往词的向量上"加"一张牌,而是按位置把词的向量"旋转"一个角度——第 1 个位置转 1 度,第 2 个位置转 2 度,第 100 个位置转 100 度(这是简化说法,实际是把向量两两配对做二维旋转,每对用不同的旋转速度)。
妙处在哪?两个向量做点积时,结果只取决于它们之间的夹角差,而夹角差正好等于位置差。也就是说:第 10 个词和第 13 个词的相对关系,跟第 110 个词和第 113 个词的相对关系,算出来是一样的——位置信息自动变成了"相对距离",而且没有任何"牌子用完"的问题,转多少度都行。
这就是为什么今天 LLaMA、Qwen、DeepSeek、Mistral 全都用 RoPE,也是为什么"扩展上下文长度"从"不可能"变成了"调几个参数就行"。
三代位置编码对比
┌──────────────┬────────────────┬──────────────┬─────────────────┐
│ │ 正弦绝对 │ 可学习绝对 │ RoPE 旋转 │
├──────────────┼────────────────┼──────────────┼─────────────────┤
│ 提出时间 │ 2017 原论文 │ 2018 BERT │ 2021 苏剑林 │
│ 是否可训练 │ 否(公式算出) │ 是 │ 否(公式算出) │
│ 编码的是 │ 绝对位置 │ 绝对位置 │ 相对位置(隐式) │
│ 加在哪里 │ 输入向量上 │ 输入向量上 │ Q、K 上(每层都做)│
│ 能否外推 │ 理论可以,实测差 │ 完全不能 │ 可以,且有多种扩展 │
│ 代表模型 │ 原版 Transformer│ BERT / GPT-2 │ LLaMA / Qwen / │
│ │ │ / GPT-3 │ DeepSeek / 几乎全部│
└──────────────┴────────────────┴──────────────┴─────────────────┘
RoPE 为什么能"外推"到更长的上下文?三种常见手法:
1. 位置插值(Position Interpolation)
把旋转角度整体缩小。原来 4096 个位置转满一圈,
现在让 32768 个位置转满一圈 —— 相当于
把同样长度的尺子刻上八倍密的刻度。
代价:分辨率变粗,近距离的区分变弱。
2. NTK-aware 缩放
不均匀地缩放:高频(管细粒度距离)少改,
低频(管远距离)多改。
相当于「近处刻度保持精细,远处刻度放粗」——
比一刀切的插值效果好得多。
3. YaRN
在 NTK 的基础上再加温度修正,
是目前长上下文扩展的主流方案之一。
Qwen、DeepSeek 的长上下文版本都用过类似手法。
一个实际的数字:Llama-2 原生 4K 上下文,
用位置插值 + 少量长文本微调,就能扩到 32K;
用 YaRN 类方法,128K 也能做到 —— 而不需要从头重训。
LayerNorm 放在哪 · 一个位置决定了能不能训起来
这是一个特别能体现"魔鬼在细节里"的例子。上一篇提过 LayerNorm 相当于层间的自动音量调节器。现在的问题是:这个调节器该放在 Attention 之前还是之后?答案居然影响到"这个模型能不能训得起来"。
【Post-LN · 2017 原论文的写法】
x_out = LayerNorm( x + Attention(x) )
↑ 先加残差,再归一化
残差通路上「有」归一化 → 梯度往回传时会被反复缩放
【Pre-LN · 2019 年之后所有大模型的写法】
x_out = x + Attention( LayerNorm(x) )
↑ 残差通路完全干净,一路直通
残差通路上「没有」归一化 → 梯度从最后一层到第一层
可以几乎无损地流回去
为什么这个区别这么要命?
Post-LN 的问题:层数一多,靠近输入的那几层收到的梯度
会被上面每一层的 LayerNorm 逐次缩放,累积起来极不稳定。
实践后果:
· 6 层、12 层还行(原论文规模)
· 到 24 层以上,必须用「学习率预热」小心伺候
—— 前几千步把学习率从 0 慢慢升上去,否则一开训就崩
· 到 100 层,基本训不动
Pre-LN 的好处:残差是一条从头到尾的高速公路,
中间没有收费站。梯度想回到第一层,一脚油门就到了。
实践后果:
· 96 层、120 层都能稳定训练
· 对学习率预热的依赖大幅降低
· 代价:最终效果比调好的 Post-LN 略差一点点
(所以有 DeepNorm、Sandwich-LN 等折中方案)
今天的标准选择:Pre-LN + RMSNorm
RMSNorm 是 LayerNorm 的简化版 —— 只除以幅度,不减平均值。
少算一步,速度快 10%~15%,效果基本无差。
LLaMA 起,几乎所有开源大模型都用 Pre-RMSNorm。
用一个生活场景把这件事讲透:Post-LN 像一条每隔一公里就设一个收费站的高速公路——车(梯度)从终点开回起点,要停几十次,每次都被检查、被调整,开到最后已经面目全非。Pre-LN 把收费站全部挪到了辅路上——主路一路畅通,车能原样开回起点;辅路上的检查照做,不影响主干道。"让主通路保持干净"是深度学习里一条被反复验证的设计原则,从 ResNet 到 Transformer 都是同一个道理。
FFN 在干什么 · 注意力负责互看,FFN 负责各自消化
一层 Transformer 有两个子模块,我们花了三篇讲第一个(Attention),第二个 FFN(Feed-Forward Network,前馈网络)一直没正面讲过。但它的参数量其实比 Attention 还多——占整个模型的三分之二左右。它到底在干什么?
所谓前馈网络,说白了就是一个"先放大、再压回来"的小加工车间:把每个词的 512 维向量先撑到 2048 维(四倍),做一次非线性变换,再压回 512 维。关键点是:它对每个词单独处理,词与词之间完全不通气。
这就形成了一个非常清晰的分工,用开会来打比方:Attention 是"讨论环节"——每个人听所有人发言,收集信息;FFN 是"散会后各自回工位消化"——把刚才听到的一堆信息,结合自己脑子里的知识加工成结论。一层 = 一轮"开会 + 消化",几十层就是几十轮。只有讨论没有消化,信息进不了脑子;只有消化没有讨论,你根本不知道别人说了什么。
FFN 的结构与参数量(d_model=512, d_ff=2048)
x [512] → W_1 [512, 2048] → 激活函数 → W_2 [2048, 512] → out [512]
↑ 撑开四倍 ↑ 压回原尺寸
参数量 = 512×2048 + 2048×512 = 2097152 ≈ 210 万
而同一层的注意力(含 W_O)约 105 万
→ FFN 是注意力的两倍,占一层参数的约 2/3
为什么要「先撑开再压回」?
这是神经网络里的经典套路:在高维空间里,
原本纠缠在一起的特征更容易被一刀切开。
打个比方:一堆红豆绿豆混在浅盘里很难分,
倒进一个大簸箕里摊开、抖一抖,就分层了 ——
分好之后再收回小盘。撑开的那一步就是「摊开抖一抖」。
【FFN 里存的是什么?—— 研究界的一个重要发现】
多项研究(如 Geva 等人 2021)指出:
FFN 的行为很像一个「键值记忆库」。
W_1 的每一行相当于一把「钥匙」,检测输入里
有没有某种特定模式;W_2 的对应列则是这把钥匙
被触发后要写出的「内容」。
所以有一个流行的说法:
Attention 负责「把信息路由到该去的地方」,
FFN 负责「存放模型学到的事实性知识」。
「巴黎是法国的首都」这类知识,主要就存在 FFN 里。
这也解释了为什么 MoE 要拿 FFN 开刀 ——
知识库最大,最值得做成「按需调用」。
激活函数的演进 · ReLU → GeLU → SwiGLU
FFN 中间那个"激活函数"是什么?所谓激活函数,说白了就是一个决定"这个信号要不要往下传、传多少"的小闸门。没有它,无论堆多少层,整个网络在数学上会退化成一个巨大的线性变换——等于只有一层,白堆了。非线性是深度的前提。
| 激活函数 | 行为 | 大白话 | 用在哪 |
|---|---|---|---|
| ReLU | 负数一律归零,正数原样通过 | 一个粗暴的开关:不合格的直接扔掉,合格的照原样放行 | 2017 原版 Transformer |
| GeLU | 按数值大小平滑地决定通过比例 | 不再一刀切:小的负数还留一点点,大的负数才彻底扔掉——软性淘汰 | BERT / GPT-2 / GPT-3 |
| SwiGLU | 把输入分成两路,一路当内容、一路当"闸门开度",相乘 | 一路负责"说什么",另一路负责"这句话该说多大声"——两路配合 | LLaMA / Qwen / DeepSeek / PaLM |
ReLU 有个毛病叫"神经元死亡":一旦某个位置的输入长期是负数,它就永远输出 0、梯度也永远是 0,这个神经元等于报废了。好比一个员工因为一次评估不合格被永久停职,再也没有翻身机会。GeLU 用平滑过渡解决了这一点——负数区域仍有一点微弱的输出和梯度,留了一线生机。
SwiGLU 更有意思,它引入了门控(Gating)机制——所谓门控,说白了就是用一路信号去控制另一路信号的音量。它把 FFN 的第一步拆成两个并行的线性层:一路算"内容",一路算"该放多少内容过去",两者逐元素相乘。从"一个固定的闸门"变成了"一个会根据内容自己调节开度的闸门"——相当于从固定水龙头换成了带感应的智能龙头。
SwiGLU 的一个工程细节:为什么 Llama 的 d_ff 是 11008 这种怪数字
普通 FFN: 两个矩阵 W_1[d, d_ff] + W_2[d_ff, d]
参数量 = 2 × d × d_ff
惯例 d_ff = 4d
SwiGLU: 三个矩阵 W_gate[d, d_ff] + W_up[d, d_ff] + W_down[d_ff, d]
参数量 = 3 × d × d_ff ← 多了一个矩阵!
为了让参数量别涨,就得把 d_ff 缩小:
3 × d × d_ff' = 2 × d × 4d
d_ff' = 8d/3 ≈ 2.67 d
Llama-2-7B:d_model = 4096
8/3 × 4096 = 10922.67
再向上取整到 256 的倍数(对齐 GPU 计算单元)→ 11008 ✓
所以那个"莫名其妙"的 11008,是
「三个矩阵还要维持原参数量」+「对齐硬件」两个约束的乘积。
下次你在模型配置文件里看到这种数字,就知道它的来历了。
Noam Shazeer 在提出 SwiGLU 的论文里留下一句名言级的结尾:"我们把这些架构的成功归因于神的恩赐(divine benevolence)"——意思是他也说不清为什么这个组合就是更好,只有实验数据支持。这在深度学习里非常典型:很多有效的设计先被实验发现,理论解释要等好几年才补上,有的至今没补上。
长上下文改造 · 三条绕开平方复杂度的路
§7.2 算过那笔账:注意力的计算量是长度的平方,10 万词就要算 100 亿次。要支持长上下文,必须动这个平方。业界的办法可以归成三条路,而且它们的取舍逻辑非常清楚。
- 路线一 · 稀疏注意力(Sparse Attention)思路:不让每个词看所有词,只看一部分。说白了就是把"全员大会"改成"小组会 + 组长联席会"。具体做法有滑动窗口(只看左右各 N 个邻居,Mistral 用的就是 4096 窗口)、全局标记(少数几个"组长"词可以看全场,其他词只能看邻居和组长,Longformer/BigBird 的做法)、分块稀疏(把序列切块,块内全看、块间抽样)。代价:牺牲了"任意两点一步直达"这个 Attention 最初的卖点,远距离信息要绕几层才能碰面。
- 路线二 · 线性注意力(Linear Attention)思路:用数学变形把 n² 变成 n。核心技巧是改变矩阵乘法的结合顺序——原本是 (QKᵀ)V,先算出 n×n 的大矩阵;变形后是 Q(KᵀV),先算 d×d 的小矩阵,跟序列长度无关了。代表有 Performer、Linformer,以及 2023 年之后火起来的 Mamba、RWKV 这类"新循环网络"。代价:必须去掉 softmax 或用近似替代,表达能力有损失;实测在长距离精确检索类任务上明显不如标准注意力。
- 路线三 · 不改数学、只改工程(Flash Attention 路线)思路:平方就平方,但让它跑得飞快、占显存极少。上一篇详细讲过分块计算的做法:结果一位小数都不差,显存从 O(n²) 降到 O(n),速度快 2~4 倍。这条路是目前的主流赢家——因为它不牺牲任何效果,纯赚。代价:计算量仍然是平方的,长度涨十倍还是慢一百倍,只是常数小了很多。
现实中的主流方案是三条路混着用。以 Mistral 7B 为例:底层用 Flash Attention(路线三),结构上用滑动窗口(路线一)加上 GQA 省显存,位置编码用 RoPE 配合插值扩展。没有哪一条路能单独解决问题,实际的长上下文能力是四五种技术叠加出来的。这也是为什么"上下文长度"这个指标常常带有水分:一个模型标称支持 128K,但它在 128K 处的实际检索准确率可能已经掉得很厉害——业界专门有个测试叫"大海捞针"(Needle in a Haystack),就是往超长文本中间藏一句话,看模型能不能找出来。标称长度和有效长度是两件事,这一点在选模型时值得留心。
为什么现代 LLM 全是 Decoder-only
你可能会好奇——既然 Encoder-Decoder 结构"更全面",为什么反而是精简版的 Decoder-only 一统天下?答案有三个层面:
- 通用性最强任何任务都能用"一段文本进、一段文本出"表达——Prompt 就是万能接口。分类可以问它"这是正面还是负面",翻译可以问它"翻成中文"——一个模型什么都能干。
- 规模化最容易结构简单(只有一半的模块),意味着扩到万亿参数时工程复杂度低。BERT 那种双向结构在超大规模下反而不稳定。
- In-Context Learning 涌现GPT-3 论文最惊人的发现——大到一定程度后,Decoder-only 模型不需要重新训练,只要在 prompt 里给几个例子,它就能学会新任务。这是"少样本学习"能力,Encoder-only 和 Encoder-Decoder 都没这么强。
所以从 2020 年 GPT-3 之后,几乎所有主流大模型都是 Decoder-only——OpenAI、Anthropic、Meta(LLaMA)、Google(Gemini 后期)、阿里(Qwen)、深度求索(DeepSeek)、字节(豆包/Doubao)、月之暗面(Kimi)……清一色 Decoder-only。
Encoder-only 退居"语义搜索、向量库"的幕后战场;Encoder-Decoder 主要用在专门的翻译、语音识别、摘要任务上,规模也不大。Decoder-only 就是当代 AI 的"事实标准"。
把三种架构想成三家培训机构,你就明白为什么第二家最后垄断了市场。
第一家(Encoder-only)专教"判断题"——你毕业后能当质检员、分类员、评审员,干得又快又准。但你不会写东西,客户想要一篇报告,你只能说"我可以帮你判断这篇报告写得好不好"。市场天花板很低——判断题的活儿本来就没那么多。
第二家(Decoder-only)只教一件事:"接着往下写"。听起来极其单调,但毕业生发现:客户要分类,他就写"这条评论是正面的";客户要翻译,他就写译文;客户要判断真假,他就写"这个说法不成立,因为……"。所有的活儿都能包装成"写点东西",于是这家机构的毕业生什么工作都能接。
第三家(Encoder-Decoder)教的是"先读透再转写",培养出来的是专业翻译和摘要员,水平很高,但只在这两个岗位上吃香,而且培训周期长、成本高。专才干不过全才,尤其当全才的水平也追上来之后。
这就是"统一接口"的力量:一个能表达所有任务的接口(自然语言),加上一个能处理这个接口的架构(自回归生成),组合出了一个通吃的方案。
三个层面之外 · 还有五个更硬的理由
上面那三条是最常被引用的答案,但底下还有几个更技术性的原因,把它们说清楚,你对这场路线之争的理解才算完整。
- 理由四:数据利用率高 4~7 倍前面算过:BERT 一个 512 词的样本只产生约 77 个学习信号,GPT 产生 512 个。在"高质量文本快用完了"的时代,同样的数据能榨出几倍的训练信号,这是决定性的优势。相当于同一本习题册,一个人只做了标了星号的题,另一个人每道题都做了。
- 理由五:训练与推理完全一致GPT 训练时做的事和推理时做的事是同一件——"看前文,猜下一个词"。没有
[MASK]这种只在训练里出现的人造物,没有任何环境落差。练兵就在战场上练,不用担心水土不服。 - 理由六:KV Cache 天然可用因为是单向的,前面词的 K/V 算完就永远不会变,可以放心缓存(§7.2 算过能省 99.8% 的重复计算)。而双向注意力一旦来了新词,前面所有词的表示都要重算——BERT 结构从原理上就没法做增量生成。这在推理成本上是天壤之别。
- 理由七:结构简单,好扩展Decoder-only 只有一种模块,重复堆叠即可;Encoder-Decoder 有三种注意力(Encoder 自注意力、Decoder 自注意力、交叉注意力),做张量并行、流水线并行时切分方案复杂得多。要在上万张卡上训练,工程简洁性本身就是竞争力。
- 理由八:把"理解"也变成了"生成"这是最深的一条。传统认知是"理解要双向",但 Decoder-only 找到了绕路的办法——让它先把思考过程写出来,再写答案。写出来的思考过程会进入上下文,成为后续推理的依据,等效于做了多轮双向审视。这就是思维链(Chain-of-Thought)和 o1/DeepSeek-R1 那类推理模型的原理。不能回头看,那就把要看的东西先写下来。
有一篇专门做这个比较的工作(2022 年的《What Language Model Architecture and Pretraining Objective Work Best for Zero-Shot Generalization?》)系统试了各种组合,结论支持了实践中的观察:如果你要的是"不做任何微调就能干各种活",Decoder-only + 预测下一个词是最好的组合;而如果允许充分微调,Encoder-Decoder 在同等参数下往往更强。换句话说,Decoder-only 赢的不是"能力上限",而是"通用性和可规模化"这两条更符合产业需求的维度。这也解释了为什么在专门的翻译、语音识别产品里,Encoder-Decoder 至今仍然活得很好。
一个有趣的问题 · Decoder-only 能理解吗
有人会问:既然 BERT 用双向 Attention 才能好好理解,那 GPT 这种只能看前不能看后的架构,为什么理解能力也这么强?
答案藏在规模里——参数一大,Decoder-only 内部就能"迂回"完成理解。它虽然每个位置只能看前面,但它预测每个下一个词时,都在综合前面所有信息做判断——训练久了,每个词的内部表示就已经承载了对整句话的深度理解。
更妙的是:Decoder-only 生成到某个位置时,可以先生成一段"思考文本"(Chain-of-Thought),再生成最终答案——相当于把"理解"这一步也变成了"生成"的一部分。这就是 2024 年 o1、DeepSeek-R1 这批推理模型的秘密。用生成模拟理解——一个模型解决所有问题。
Encoder-only 会消失吗?· 不会,但退居幕后
虽然大模型潮流是 Decoder-only,但 Encoder-only 并没有消失——它退居到了一个非常关键的位置:向量嵌入。
今天 RAG(Retrieval-Augmented Generation)系统、向量数据库、搜索引擎、推荐系统里,都需要把一段文本变成一个高质量的向量——这个活儿 Encoder 最擅长。因为它双向、专注理解、模型小、推理快,正好符合"高频、低延迟、只做理解"的场景。
代表:OpenAI 的 text-embedding-3、BAAI 的 bge 系列、Qwen 的 gte 系列——底层都是 BERT-style 的 Encoder-only。所以别以为 Encoder 死了——它只是从台前走到了幕后,成了向量检索基础设施的隐形冠军。
三派系一句话总结
- Encoder-only(BERT)看得清楚、说不出来——用在"分类、抽取、搜索、嵌入"。
- Decoder-only(GPT)边看边说、能说会道——用在"对话、生成、推理、编程"。
- Encoder-Decoder(T5)先看再说、专业转写——用在"翻译、摘要、语音识别"。
Transformer 的"左右脑"可以拆开单独用,于是有了三大派系:Encoder-only 懂、Decoder-only 写、Encoder-Decoder 翻。今天的 LLM 战场,Decoder-only 一家独大——因为它足够通用、足够易扩展、还能涌现出上下文学习能力。
但当模型规模冲上万亿,另一个问题来了——参数越大,训练和推理成本越贵。有没有办法让"参数很多、但每次只用一小部分"?下一篇,我们看看 2024 年最火的架构——MoE 专家混合。