文章目录
- 一、为什么需要BERT?传统方法的局限
-
- 1.1 传统RNN网络的问题
- 1.2 传统word2vec的问题
- 二、BERT框架概述
- 三、Transformer基础架构
-
- 3.1 Encoder-Decoder编码解码框架
- 3.2 Self-Attention自注意力机制
-
- 第一步:构造Q、K、V三个矩阵
- 第二步:计算注意力得分
- 第三步:归一化(Scaling)
- 第四步:加权求和
- 3.3 Multi-Head Attention多头注意力
- 3.4 多层堆叠
- 3.5 位置编码(Positional Encoding)
-
- 方法一:0-1范围归一化位置
- 方法二:1-n正整数编号
- 方法三:三角函数位置编码(Transformer采用)
- 3.6 Add & Norm 残差与归一化
- 3.7 Transformer整体框架
- 3.8 Decoder的Shifted Right操作
- 四、BERT预训练任务详解
-
- 4.1 Masked Language Model(MLM)遮蔽语言模型
- 4.2 Next Sentence Prediction(NSP)下一句预测
- 五、BERT模型变体与参数规格
- 六、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,无法并行化,序列越长训练时间越长。
1.2 传统word2vec的问题
核心结论:我们需要一种能根据上下文动态生成词向量、并且可以并行计算的模型架构——这正是Transformer与BERT诞生的背景。
二、BERT框架概述
BERT(Bidirectional Encoder Representations 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
优点:
[
−
1
,
1
]
[-1, 1]
[−1,1] 区间,不会随序列长度增长而放大。
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论文中发布了两个版本:
| 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通用性强的根本原因。
七、总结
- 双向上下文建模( vs GPT的单向)
- Self-Attention并行计算( vs RNN的串行)
- 预训练+微调范式(取代任务定制模型)
BERT的历史地位
BERT开启了NLP的"预训练时代",后续涌现了大量改进模型:
- RoBERTa:去掉NSP、更大batch、更多数据,进一步提升效果
- ALBERT:缩小参数量(跨层参数共享、词向量分解),提升训练效率
- DistilBERT:模型蒸馏,参数量减少40%,速度提升60%,保留97%效果
- GPT系列:Decoder路线的自回归预训练,走向生成式AI


