Encoder-only 架构与 BERT 家族:理解型大模型的构建方式
在 Transformer 的完整结构中,Encoder 与 Decoder 共同组成了一套既能理解文本、又能生成文本的模型框架。但在真实工业应用中,不同任务对模型能力的要求并不相同。有些任务需要模型不断生成新的词元,例如机器翻译、对话生成、文章续写;而另一些任务只需要模型读懂输入文本,然后给出判断、分类、标注或打分。
正是因为任务目标不同,Transformer 在后续发展中逐渐演化出了几类典型架构。其中第一类,就是专门面向文本理解任务的 Encoder-only 架构。这一方向最具代表性的模型,是 Google 在 2018 年提出的 BERT。
本文将系统梳理 Encoder-only 架构的设计动机、BERT 的核心训练任务、特殊 Token 的作用,以及“预训练 + 微调”这一改变 NLP 发展路径的技术范式。同时,我也会把一些常见疑问自然地融入解释中,例如:BERT 的伟大是否主要来自训练任务设计?微调时所谓“在顶层加一个分类器”到底是什么意思?Encoder-only 模型最后输出的矩阵又如何接到具体任务上?
一、从完整 Transformer 到 Encoder-only
1. Encoder 的特长:双向理解上下文
在原始 Transformer 中,Encoder 的职责是接收一段输入序列,并通过多层 Self-Attention 和前馈网络,为序列中的每个词元生成富含上下文信息的表示。
Encoder 的关键特点是:它的 Self-Attention 通常不限制词元之间的可见范围。对于输入序列中的任意一个词元,它既可以关注左侧上下文,也可以关注右侧上下文。也就是说,模型在表示一个词时,能够同时利用这个词前后的信息。
举例来说,对于句子:
我 今天 去 买 了 苹果
如果要理解“苹果”这个词的含义,模型不仅可以看到左侧的“我 今天 去 买 了”,也可以在条件允许时看到右侧可能出现的词。虽然这个例子右侧可能没有更多内容,但在更复杂的句子中,右侧上下文常常非常重要。例如:
He deposited some money in the bank(他在银行存了钱)
与:
He’s walking along the bank where he works at the bank(他在他工作的银行旁边的河岸上散步)
这里“bank”到底指金融机构还是河岸,需要依赖上下文判断。Encoder 的双向注意力机制,使模型更容易捕捉这种依赖关系。
因此,Encoder 更适合做一件事:深度理解输入文本。
2. Decoder 的特长:自回归生成
Decoder 的设计目标则不同。Decoder 通常带有 Causal Mask,也就是因果掩码。它的作用是:在预测当前位置时,只允许模型看到当前位置之前的词元,而不能看到未来词元。
这种限制非常符合文本生成的自然过程。生成句子时,模型必须从左到右逐个词元输出。在生成第 $t$ 个词元时,模型只能依赖前 $t-1$ 个已经生成的词元,而不能提前看到尚未生成的未来内容。
因此,Decoder 更适合做生成类任务,例如:
- 机器翻译;
- 文本摘要;
- 对话生成;
- 代码补全;
- 故事续写。
在这些任务中,模型不仅要理解输入,还要持续产生新的输出序列。
3. 为什么许多任务只需要 Encoder
然而,并不是所有 NLP 任务都需要生成新文本。很多任务的目标只是对输入文本进行理解,然后输出一个有限形式的结果。
例如:
- 情感分析:判断一句话是正面情绪还是负面情绪;
- 垃圾邮件分类:判断一封邮件是否为垃圾邮件;
- 新闻分类:判断一篇文章属于体育、科技、财经还是娱乐;
- 命名实体识别:标出句子中的人名、地名、机构名等;
- 词性标注:判断每个词的语法角色;
- 文本相似度计算:判断两句话语义是否接近;
- 自然语言推理:判断两句话之间是蕴含、矛盾还是中立关系。
这些任务有一个共同点:输出通常不是完整的自然语言序列,而是类别、标签、分数或结构化结果。
在这些场景下,Decoder 的逐词生成能力并不必要。更重要的是,Causal Mask 会限制模型只能看到左侧上下文,这反而可能削弱模型对完整上下文的理解能力。
于是,一个很自然的想法出现了:如果任务不需要生成,那么可以去掉 Decoder,只保留 Encoder。这就是 Encoder-only 架构 的核心动机。
Encoder-only 模型专注于文本表示和文本理解。它接收输入文本,输出每个词元或整个句子的向量表示,然后由额外的任务头完成分类、标注或匹配等下游任务。
二、BERT 的核心贡献:用自监督任务训练双向理解
1. BERT 的本质不是复杂结构,而是训练任务设计
很多人在学习 BERT 时会产生一个疑问:BERT 是否在网络结构上做了非常复杂的创新?它是不是本质上只是“更好的训练任务 + 普通 Transformer Encoder”?
这个判断基本是正确的。
从网络结构上看,BERT 使用的就是标准 Transformer 中的 Encoder 部分。它没有发明一种全新的注意力机制,也没有彻底改变 Encoder 的内部模块。BERT 使用的仍然是 Multi-Head Attention、残差连接、Layer Normalization 和前馈神经网络等组件。
BERT 真正重要的贡献在于:它设计了一套适合双向 Encoder 的预训练任务,使模型能够在海量无标注文本上学习通用语言理解能力。
换句话说,BERT 的关键不是“把 Transformer Encoder 改成了什么样子”,而是“如何让 Encoder 通过合适的任务学到真正的双向语义表示”。
这正是 BERT 的核心思想。
2. MLM:通过完形填空学习双向上下文
在 BERT 之前,许多语言模型采用从左到右的训练方式,即根据前文预测下一个词。这样的训练方式天然适合生成任务,但会带来一个限制:模型在预测某个词时,只能看到左侧上下文,无法利用右侧上下文。
这与 Encoder 的双向理解目标并不完全一致。如果模型要真正理解一个词,它往往需要同时参考左右两侧的信息。
为了解决这个问题,BERT 提出了 Masked Language Model,简称 MLM,中文常称为“掩码语言模型”。它的基本思想非常直观:让模型做完形填空。
具体来说,训练时从输入序列中随机选择一部分词元,将它们遮掩掉,然后让模型根据剩余上下文预测这些被遮掩的词元。
例如,原句可能是:
我 今天 去 买 了 苹果
训练输入可能变成:
我 今天 去
[MASK]了 苹果
模型的任务是根据上下文预测 [MASK] 位置原本最可能是什么词,例如“买”。
从数学上看,假设输入序列为:
$$x = (x_1, x_2, \dots, x_n)$$
其中一部分位置被替换为特殊标记 [MASK]。对于某个被遮掩位置 $i$,模型需要预测:
$$p(x_i \mid x_{\setminus i})$$
也就是在给定其他所有可见词元的情况下,估计原始词元 $x_i$ 的条件概率。
这与从左到右的语言模型不同。传统自回归语言模型通常建模:
$$p(x_i \mid x_1, x_2, \dots, x_{i-1})$$
即只依赖左侧上下文。而 MLM 允许模型利用左侧和右侧上下文,因此更符合“双向理解”的目标。
不过,MLM 的设计也需要注意训练和推理之间的一致性问题。
在训练阶段,模型会看到大量 [MASK] 标记。但在真实下游任务中,输入文本通常不会出现 [MASK]。如果训练时模型只学会处理 [MASK],而从未见过原始词元出现在被遮掩位置附近,就可能造成训练与微调之间的分布不一致。
为了缓解这个问题,BERT 对被选中的 15% 词元采取了三种处理策略:
- 80% 的概率替换为
[MASK]; - 10% 的概率替换为随机词;
- 10% 的概率保持原词不变。
这样做可以让模型不仅学会处理 [MASK],也学会在微调阶段面对普通输入文本。模型不能简单地把所有注意力都放在 [MASK] 上,而必须真正学习上下文表示。
3. NSP:学习句子之间的关系
MLM 主要关注句子内部词元之间的关系。但是,许多 NLP 任务需要理解两个句子之间的逻辑关系。
例如:
- 问答任务中,需要判断答案句是否回应了问题句;
- 自然语言推理中,需要判断前提句和假设句之间是否蕴含;
- 对话任务中,需要判断下一句是否合理;
- 文档检索中,需要判断查询和文档片段是否相关。
为了让模型理解句子级别的关系,BERT 在原始设计中引入了 Next Sentence Prediction,简称 NSP,即“下一句预测”。
训练时,模型会接收两个句子 A 和 B。其中:
- 50% 的情况下,B 是原文中紧跟在 A 后面的下一句,标签为
IsNext; - 50% 的情况下,B 是从语料中随机抽取的句子,标签为
NotNext。
模型需要判断这两个句子是否是相邻关系。
例如,一个正样本可能是:
句子 A:今天天气很好。
句子 B:我们决定去公园散步。
标签为 IsNext。
一个负样本可能是:
句子 A:今天天气很好。
句子 B:量子力学中的波函数描述系统状态。
标签为 NotNext。
NSP 的目标是让模型学会从整体语义层面判断两个句子是否连贯。这对一些需要句间推理的任务有帮助。
不过,后续研究发现,NSP 的收益并不总是显著。在一些改进模型中,例如 RoBERTa,NSP 被移除或替换为其他训练方式。这并不否定 BERT 原始设计的价值,只是说明预训练任务本身也在不断演化。
三、BERT 的输入表示与特殊 Token
1. [CLS]:用于聚合全局语义
BERT 的输入序列中通常会加入特殊 Token。其中最重要的是 [CLS] 和 [SEP]。
[CLS] 是 Classification 的缩写,通常放在整个输入序列的最开头。例如:
[CLS]我 喜欢 吃 苹果[SEP]
经过多层 Encoder 后,每个位置都会得到对应的向量表示。[CLS] 位置的向量也被更新。由于 Self-Attention 可以让每个位置与其他位置交互,[CLS] 在多层计算后能够聚合整个输入序列的信息。
因此,在很多句子级任务中,[CLS] 位置的输出向量被当作整个输入的全局语义表示。
如果输入是一个分类任务,例如情感分析,模型通常不会使用每个词的向量分别做预测,而是直接取出 [CLS] 向量,然后送入分类器。
假设最后一层 Encoder 输出的 [CLS] 向量为:
$$h_{CLS} \in \mathbb{R}^d$$
其中 $d$ 是隐藏层维度。分类器可以是一个线性层:
$$z = W h_{CLS} + b$$
其中,$W \in \mathbb{R}^{C \times d}$
$C$ 是类别数。对于二分类情感分析,$C=2$,输出分别对应正面和负面的 logits。
2. [SEP]:用于标记句子边界
[SEP] 是 Separator 的缩写,用于告诉模型某个句子在哪里结束,或者两个句子在哪里分开。
对于单句输入,形式可能是:
[CLS]我 喜欢 吃 苹果[SEP]
对于双句输入,形式可能是:
[CLS]我 喜欢 吃 苹果[SEP]它 很 甜[SEP]
这样,模型可以明确知道第一个句子和第二个句子的边界。
在 NSP、自然语言推理、问答等任务中,双句输入非常常见。[SEP] 为模型提供了结构信息,使它能够区分两个句子的范围。
3. 输入不只是词向量
值得注意的是,BERT 的输入并不只是简单的词 Embedding。通常,每个输入 Token 的最终嵌入由几部分相加得到:
- Token Embedding:词元本身的向量;
- Segment Embedding:区分属于第一个句子还是第二个句子;
- Position Embedding:表示词元在序列中的位置。
对于双句输入,Segment Embedding 可以帮助模型区分句子 A 和句子 B。Position Embedding 则保留序列顺序信息。
虽然 Self-Attention 本身具有置换等变性,也就是说,如果不加入位置信息,它无法区分词序,因此位置编码是必要的。BERT 使用的是可学习的位置嵌入,而不是原始 Transformer 中的正弦位置编码,但这并不影响其核心目标:让模型知道每个 Token 的位置和所属句子。
四、预训练 + 微调:从通用语言能力到具体任务
1. 预训练阶段:让模型接受通识教育
在 BERT 之前,许多 NLP 模型通常针对具体任务从头训练。任务需要大量标注数据,而高质量标注数据往往昂贵且有限。
BERT 带来的重要变化是:先在海量无标注文本上进行预训练,再在具体任务上进行微调。
预训练阶段的数据可以来自大规模语料,例如网页、书籍、维基百科等。由于 MLM 和 NSP 可以自动构造训练目标,因此不需要人工逐条标注。
这属于自监督学习。所谓自监督,并不是完全没有监督信号,而是监督信号来自数据本身。
例如,在 MLM 中,原始词元本身就是标签。模型预测被遮盖的词,原始词提供了正确答案。在 NSP 中,两句话是否相邻也可以从语料中自动获得。
预训练的目标不是直接解决某个具体任务,而是让模型学习语言的通用规律,包括:
- 词法和句法结构;
- 词语搭配关系;
- 上下文语义关联;
- 指代和省略;
- 常识性知识;
- 句间关系。
预训练完成后,模型得到一个通用的语言表示模型。例如,BERT-base 通常包含 12 层 Transformer Encoder,隐藏维度为 768。它此时并不知道什么是情感分析,也不知道什么是命名实体识别,但它已经具备了较强的文本理解能力。
2. 微调阶段:让模型适应具体任务
预训练模型不能直接输出下游任务的答案。比如,对于情感分析任务,模型需要知道输出应该是“正面”或“负面”;对于命名实体识别任务,模型需要知道每个词是否属于人名、地名、机构名等。
因此,需要在预训练模型的基础上进行微调。
微调阶段通常使用少量带标签的下游任务数据。例如,对于电影评论情感分析,可能有 10000 条评论,每条评论都标有“正面”或“负面”。
微调时,一般在 BERT 的输出之上加入任务特定的输出层。对于分类任务,这个输出层通常是一个线性分类器。
所谓“在顶层加一个分类器”,可以从数据流动的角度理解。
假设输入序列长度为 $n$,BERT 的隐藏层维度为 $d$。经过最后一层 Encoder 后,输出矩阵形状为:
$$ H \in \mathbb{R}^{n \times d} $$
如果考虑 batch 维度,则形状为:
$$ H \in \mathbb{R}^{B \times n \times d} $$
其中 $B$ 是 batch size。
“顶层”通常指最后一层 Encoder 的输出。它已经完成了对输入文本的上下文编码。接下来,根据任务目标,从这个顶层输出中取出需要的向量,再接入新的任务头。
“加”一个分类器,并不是把分类器插入 Encoder 内部,而是在 Encoder 输出之后连接一个新的模块。这个模块通常很简单,例如一个线性层:
$$ \text{Linear}(d, C) $$
其中 $C$ 是类别数。
对于二分类情感分析,可以写为:
$$ \text{Linear}(768, 2) $$
如果取 [CLS] 向量 $h_{CLS}$,则:
$$ z = W h_{CLS} + b $$
输出 $z \in \mathbb{R}^2$。经过 softmax 后可以得到:
$$ p = \text{softmax}(z) $$
其中 $p_1$ 表示正面概率,$p_2$ 表示负面概率。
微调时,通常会用较小的学习率同时更新 BERT 参数和新增分类器参数。因为 BERT 已经在预训练中获得了良好的语言表示,所以只需要轻微调整,而不适合剧烈更新。
3. 端到端微调与冻结参数
在标准微调中,BERT 的所有 Encoder 层和新增分类器都会参与训练。这种方式称为端到端微调。
但有时也会采用另一种方式:冻结 BERT 的主体参数,只训练顶层新增的分类器。也就是说,Encoder 的权重不再更新,只有新加入的任务头更新。
这种做法可以称为特征提取式微调,或者线性探测。它的优点是训练成本低,计算量小,在小数据场景下不容易过拟合。缺点是模型不能针对具体任务进一步调整底层和中间层表示,特征适配能力较弱。
端到端微调的优点是模型可以根据任务数据继续优化表示,通常效果更好。缺点是训练成本更高,且在小数据集上可能过拟合。
因此,在实践中需要根据数据规模、任务复杂度、计算资源和模型规模进行选择。
五、Encoder-only 模型的输出如何接到任务上
1. Encoder-only 模型的目标不是生成
Encoder-only 架构的设计重点通常不是生成连续文本,而是理解和表示文本。它更适合判别式任务,例如分类、匹配、标注、检索和抽取。
这并不是说 Encoder-only 模型完全不能参与生成过程。例如,它可以为生成系统提供表示,或者通过 MLM 进行局部填空。但从主流使用方式看,Encoder-only 模型通常不会像 Decoder-only 模型那样直接自回归地生成完整文本。
因此,可以简单地说:Encoder-only 架构主要面向理解、分类、识别、匹配等非自回归生成任务。
2. 句子级任务:使用 [CLS] 向量
对于句子级任务,模型最终需要给出整个输入的判断结果。
典型任务包括:
- 情感分类;
- 垃圾邮件识别;
- 新闻主题分类;
- 文本相似度判断;
- 自然语言推理;
- 双句关系分类。
这些任务通常不需要知道每个词的标签,只需要知道整个句子或句子对的整体类别。
因此,常用做法是取出 [CLS] 位置的向量,然后接分类器。
假设最后一层 Encoder 输出为:
$$ H = [h_{CLS}, h_1, h_2, \dots, h_n] $$
其中每个 $h_i \in \mathbb{R}^d$。
句子级分类只取:
$$ h_{CLS} $$
然后计算:
$$ z = W_{cls} h_{CLS} + b_{cls} $$
如果任务是二分类,则 $z$ 是二维向量;如果是十分类,则 $z$ 是十维向量。
训练时通常使用交叉熵损失:
$$ \mathcal{L} = - \sum_{c=1}^{C} y_c \log p_c $$
其中 $y$ 是真实标签的 one-hot 向量,$p$ 是 softmax 后的预测概率。
3. Token 级任务:使用每个词元的输出
另一类任务需要对序列中的每个词元做预测。
典型任务包括:
- 命名实体识别;
- 词性标注;
- 分词;
- 序列标注;
- 槽位填充。
例如,在命名实体识别中,输入:
张 三 去 北 京 大 学 参观
模型可能需要输出:
张:B-PER
三:I-PER
去:O
北:B-ORG
京:I-ORG
大:I-ORG
学:I-ORG
参:O
观:O
这里每个词元都有自己的标签。因此,不能只使用 [CLS] 向量,而需要使用每个词元对应的输出向量。
假设序列长度为 $n$,每个词元向量为 $h_i$。Token 级分类器为:
$$ W_{token} \in \mathbb{R}^{L \times d} $$
其中 $L$ 是标签数量。
对每个位置 $i$,计算:
$$ z_i = W_{token} h_i + b_{token} $$
得到该位置的标签 logits。然后对每个位置使用交叉熵损失,并将所有位置的损失求平均或求和。
也就是说,同一个分类矩阵会被应用到每个 Token 的向量上。
如果输入有 10 个 Token,输出就是 10 个预测结果;如果有 100 个 Token,输出就是 100 个预测结果。
4. 分类器与 LM Head 的共性
在生成式语言模型中,常见组件叫 LM Head。它的作用是把模型顶层隐藏状态映射到词表大小的空间,然后预测下一个词。
例如,如果词表大小是 30000,LM Head 通常是一个线性层:
$$ \text{Linear}(d, 30000) $$
输出 30000 维 logits,表示词表中每个词的概率。
在 Encoder-only 模型中,分类器或标注头的作用类似,只不过输出空间不同。
- LM Head:输出词表大小的概率分布,用于生成下一个词;
- 分类器:输出类别数,用于句子分类;
- Token 标注头:输出标签数,用于序列标注。
从形式上看,它们都是接在 Transformer 顶层输出之后的线性映射。本质上都是通过矩阵乘法将隐藏向量投影到任务需要的目标空间。
因此,可以将它们统一理解为“任务头”。Transformer Encoder 负责生成高质量上下文表示,任务头负责把这些表示转换成具体预测结果。
六、为什么 Encoder-only 架构如此重要
1. 它确立了理解型大模型的基本范式
BERT 之后,NLP 领域逐渐形成了清晰的技术路线:先用大规模无标注语料训练通用表示模型,再用少量标注数据适配下游任务。
这种方式显著降低了具体任务对大规模标注数据的依赖。只要任务可以被转化为文本输入和向量输出,就可以尝试在预训练模型基础上微调。
这使得许多小数据任务也能获得显著性能提升。
2. 它把特征工程变成了表示学习
传统 NLP 系统中,研究者经常需要手工设计特征,例如词袋特征、n-gram、词性特征、句法树、规则模板等。
Encoder-only 模型改变了这一过程。模型通过 Self-Attention 自动学习上下文表示,不再依赖大量人工特征工程。
输入文本经过 Encoder 后,每个 Token 都会得到上下文化向量。这些向量可以直接用于分类、匹配、标注等任务。
3. 它推动了预训练模型生态的发展
BERT 之后,出现了大量基于 Encoder-only 的改进模型,例如:
- RoBERTa;
- ALBERT;
- ELECTRA;
- DeBERTa;
- SpanBERT。
这些模型在分词方式、预训练任务、位置编码、训练数据、模型结构等方面进行了不同方向的改进,但整体仍然延续了 Encoder-only 或理解型预训练模型的基本思路。
七、总结
Encoder-only 架构的核心思想可以概括为一句话:如果任务的目标不是生成文本,而是理解文本,那么可以只保留 Transformer 的 Encoder,并设计合适的预训练任务,使模型获得强大的双向语义表示能力。
BERT 是这一架构的代表。它的网络结构本身并不复杂,主要使用标准 Transformer Encoder。它真正重要的贡献在于提出了 MLM 和 NSP 等自监督预训练任务,使模型能够利用海量无标注文本学习语言理解能力。
MLM 通过完形填空迫使模型同时利用左右上下文,从而学习真正的双向表示。NSP 则尝试让模型理解两个句子之间的关系。特殊 Token [CLS] 和 [SEP] 分别承担了全局语义聚合和句子边界标记的作用。
在应用层面,BERT 确立了“预训练 + 微调”的范式。预训练阶段让模型学习通用语言能力,微调阶段用少量标注数据让模型适应具体任务。对于句子级任务,通常使用 [CLS] 向量接分类器;对于 Token 级任务,则使用每个 Token 的输出向量接标注头。
从更一般的角度看,无论是生成式模型中的 LM Head,还是理解式模型中的分类器、标注头,它们本质上都是接在 Transformer 顶层表示之后的线性映射模块。区别只在于输出空间和任务目标不同:LM Head 面向词表预测,分类器面向类别预测,标注头面向序列标签预测。
理解了 Encoder-only 架构,就理解了 BERT 家族模型的基本逻辑:用双向注意力构建上下文表示,用自监督任务学习语言能力,用任务头连接具体应用。
这也为后续理解 Decoder-only 架构与 GPT 家族打下了重要基础。BERT 强调双向理解,而 GPT 强调自回归生成。两条路线从不同方向推动了大模型的发展,并最终共同塑造了今天的语言模型生态。