文章目录
- 一、为什么需要BERT?传统方法的局限
-
- [1.1 传统RNN网络的问题](#1.1 传统RNN网络的问题)
- [1.2 传统word2vec的问题](#1.2 传统word2vec的问题)
- 二、BERT框架概述
- 三、Transformer基础架构
-
- [3.1 Encoder-Decoder编码解码框架](#3.1 Encoder-Decoder编码解码框架)
- [3.2 Self-Attention自注意力机制](#3.2 Self-Attention自注意力机制)
- [3.3 Multi-Head Attention多头注意力](#3.3 Multi-Head Attention多头注意力)
- [3.4 多层堆叠](#3.4 多层堆叠)
- [3.5 位置编码(Positional Encoding)](#3.5 位置编码(Positional Encoding))
- [3.6 Add & Norm 残差与归一化](#3.6 Add & Norm 残差与归一化)
- [3.7 Transformer整体框架](#3.7 Transformer整体框架)
- [3.8 Decoder的Shifted Right操作](#3.8 Decoder的Shifted Right操作)
- 四、BERT预训练任务详解
-
- [4.1 Masked Language Model(MLM)遮蔽语言模型](#4.1 Masked Language Model(MLM)遮蔽语言模型)
- [4.2 Next Sentence Prediction(NSP)下一句预测](#4.2 Next Sentence Prediction(NSP)下一句预测)
- 五、BERT模型变体与参数规格
- 六、BERT微调与下游应用
- 七、总结
一、为什么需要BERT?传统方法的局限
在BERT出现之前,NLP领域主要面临两大痛点:传统RNN的串行计算瓶颈 与word2vec词向量的静态表示问题。
1.1 传统RNN网络的问题
RNN(循环神经网络)通过隐藏状态 h 1 → h 2 → ⋯ → h m h_1 \rightarrow h_2 \rightarrow \dots \rightarrow h_m h1→h2→⋯→hm 依次处理序列,存在以下缺陷:
- 串行依赖导致训练慢 :必须等 h 1 h_1 h1 计算完成才能计算 h 2 h_2 h2,无法并行化,序列越长训练时间越长。
- 并行计算效果差:难以在多台服务器上同时训练同一个网络,无法充分利用GPU集群。
1.2 传统word2vec的问题
- 词向量训练好后不再改变:无论上下文如何,同一个词的向量永远相同。
- 无法区分多义词:不同语境下的同一词语含义不同,但共享同一个向量。例如"机车"在台湾俚语中指"罗嗦",而在普通话中指"摩托车",静态向量无法区分。
核心结论 :我们需要一种能根据上下文动态生成词向量 、并且可以并行计算的模型架构------这正是Transformer与BERT诞生的背景。
二、BERT框架概述
BERT (B idirectional E ncoder R epresentations from Transformers)是基于Transformer编码器的双向预训练语言模型。
| 特性 | 说明 |
|---|---|
| 模型结构 | 基于Transformer的Encoder部分,采用多层自注意力机制和前馈神经网络 |
| 核心能力 | 预训练学习丰富的语言表示,可迁移到各类NLP下游任务 |
| 预训练任务 | 遮蔽语言模型(MLM)+ 下一句预测(NSP) |
| 双向性 | 预测一个词时同时考虑左右两侧上下文(区别于GPT的单向自回归) |
| 微调方式 | 在特定任务数据集上进一步训练,适配下游任务 |
| 历史影响 | 刷新11项NLP基准测试记录,奠定预训练模型范式,催生RoBERTa、ALBERT等后续工作 |
三、Transformer基础架构
BERT的核心骨架是Transformer的Encoder部分。要理解BERT,必须先理解Transformer。
3.1 Encoder-Decoder编码解码框架
Encoder-Decoder(编码-解码)是大部分注意力模型的基础框架,主要用于处理序列到序列(Seq2Seq) 问题------输入一个序列,输出另一个序列,且两个序列长度可以不同。
典型应用场景:
- 机器翻译:输入英文序列 → 输出中文序列
- 文本摘要:输入文章全文 → 输出摘要
- 问答系统:输入问题 → 输出答案
工作流程:
输入序列 <x1, x2, ..., xn> → [Encoder] → 语义编码C → [Decoder] → 输出序列 <y1, y2, ..., ym>
- Encoder(编码器):将输入序列编码为一个语义向量C,C中存储了整个输入序列的信息。传统实现可用RNN/LSTM/GRU/BiLSTM等。
- Decoder(解码器):根据语义编码C,逐步解码生成输出序列。
- 编码与解码方式可任意组合:Encoder用BiLSTM,Decoder用GRU,完全可以。
通俗理解:翻译"Bonjour"时,大脑先把这个词的概念提取出来(编码),再从英语词库中找到对应的"Hello"(解码)。提取出来的"概念"就是语义向量C。
3.2 Self-Attention自注意力机制
核心问题:一句话中哪些词是重点?如何让计算机自动关注到话语中的关键词?
Self-Attention(自注意力)通过让每个词与序列中所有词计算关联程度,动态捕捉上下文语义。
第一步:构造Q、K、V三个矩阵
输入词向量通过三个可训练的权重矩阵 W Q W^Q WQ、 W K W^K WK、 W V W^V WV 分别投影得到:
- Q(Query,查询):当前词"主动查询"其他词
- K(Key,键):其他词"等待被查询"的特征
- V(Value,值):其他词实际携带的信息特征
q i = x i ⋅ W Q , k i = x i ⋅ W K , v i = x i ⋅ W V q_i = x_i \cdot W^Q, \quad k_i = x_i \cdot W^K, \quad v_i = x_i \cdot W^V qi=xi⋅WQ,ki=xi⋅WK,vi=xi⋅WV
第二步:计算注意力得分
每个词的Q与序列中所有词的K计算内积,表示匹配程度:
Score ( q i , k j ) = q i ⋅ k j \text{Score}(q_i, k_j) = q_i \cdot k_j Score(qi,kj)=qi⋅kj
- q 1 ⋅ k 1 q_1 \cdot k_1 q1⋅k1:第1个词与自身的匹配度
- q 1 ⋅ k 2 q_1 \cdot k_2 q1⋅k2:第1个词与第2个词的匹配度
第三步:归一化(Scaling)
直接内积在维度较大时数值会很大,导致Softmax梯度消失。因此除以 d k \sqrt{d_k} dk 进行缩放:
Attention ( Q , K , V ) = Softmax ( Q K T d k ) V \text{Attention}(Q, K, V) = \text{Softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V Attention(Q,K,V)=Softmax(dk QKT)V
其中 d k d_k dk 是K向量的维度。这一步归一化的作用是:防止维度增大导致内积值过大,保持梯度稳定。
第四步:加权求和
归一化后的注意力权重与V相乘求和,得到每个词的最终特征表示 z i z_i zi。
关键特性 :每个词的Q会与整个序列中每一个K计算得分,再基于得分分配V的权重。因此同样的词在不同句子中会得到不同的特征向量------这正是解决word2vec静态表示问题的核心。
并行优势:Q、K、V矩阵可以一次性并行计算,完全避免了RNN的串行依赖,极大提升了训练速度。
3.3 Multi-Head Attention多头注意力
卷积神经网络中用多组卷积核提取不同特征图。同理,Transformer中用多组Q、K、V可以得到多种词的特征表达。
多头机制的工作流程:
- 拆分多头 :将 d m o d e l d_{model} dmodel 维的Q、K、V拆分为 h h h 个低维子空间(通常 h = 8 h=8 h=8),每个头独立计算Attention。
- 并行计算 :每个头独立输出 Z 0 , Z 1 , ... , Z h − 1 Z_0, Z_1, \dots, Z_{h-1} Z0,Z1,...,Zh−1,分别关注不同的语义信息(有的头关注语法,有的头关注指代关系)。
- 拼接 :将所有头的输出沿特征维度拼接: Concat ( Z 0 , Z 1 , ... , Z h − 1 ) \text{Concat}(Z_0, Z_1, \dots, Z_{h-1}) Concat(Z0,Z1,...,Zh−1)。
- 线性降维 :拼接后通过一个全连接层 W O W^O WO 降维,得到最终输出。
MultiHead ( Q , K , V ) = Concat ( head 1 , ... , head h ) W O \text{MultiHead}(Q, K, V) = \text{Concat}(\text{head}_1, \dots, \text{head}_h) W^O MultiHead(Q,K,V)=Concat(head1,...,headh)WO
其中 head i = Attention ( Q W i Q , K W i K , V W i V ) \text{head}_i = \text{Attention}(QW_i^Q, KW_i^K, VW_i^V) headi=Attention(QWiQ,KWiK,VWiV)。
3.4 多层堆叠
单层Self-Attention的表达能力有限,实际使用时将多个Encoder Layer堆叠起来(类似CNN堆多层卷积):
输入Embedding → [Encoder Layer 1] → [Encoder Layer 2] → ... → [Encoder Layer N] → 输出表示
BERT-base堆叠了12层,BERT-large堆叠了24层。层数越多,模型能捕捉的语义层次越深。
3.5 位置编码(Positional Encoding)
问题:Self-Attention本身是"无序"的------它只关心句子中有哪些词,不关心词的顺序。但语序对语言至关重要("我打你" vs "你打我")。
因此必须引入位置信息。
方法一:0-1范围归一化位置
我喜欢吃洋葱 → [0, 0.16, 0.32, ..., 1.0]
我真的不喜欢吃洋葱 → [0, 0.125, 0.25, ..., 1.0]
缺陷:句子长度不同,相同位置的编码值不同,无法跨句子比较位置。
方法二:1-n正整数编号
我喜欢吃洋葱 → [1, 2, 3, 4, 5, 6]
我真的不喜欢吃洋葱 → [1, 2, 3, 4, 5, 6, 7]
缺陷:句子越长,后面的数字越大,导致位置权重被数值大小扭曲。
方法三:三角函数位置编码(Transformer采用)
Transformer作者设计了基于正弦/余弦的位置编码公式:
P E ( p o s , 2 i ) = sin ( p o s 10000 2 i / d m o d e l ) PE_{(pos, 2i)} = \sin\left(\frac{pos}{10000^{2i/d_{model}}}\right) PE(pos,2i)=sin(100002i/dmodelpos)
P E ( p o s , 2 i + 1 ) = cos ( p o s 10000 2 i / d m o d e l ) PE_{(pos, 2i+1)} = \cos\left(\frac{pos}{10000^{2i/d_{model}}}\right) PE(pos,2i+1)=cos(100002i/dmodelpos)
- pos:词在句子中的位置(从0开始)
- d m o d e l d_{model} dmodel:词向量的维度
- i i i :维度索引( i = 0 , 1 , ... , d m o d e l / 2 − 1 i = 0, 1, \dots, d_{model}/2 - 1 i=0,1,...,dmodel/2−1)
- 偶数维 用sin,奇数维用cos
最终输入 :将词向量(Word Embedding)与位置编码(Positional Encoding)逐点相加:
Input = WordEmbedding + PositionalEncoding \text{Input} = \text{WordEmbedding} + \text{PositionalEncoding} Input=WordEmbedding+PositionalEncoding
优点:
- PE值分布在 − 1 , 1 -1, 1 −1,1 区间,不会随序列长度增长而放大。
- 不同句子中相同位置的PE值相同(如pos=0时PE=0),具有跨句子的泛化能力。
- 相对位置可被学习: P E p o s + k PE_{pos+k} PEpos+k 可以表示为 P E p o s PE_{pos} PEpos 的线性函数。
3.6 Add & Norm 残差与归一化
每个Encoder Layer内部包含两个关键操作:
-
Add(残差连接) :将Attention的输入直接加到输出上(类似ResNet的shortcut),缓解深层网络梯度消失问题。
Output = Sublayer ( x ) + x \text{Output} = \text{Sublayer}(x) + x Output=Sublayer(x)+x
-
Norm(Layer Normalization):对每个样本的特征做归一化,加速收敛、稳定训练。
完整子层结构:
x → Multi-Head Attention → Add(x + attn_output) → Norm → Feed Forward → Add → Norm → 输出
3.7 Transformer整体框架
Transformer整体由Encoder堆栈和Decoder堆栈组成:
- Encoder侧:N层Encoder Layer,每层包含 Multi-Head Attention + Feed Forward(两层全连接)。
- Decoder侧:N层Decoder Layer,包含 Masked Multi-Head Attention + Encoder-Decoder Attention + Feed Forward。
- Feed Forward层:一个两层的全连接神经网络,中间激活函数为ReLU/GELU。
重要区分 :BERT只用了Encoder部分,没有Decoder。这是BERT与GPT(只用Decoder)、原始Transformer(两者都用)的核心结构区别。
3.8 Decoder的Shifted Right操作
Decoder在训练时使用"Shifted Right"技巧:
- 将目标输出序列右移一位,最左侧添加起始符
<sos>(Start Of Sentence)。 - 训练时解码器以
<sos>开头,逐步预测下一个词。
示例(中译英任务):
- 输入:我爱中国
- 目标输出:I love China
- Decoder输入(shifted right):
<sos> I love China - Decoder输出预测:
I love China <eos>
这样解码器在生成每个词时,都能基于已经生成的前缀进行预测,实现自回归生成。
四、BERT预训练任务详解
BERT在大规模无标注语料上进行预训练,使用两个自监督任务:
4.1 Masked Language Model(MLM)遮蔽语言模型
核心思想:随机遮蔽输入中15%的词,让模型根据上下文预测被遮蔽的词。这就是"完形填空"任务。
15%的Masking策略细节(BERT论文的重要设计):
被选中的15%的词中:
- 80% 替换为
[MASK]标记,如"我今天去面试" → "我MASK天去MASK试" - 10% 随机替换为另一个词(防止模型过度依赖MASK标记)
- 10% 保持原词不变(降低预训练与微调的差距)
为什么按字Mask而不是按词Mask?
因为词的组合太多(今天、明天、后天、上午、下午......),按字Mask的预测空间更小,模型更容易学。
双向性的体现:预测被Mask的词时,模型同时看到左右两侧的上下文------这正是BERT"双向"的含义。
4.2 Next Sentence Prediction(NSP)下一句预测
核心思想:判断两个句子A和B在原文中是否是连续的上下句。
输入构造:
[CLS] 句子A [SEP] 句子B [SEP]
正样本(Label = IsNext):
[CLS] 我今天去面试 [SEP] 准备好了简历 [SEP] → Label: yes
负样本(Label = NotNext):
[CLS] 我今天去面试 [SEP] 中午吃了包子 [SEP] → Label: no
特殊标记说明:
| 标记 | 全称 | 作用 |
|---|---|---|
[CLS] |
Classification Token | 放在序列开头,最终输出用于分类任务;训练中也作为一个普通token参与学习 |
[SEP] |
Separator Token | 分隔两个句子,或表示单句结束 |
[MASK] |
Mask Token | MLM任务中被遮蔽的位置 |
为什么需要NSP?
许多下游任务(如问答QA、自然语言推理NLI)需要理解句子间的关系,NSP让模型学到句间连贯性,而不仅仅是单词语义。
五、BERT模型变体与参数规格
BERT论文中发布了两个版本:
| 模型规格 | 层数(Encoder) | 隐藏维度 | Attention头数 | 参数量 | 适用场景 |
|---|---|---|---|---|---|
| BERT-base | 12 | 768 | 12 | ~110M | 日常微调、资源有限场景 |
| BERT-large | 24 | 1024 | 16 | ~340M | 追求SOTA效果、算力充足场景 |
其他关键超参数:
- 最大序列长度:512 tokens
- Batch Size:128,000 words
- 训练步数:1,000,000步
- 训练数据:BooksCorpus(8亿词)+ English Wikipedia(25亿词)
- 优化器:Adam, β 1 = 0.9 \beta_1=0.9 β1=0.9, β 2 = 0.999 \beta_2=0.999 β2=0.999, LR = 1 e − 4 \text{LR}=1e-4 LR=1e−4
- Warmup Steps:10,000
六、BERT微调与下游应用
预训练完成后,BERT可以通过微调(Fine-tuning) 适配各类下游NLP任务。微调时将预训练参数初始化,用下游任务数据继续训练即可。
常见下游任务与微调方式
| 任务类型 | 输入示例 | 微调方式 |
|---|---|---|
| 文本分类 | 单句 → 情感/主题类别 | 取[CLS]输出接分类层 |
| 命名实体识别(NER) | 句子 → 每个词的实体标签 | 对每个token输出接分类层 |
| 问答系统(QA) | 问题+段落 → 答案起止位置 | 预测答案的start/end span |
| 自然语言推理(NLI) | 前提+假设 → 蕴含/矛盾/中立 | 用[CLS]做句对分类 |
| 文本相似度 | 句子A+句子B → 相似度分数 | 句对表示接回归层 |
BERT的灵活性:只需在Encoder输出后接一个简单的任务层(分类层/span预测层等),几乎所有NLP任务都能适配------这是BERT通用性强的根本原因。
七、总结
- BERT的本质:一个基于Transformer Encoder的双向预训练语言模型,通过MLM和NSP两个自监督任务学习深层语言表示。
- 技术突破 :
- 双向上下文建模( vs GPT的单向)
- Self-Attention并行计算( vs RNN的串行)
- 预训练+微调范式(取代任务定制模型)
- 关键组件:Self-Attention → Multi-Head → 位置编码 → 残差连接 → LayerNorm → 多层堆叠。
BERT的历史地位
BERT开启了NLP的"预训练时代",后续涌现了大量改进模型:
- RoBERTa:去掉NSP、更大batch、更多数据,进一步提升效果
- ALBERT:缩小参数量(跨层参数共享、词向量分解),提升训练效率
- DistilBERT:模型蒸馏,参数量减少40%,速度提升60%,保留97%效果
- GPT系列:Decoder路线的自回归预训练,走向生成式AI