大模型 · 01

GPT 与 BERT:预训练范式

从特征工程到预训练——拆解 GPT 的因果语言模型和 BERT 的掩码语言模型,理解为什么让模型先在海量文本上自学,再去做具体任务,彻底改变了 NLP 的玩法。

18 min read

预训练革命

在 2018 年之前,NLP 的标准流程是这样的:

  1. 拿到一个具体任务(情感分类、命名实体识别、机器翻译……)
  2. 手工设计特征(词袋、TF-IDF、n-gram、依存句法树……)
  3. 训练一个监督模型(SVM、CRF、浅层 LSTM……)

每换一个任务,特征要重新设计,模型要从零训练。标注数据永远不够用——人工标 10 万条已经是大工程,但语言的复杂度远不止 10 万条能覆盖的。

2018 年,两篇论文几乎同时给出了另一种范式:

先在海量无标注文本上"自学"语言规律(预训练),再用少量标注数据适配具体任务(微调)。

这两篇论文就是 GPT(OpenAI,2018 年 6 月)和 BERT(Google,2018 年 10 月)。它们用的底层架构都是 Transformer,但训练目标截然不同——一个从左往右预测,一个双向填空。

预训练的核心洞察很简单:语言本身就是监督信号。你不需要人工标注"这句话是正面还是负面",只要让模型预测下一个词(或者还原被遮住的词),它就必须理解语法、语义、常识、甚至逻辑推理。几十 GB 的互联网文本免费提供了数十亿个这样的"自监督"训练样本。

这个范式转变的影响是颠覆性的:

  • 特征工程消失了 —— 预训练模型自己学出了特征表示
  • 小数据任务不再绝望 —— 微调只需要几百到几千条标注
  • 一个模型通吃多任务 —— 同一个预训练模型微调一下就能做分类、问答、摘要
  • 规模带来质变 —— 模型越大、数据越多,下游任务表现越好(后来被总结为 Scaling Laws)

语言模型基础

在讲 GPT 和 BERT 之前,需要搞清一个核心概念:语言模型(Language Model)

语言模型的任务很朴素——给定一个词序列,估计它出现的概率:

P(x1,x2,,xT)P(x_1, x_2, \ldots, x_T)

用链式法则展开:

P(x1,x2,,xT)=t=1TP(xtx1,x2,,xt1)P(x_1, x_2, \ldots, x_T) = \prod_{t=1}^{T} P(x_t \mid x_1, x_2, \ldots, x_{t-1})

每一步都在回答同一个问题:给定前面所有的词,下一个词是什么? 这就是"预测下一个 token"。

注意这里说的是 token 而不是"词"。现代语言模型用 子词分词(BPE / SentencePiece)把文本切成比词更细的单元。比如 "unhappiness" 可能被切成 "un" + "happi" + "ness"。这样做的好处是:词表大小可控(通常 32K-128K),同时能处理任何新词——没见过的词总能被拆成见过的子词。

语言模型的训练不需要任何标注——原始文本本身就包含了所有监督信号。每一个 token 的"标签"就是它自己,而"输入"就是它前面的所有 token。这就是自监督学习(self-supervised learning):数据自己提供标签。

为什么"预测下一个词"能学到这么多?

因为要准确预测下一个词,模型被迫理解越来越深层的东西:

  • 预测 "北京是中国的___" → 需要事实知识(首都)
  • 预测 "他虽然很累,___还是坚持跑完" → 需要语法(但/却)
  • 预测 "如果 A > B 且 B > C,那么 A ___ C" → 需要逻辑推理(>)
  • 预测 "她说完这句话,转身就走了。他愣在原地,___" → 需要情感理解

预测任务看似简单,但要做好它,模型必须内化语言的几乎所有层面。这就是预训练的力量。

GPT:单向 Transformer

GPT(Generative Pre-trained Transformer) 的核心思想极其简单:拿一个 Transformer 的 decoder 做语言模型。

架构:Decoder-Only

GPT 使用 decoder-only 架构——去掉了原始 Transformer 的 encoder,只保留 decoder 的堆叠。如果你读过 Transformer 篇,你已经知道这个结构的核心:

  • 每个 block 包含 因果自注意力(causal self-attention) + FFN
  • 因果注意力用一个下三角掩码确保每个 token 只能看到自己和之前的 token
  • 这让模型天然适合自回归生成:从左到右,一个一个 token 地预测

因果掩码的数学表达:

Attention(Q,K,V)=softmax ⁣(QKdk+M)V\text{Attention}(Q, K, V) = \text{softmax}\!\left(\frac{QK^\top}{\sqrt{d_k}} + M\right) V

其中 Mij=0M_{ij} = 0jij \leq i(允许看),Mij=M_{ij} = -\inftyj>ij > i(禁止看)。加上 -\infty 后 softmax 输出为 0——未来的信息被完全屏蔽。

训练目标:因果语言模型(CLM)

给定一段文本 x1,x2,,xTx_1, x_2, \ldots, x_T,GPT 最大化:

LCLM=t=1TlogP(xtx1,,xt1;θ)\mathcal{L}_{\text{CLM}} = \sum_{t=1}^{T} \log P(x_t \mid x_1, \ldots, x_{t-1}; \theta)

每个位置 tt 的输出向量经过线性层 + softmax 变成词表上的概率分布,和真实 token 做交叉熵损失。整个训练过程可以完全并行——虽然推理是自回归的,但训练时所有位置的损失可以一次算出来(因为 causal mask 保证了每个位置看不到后面的答案)。

从 GPT-1 到 GPT-4

模型年份参数量层数关键突破
GPT-12018117M12证明"预训练 + 微调"可行
GPT-220191.5B48不微调也能做任务(zero-shot)
GPT-32020175B96In-context learning,few-shot 范式
GPT-42023未公开(传 ~1.8T MoE)未公开多模态,推理能力质变

GPT-1 的贡献是验证了预训练范式——在 BookCorpus 上预训练一个 12 层 Transformer,然后微调,在 9/12 个 NLP 基准上拿了最好成绩。

GPT-2 发现了一件有趣的事:模型够大就不需要微调了。直接给 prompt "TL;DR:" 它就能做摘要,给 "Translate English to French:" 就能翻译。虽然效果还不够好,但这暗示了模型在预训练中"附带"学会了很多任务。

GPT-3 把这个发现推到极致——175B 参数,用 in-context learning 取代微调:只需要在 prompt 里给几个例子(few-shot),模型就能做新任务。不改权重,不算梯度,纯靠推理时的"模式匹配"。这彻底改变了 NLP 的使用方式。

BERT:双向理解

BERT(Bidirectional Encoder Representations from Transformers) 走了一条完全不同的路:它用的是 Transformer 的 encoder,而且双向看

架构:Encoder-Only

BERT 使用标准的 Transformer encoder——和 decoder 的唯一区别是没有因果掩码。每个 token 的 注意力 可以看到序列中所有位置(包括后面的 token)。

这意味着当模型处理"机器学习很有趣"时,"学"这个 token 不仅能看到前面的"机器",也能看到后面的"习很有趣"。完整的上下文信息让 BERT 在理解任务上有天然优势。

训练目标 1:掩码语言模型(MLM)

但双向带来一个问题:你不能让模型"预测下一个词"了——因为它能看到答案!

BERT 的解决方案巧妙:随机遮住一些 token,让模型猜被遮住的是什么。这就是 Masked Language Model(MLM)

  1. 随机选择输入中 15% 的 token
  2. 其中 80% 替换为特殊标记 [MASK]
  3. 其中 10% 替换为随机 token
  4. 其中 10% 保持不变
  5. 模型要预测这 15% 位置的原始 token
LMLM=iMlogP(xix\M;θ)\mathcal{L}_{\text{MLM}} = - \sum_{i \in \mathcal{M}} \log P(x_i \mid \mathbf{x}_{\backslash \mathcal{M}}; \theta)

其中 M\mathcal{M} 是被 mask 的位置集合。注意和 GPT 的关键区别:GPT 的条件是 x<tx_{<t}(只有前文),BERT 的条件是 x\M\mathbf{x}_{\backslash \mathcal{M}}(除了被 mask 的位置,前后文都能看到)。

为什么不全部替换为 [MASK]?因为微调时输入里没有 [MASK] 标记——如果预训练时模型只学会了处理 [MASK],在真实文本上就会失效。混入随机替换和保持不变,让模型对每个位置都保持"警惕"。

训练目标 2:下一句预测(NSP)

BERT 还有第二个预训练任务——Next Sentence Prediction:给模型两个句子 A 和 B,预测 B 是不是 A 的真实下一句。

  • 50% 的情况下,B 是 A 的真实下一句(正例)
  • 50% 的情况下,B 是随机抽取的句子(负例)

NSP 的初衷是让模型理解句子间的关系,帮助问答、推理等任务。不过后来的研究(RoBERTa, 2019)发现 NSP 帮助不大甚至有害——去掉它效果反而更好。原因可能是随机抽的负例太容易区分,模型学会了走捷径(比如只看话题是否相关)。

为什么双向很重要

用一个例子感受差异。考虑句子:"他在银行存了一笔钱"和"河的两岸有很多银行"。

  • GPT(单向):处理到"银行"时,只能看到前面的"他在"或"河的两岸有很多"——第一句话里看到"他在",很难判断是金融还是河岸;第二句看到"河的两岸"才能判断
  • BERT(双向):处理"银行"时同时看到前后文——第一句的"存了一笔钱"和第二句的"河的两岸"都能用上,消歧义更准确

对于理解型任务(分类、问答、NER),双向信息至关重要。但双向也有代价——BERT 不能做生成。因为它看过了整个序列,没法自回归地一个个生成 token。

下面的交互组件直观对比了两种预训练方式的注意力模式。切换 GPT / BERT,悬停某个 token 看它能"看到"哪些位置:

因果注意力:每个 token 只能看到自己和左边的 token。悬停某行查看它的注意力范围。

输入序列因果注意力掩码 (下三角)1000000110000011100001111000111110011111101111111训练目标:预测下一个 token P(x_t | x₁, ..., x_{t-1})自回归 (Autoregressive) — 适合生成任务

GPT vs BERT 对比

把两种范式放在一起看:

GPTBERT
架构Decoder-only (Transformer decoder 堆叠)Encoder-only (Transformer encoder 堆叠)
注意力方向单向(因果掩码,只看左边)双向(无掩码,看所有位置)
训练目标因果语言模型 CLM:预测下一个 token掩码语言模型 MLM:还原被 mask 的 token
数学形式P(xtx<t)P(x_t \mid x_{<t})P(xix\M)P(x_i \mid \mathbf{x}_{\backslash \mathcal{M}})
训练效率每个 token 都参与损失计算只有 15% 被 mask 的 token 参与损失
擅长任务文本生成、对话、代码生成文本分类、问答、命名实体识别
是否能生成天然支持自回归生成不能直接生成(可以填空)
代表模型GPT 系列、LLaMA、ClaudeBERT、RoBERTa、ALBERT、DeBERTa
当前地位大模型的主流路线中小规模理解任务仍在广泛使用

一个常被忽略的区别是训练效率。GPT 的每个 token 都贡献一个损失项(预测下一个 token),BERT 只有被 mask 的 15% 贡献损失。这意味着同样多的训练数据,GPT 从每个 token 都学到了信息,BERT 浪费了 85%。这个效率差异在数据量达到万亿 token 时变得很关键。

还有一个架构层面的差异:BERT 的双向注意力无法使用 KV cache 优化。decoder-only 的推理可以把之前 token 的 key/value 缓存下来(参见 Transformer 篇),每一步只需要计算新 token。BERT 的每个 token 都要和所有 token 做注意力,缓存无法复用。当序列长度很长时,这个差距是数量级的。

微调与 Prompt

预训练给了我们一个"懂语言"的基础模型。但它不知道你想让它做什么——分类?问答?翻译?有两种方式告诉它。

方式一:微调(Fine-tuning)

这是 BERT 时代的标准做法:

  1. 拿预训练好的模型
  2. 在最后一层后面加一个任务特定的头(比如分类就加一个线性层)
  3. 用标注数据更新所有参数
  4. 每个任务都得到一个独立的模型
θ=argminθLtask(Dlabeled;θpretrained)\theta^* = \arg\min_\theta \mathcal{L}_{\text{task}}(\mathcal{D}_{\text{labeled}}; \theta_{\text{pretrained}})

微调的好处是效果好——几百条标注数据就能在特定任务上达到很高的准确率。坏处是每个任务需要单独一个模型。如果你有 100 个任务,就需要部署 100 个 BERT。

方式二:In-Context Learning(上下文学习)

GPT-3 开创了一种完全不同的范式——不改权重,用 prompt 定义任务

将以下句子翻译成英文:

句子:机器学习很有趣
翻译:Machine learning is fun

句子:今天天气真好
翻译:

模型看到了两个"示例",然后自然地续写出翻译结果。这就是 few-shot in-context learning:通过在 prompt 中给出几个示例,让模型理解任务格式并执行。

微调(Fine-tuning)In-Context Learning
是否改权重改(全部或部分)不改
需要多少数据几百到几千条标注0(zero-shot)到几十条(few-shot)
计算成本训练:高;推理:低训练:零;推理:高(长 prompt)
部署每个任务一个模型一个模型服务所有任务
效果特定任务上更好通用但不极致

为什么 GPT 路线最终胜出

2018-2020 年,BERT 在各种 NLP 排行榜上碾压 GPT——因为理解任务正是它的强项,而且微调后效果极好。BERT 一度看起来是更好的范式。

但从 2020 年的 GPT-3 开始,风向变了。几个关键因素让 decoder-only + 自回归生成成为大模型的主流选择:

  1. 生成能力是刚需 —— ChatGPT 证明了"对话"是 AI 最自然的交互方式,而 BERT 不能生成
  2. 规模效应更好 —— GPT 架构的训练效率更高(每个 token 都学),scaling law 显示 decoder-only 在大规模下收益更大
  3. 一个模型做所有事 —— in-context learning 消除了"每个任务一个模型"的部署噩梦
  4. 简洁性 —— decoder-only 只有一种 block,encoder-decoder 的复杂度在大规模下没有带来对应的收益
  5. 后训练的突破 —— RLHF(基于人类反馈的强化学习)让自回归模型学会了"听指令",弥补了 GPT 架构在理解任务上的劣势

今天,最强的大模型——GPT-4、Claude、Gemini、LLaMA、DeepSeek——全部都是 decoder-only 架构。BERT 并没有消失——它仍然是中小规模理解任务(搜索排序、文档分类、NER)的最佳选择,因为它小、快、微调效果好。但在"通向通用智能"这条路上,GPT 的路线赢了。

这个想法在前沿里