20 KiB
title, draft, tags
| title | draft | tags | |||||
|---|---|---|---|---|---|---|---|
| 上下文化表示:ELMo 与 BERT 的双向上下文建模 | false |
|
上下文化表示:ELMo 与 BERT 的双向上下文建模
一、静态词向量的根本局限
1.1 一词多义问题
静态词向量的问题:
使用 Word2Vec 或 GloVe 学习到的词向量是静态的——同一个词无论在什么上下文中,都对应同一个向量。
具体问题:
| 词 | 上下文 | 正确语义 | 静态向量会混淆 |
|---|---|---|---|
| "bank" | river ___ | 河岸 | 无法区分 |
| "bank" | ___ robbery | 银行 | 无法区分 |
| "run" | ___ a marathon | 跑步(动词) | 无法区分 |
| "run" | salmon ___ | 溪流(名词) | 无法区分 |
数学表示:
对于同一词 w 在不同上下文 c_1 和 c_2 中,静态词向量满足 $\mathbf{v}_w^{(c_1)} = \mathbf{v}_w^{(c_2)} = \mathbf{v}_w$。这忽略了语义的可变性。
1.2 解决方案的演进
方案演进:
静态词向量(Word2Vec/GloVe)
↓ 解决一词多义
多义词向量(未广泛使用)
↓ 上下文感知
上下文向量(ELMo, 2018)
↓ 大规模预训练 + 深 Transformer
BERT(2018)
核心思想:
每个词的表示应该依赖于其上下文。相同的词在不同的句子中应该有不同的向量。
二、ELMo:深度上下文化词表示
2.1 ELMo 的核心思想
ELMo(Embeddings from Language Models, Peters et al., 2018)的全称是"从语言模型提取的嵌入"。
核心洞察:
使用双向 LSTM 语言模型(BiLSTM LM)的内部状态作为词的上下文相关表示。
关键创新:
- 字符卷积嵌入:ELMo 使用字符级卷积网络(CNN)生成词嵌入,天生具备极强的 OOV(未登录词)处理能力,远超 Word2Vec/GloVe 等基于词的静态嵌入
- 双向:同时考虑左上下文和右上下文
- 深层:使用多层 LSTM 的不同层捕捉不同粒度的信息
- 预训练 + fine-tune:在大语料上预训练,可以微调到下游任务
2.2 双向语言模型的数学定义
前向语言模型:
给定词序列 $w_1, w_2, \ldots, w_T$,前向 LM 计算:
P(w_t | w_1, \ldots, w_{t-1}) = \text{softmax}(\mathbf{h}_t^{\rightarrow} \mathbf{W}_o) \tag{2.1}
其中 \mathbf{h}_t^{\rightarrow} 是前向 LSTM 在位置 t 的隐藏状态。
后向语言模型:
P(w_t | w_{t+1}, \ldots, w_T) = \text{softmax}(\mathbf{h}_t^{\leftarrow} \mathbf{W}_o) \tag{2.2}
其中 \mathbf{h}_t^{\leftarrow} 是后向 LSTM 在位置 t 的隐藏状态。
双向 LM 目标:
\mathcal{L} = \sum_{t=1}^T \left[ \log P(w_t | w_1, \ldots, w_{t-1}) + \log P(w_t | w_{t+1}, \ldots, w_T) \right] \tag{2.3}
这使得每个位置 t 的表示同时包含左右两边的信息。
2.3 ELMo 的架构
双层双向 LSTM:
Token: w_1 w_2 w_3 ... w_T
↓ ↓ ↓ ↓
Char Emb → → → → →
↓ ↓ ↓ ↓
┌───────────────────────┐
│ Forward LSTM Layer 1 │
└───────────────────────┘
↓ ↓ ↓ ↓
┌───────────────────────┐
│ Backward LSTM Layer 1 │
└───────────────────────┘
↓ ↓ ↓ ↓
┌───────────────────────┐
│ Forward LSTM Layer 2 │
└───────────────────────┘
↓ ↓ ↓ ↓
┌───────────────────────┐
│ Backward LSTM Layer 2 │
└───────────────────────┘
↓ ↓ ↓ ↓
h_1 h_2 h_3 ... h_T
每层输出:
每个位置 t 有两个 LSTM 层的输出:
\mathbf{h}_t^{\rightarrow, 1}, $\mathbf{h}_t^{\rightarrow, 2}$(前向,层1和层2)\mathbf{h}_t^{\leftarrow, 1}, $\mathbf{h}_t^{\leftarrow, 2}$(后向,层1和层2)
2.4 ELMo 表示的聚合
原始 ELMo 向量:
对于每个位置 $t$,拼接所有层的隐藏状态:
\mathbf{H}_t = [\mathbf{h}_t^{\rightarrow, 1}; \mathbf{h}_t^{\rightarrow, 2}; \mathbf{h}_t^{\leftarrow, 1}; \mathbf{h}_t^{\leftarrow, 2}] \in \mathbb{R}^{4d} \tag{2.4}
其中 d 是每层 LSTM 的隐藏维度。
加权聚合(ELMo 改进版):
不是简单拼接,而是学习加权平均:
\mathbf{v}_t = \gamma \sum_{j=1}^L s_j \mathbf{h}_t^j \tag{2.5}
其中:
L是层数(这里 $L=2$)s_j是可学习的 softmax 权重,经 softmax 归一化后 $\sum_j s_j = 1$,自适应选取各层信息\gamma是可学习的全局缩放系数,平衡整体向量幅值
为什么加权:
不同层捕获不同类型的信息:
- 底层(Layer 1):更关注语法/词形信息(词性、词缀)
- 高层(Layer 2):更关注语义/意义信息(命名实体、语义角色)
2.5 ELMo 在下游任务的使用
固定特征提取器模式:
- 冻结 BiLSTM LM 的权重
- 在下游任务上添加 task-specific 层
- 只微调新增层的权重
数学表示:
设下游任务的输入是句子 $s = (w_1, \ldots, w_T)$,ELMo 向量为 $\mathbf{v}_t$。
下游任务的表示为:
\mathbf{x}_t^{\text{down}} = [\mathbf{x}_t^{\text{base}}; \mathbf{v}_t] \tag{2.6}
其中 \mathbf{x}_t^{\text{base}} 是原始词向量,\mathbf{v}_t 是 ELMo 上下文嵌入。
组合方式:
- Concatenation:拼接原始词向量和 ELMo 向量
- Weighted:直接用
\mathbf{v}_t替换原始向量
ELMo 两种使用模式:
- 特征冻结模式:仅微调下游任务层(添加 Task-specific 层),适合小数据集
- 全量微调模式:整体更新 BiLSTM 权重,适合大数据场景
2.6 ELMo 的局限性
| 局限 | 描述 |
|---|---|
| 架构限制 | BiLSTM 无法捕获长距离依赖(最长约 100-200 tokens) |
| 并行性差 | LSTM 训练是序列性的,无法充分利用 GPU 并行 |
| 表示能力 | BiLSTM 的 hidden states 是线性组合,表达能力有限 |
| 参数量 | 相对较少的参数限制了表示能力 |
这促使了 Transformer 架构的引入。
三、BERT:深度双向预训练
3.1 BERT 的核心思想
BERT(Bidirectional Encoder Representations from Transformers, Devlin et al., 2018)的核心贡献是:
使用 Masked Language Model(MLM) 目标,实现真正的双向上下文表示。
关键创新:
- 真正的双向上下文:不是像 ELMo 那样简单拼接前后向(伪双向,时序依赖无法突破),而是通过掩码机制同时看到左右上下文,实现原生全局双向建模
- Transformer 架构:用 Self-Attention 替代 LSTM,解决长距离依赖和并行问题
- 大规模预训练:在大规模语料(Wikipedia + BookCorpus)上预训练
3.2 Masked Language Model 的数学推导
核心问题:双向条件下,语言模型的似然 P(w_t | w_1, \ldots, w_{t-1}, w_{t+1}, \ldots, w_T) 会产生"信息泄漏"——当前词可能直接从输入中"看到自己"。
解决方案:掩码机制:
在输入中随机遮盖 15% 的 token:
- 被遮盖的 token 以 [MASK] 替换
- 模型需要根据双向上下文预测被遮盖的词
MLM 目标:
\mathcal{L}_{\text{MLM}} = -\sum_{t \in \mathcal{M}} \log P(w_t | w_{\setminus t}) \tag{3.1}
其中 \mathcal{M} 是被掩码的位置集合。
这实现了同时利用左右上下文信息!
3.3 BERT 的输入表示
BERT 的输入是三部分之和:
\boldsymbol{e}_t = \boldsymbol{e}_{\text{tok},t} + \boldsymbol{e}_{\text{pos},t} + \boldsymbol{e}_{\text{seg},t} \tag{3.2}
其中:
- $\boldsymbol{e}_{\text{tok},t}$:词嵌入(Token Embedding)
- $\boldsymbol{e}_{\text{pos},t}$:绝对位置嵌入(Position Embedding)
- $\boldsymbol{e}_{\text{seg},t}$:句子分段嵌入(Segment Embedding),用于区分句子 A 和 B
3.4 预训练任务详解
任务 1:Masked Language Model(MLM)
BERT 随机选择 15% 的 token 进行掩码:
- 80% 替换为 [MASK]
- 10% 替换为随机 token(增加鲁棒性)
- 10% 保持不变(减少 [MASK] 在微调时的影响)
掩码策略设计动机:缓解「预训练存在 [MASK]、微调无 [MASK]」的分布偏移问题。若全部使用 [MASK],则预训练时模型看到 MASK token 但微调时看不到,造成不一致。随机词和保留原词让模型被迫学习更鲁棒的表示。
数学表示:
设 w_t 是被选中的 token:
- 80%:
w_t \rightarrow \text{[MASK]} - 10%:
w_t \rightarrow w_{\text{random}} - 10%:$w_t \rightarrow w_t$(不变)
任务 2:Next Sentence Prediction(NSP)
判断句子 B 是否是句子 A 的下一句:
P(\text{IsNext} | \text{sentence } A, \text{ sentence } B) \tag{3.3}
正样本:B 确实是 A 的下一句 负样本:B 是随机采样的句子
NSP 的核心缺陷:NSP 偏向主题匹配(判断两句是否属于同一话题),无法学习深层语义连贯关系。这也是 RoBERTa 直接剔除 NSP 任务的根本原因。
NSP 目标:
\mathcal{L}_{\text{NSP}} = -\log P(\text{IsNext} | A, B) \tag{3.4}
3.5 BERT 的 Transformer 架构
标准 Transformer Encoder:
BERT-base 使用 12 层 Transformer Encoder:
Input: [CLS] token_1 [SEP] token_2 [SEP]
↓ ↓ ↓ ↓
Token + Pos + Seg Embeddings
↓
Transformer Encoder × 12
↓
Output: [CLS] h_{T+1} ...
每层 Transformer Block:
- Multi-Head Self-Attention
- Add & LayerNorm
- Feed-Forward Network
- Add & LayerNorm
3.6 BERT 的输出表示
定义(最后一层表示):
\mathbf{H}_t^{(L)} \in \mathbb{R}^d \tag{3.5}
这是第 L 层(最后一层)Transformer 的输出。
对于分类任务(如情感分析):
- 使用 [CLS] token 的表示:
\mathbf{H}_0^{(L)} - 通过 softmax 分类:
P(y | \mathbf{H}_0^{(L)}) = \text{softmax}(\mathbf{H}_0^{(L)} \mathbf{W}_o) \tag{3.6}
对于序列标注任务(如 NER):
- 每个 token 的表示:
\mathbf{H}_t^{(L)} - 通过 CRF 层或 softmax 分类(工业界 NER 主流用法是 BERT + CRF)
BERT 架构定位:BERT 是纯 Encoder-only 架构,无解码器结构,天生不支持自回归文本生成,仅适合理解类任务。
3.7 BERT 与 ELMo 的对比
| 维度 | ELMo | BERT |
|---|---|---|
| 架构 | BiLSTM | Transformer Encoder |
| 双向上下文 | 拼接前后向 | 通过 MLM 同时利用 |
| 表示方式 | 加权层拼接 | 最后一层 + attention |
| 并行性 | 低(LSTM 序列性) | 高(Transformer 并行) |
| 长距离依赖 | 弱(< 200 tokens) | 强(512 tokens) |
| 掩码机制 | 无 | MLM |
| 预训练任务 | 语言模型 | MLM + NSP |
四、BERT 的数学细节
4.1 Self-Attention 的矩阵形式
定义(Query, Key, Value):
对于输入序列 $\mathbf{H} \in \mathbb{R}^{T \times d}$:
\mathbf{Q} = \mathbf{H} \mathbf{W}_Q, \quad \mathbf{K} = \mathbf{H} \mathbf{W}_K, \quad \mathbf{V} = \mathbf{H} \mathbf{W}_V \tag{4.1}
注意力分数:
\mathbf{A} = \text{softmax}\left(\frac{\mathbf{Q} \mathbf{K}^\top}{\sqrt{d_k}}\right) \tag{4.2}
除以 \sqrt{d_k} 的作用:防止高维下内积数值过大,导致 softmax 梯度饱和、训练停滞。
输出:
\mathbf{O} = \mathbf{A} \mathbf{V} \tag{4.3}
4.2 多头注意力
定义(多头输出):
\text{MultiHead}(\mathbf{H}) = \text{Concat}(\text{head}_1, \ldots, \text{head}_h) \mathbf{W}_O \tag{4.4}
\text{head}_i = \text{Attention}(\mathbf{H} \mathbf{W}_Q^i, \mathbf{H} \mathbf{W}_K^i, \mathbf{H} \mathbf{W}_V^i) \tag{4.5}
维度关系:
如果 $d_{\text{model}} = 768$,$h = 12$,则每头的维度 $d_k = d_v = 64$。
输出投影层:拼接多头结果后必须经过输出投影层 $\mathbf{W}O \in \mathbb{R}^{d_v \times d{\text{model}}}$,将多头注意力输出映射回原始维度,保持模型一致性。
4.3 BERT 的训练目标
总损失函数:
\mathcal{L} = \mathcal{L}_{\text{MLM}} + \mathcal{L}_{\text{NSP}} \tag{4.6}
MLM 损失:
\mathcal{L}_{\text{MLM}} = -\sum_{t \in \mathcal{M}} \log \frac{\exp(\mathbf{H}_t^{(L)} \mathbf{w}_{w_t})}{\sum_{w \in V} \exp(\mathbf{H}_t^{(L)} \mathbf{w}_w)} \tag{4.7}
NSP 损失:
\mathcal{L}_{\text{NSP}} = -\left[ y \log P(\text{IsNext}) + (1-y) \log (1-P(\text{IsNext})) \right] \tag{4.8}
4.4 位置编码与长度外推
BERT 的位置编码:
使用可学习的绝对位置编码 $\mathbf{E}{\text{pos}} \in \mathbb{R}^{512 \times d{\text{model}}}$。
问题:零外推性:
BERT 原生仅支持 512 序列长度,无外推能力。当序列长度超过 512 时,无法查表。
后续改进:
| 方法 | 描述 |
|---|---|
| RoPE | 旋转位置编码,通过复数乘法实现相对位置编码(GPT、LLAMA 等使用) |
| ALiBi | 在注意力分数上加线性偏置 |
| RoPE | 解决长序列外推问题 |
五、BERT 的 Fine-tuning
5.1 预训练 + Fine-tuning 范式
核心思想:
- 在大规模语料上预训练:学习通用语言表示
- 在下游任务上微调:添加任务特定层,调整所有权重
数学表示:
预训练目标:
\theta^* = \arg\max_\theta \sum_{(w_1, \ldots, w_T)} \mathcal{L}_{\text{MLM}}(\theta) + \mathcal{L}_{\text{NSP}}(\theta) \tag{5.1}
Fine-tuning 目标:
\theta^* = \arg\max_{\theta'} \sum_{(x, y) \in \mathcal{D}_{\text{task}}} \mathcal{L}_{\text{task}}(\theta'; \theta^*) \tag{5.2}
5.2 不同任务的 Fine-tuning 方式
分类任务:
[CLS] → FC + softmax → 类别
序列标注任务(NER):
token_1 → FC → tag_1
token_2 → FC → tag_2
...
问答任务(SQuAD):
[CLS] question [SEP] context [SEP]
↓
预测答案范围的 start 和 end
文本生成任务:
BERT 本身不是生成模型,但可以通过添加解码器实现(如 BERT2BERT)。
六、训练中的问题与解决方案
6.1 BERT 训练的问题
问题 1:[MASK] token 在微调时不出现
预训练时使用 [MASK],但微调时没有掩码。这导致预训练和微调的不一致。
BERT 的解决方案(随机替换):
- 80% 替换为 [MASK]
- 10% 替换为随机 token
- 10% 保持不变
后续改进(ERNIE 等):
引入了实体级掩码、 phrase 级掩码等更复杂的掩码策略。
问题 2:NSP 任务太简单
NSP 是一个二分类任务,学习太容易,没有学到足够的语义信息。
解决方案:
RoBERTa 去掉了 NSP 任务,使用动态掩码,取得了更好的效果。
6.2 训练不收敛
问题表现:
- Loss 爆炸或 NaN
- 梯度消失
解决方案:
- 使用 AdamW 优化器(权重衰减解耦,适配预训练模型)
- 学习率 warmup(预热步数为总步数的 1%~2%)
- 梯度裁剪
- 使用适当的权重衰减
- 混合精度 BF16 训练(适配大模型,防止溢出)
6.3 BERT 微调通用超参(实战刚需)
- 基础学习率:
2 \times 10^{-5} \sim 5 \times 10^{-5} - 预热步数:总步数的 1%~2%
- 优化器:优先 AdamW(权重衰减解耦)
- 批大小:16~32(根据显存调整)
- 训练轮数:2~4(小数据集避免过拟合)
6.3 内存与计算效率
BERT-base 的资源需求:
| 资源 | 需求 |
|---|---|
| 参数 | 110M |
| FP32 权重 | ~440MB |
| FP16 权重 | ~220MB |
| 训练 batch size | 32(单卡)或更大(多卡) |
Gradient Checkpointing:
通过在前向传播时不保存所有中间激活,而是在反向传播时重新计算,降低内存占用。
七、BERT 家族与后续发展
7.1 主要变体
| 模型 | 参数量 | 主要改进 |
|---|---|---|
| BERT-base | 110M | 12层, 768维, 12头 |
| BERT-large | 340M | 24层, 1024维, 16头 |
| RoBERTa | 125M | 去掉 NSP,动态掩码,更多数据 |
| ALBERT | 12M | 参数共享,减少内存 |
| ELECTRA | 110M | 替换 token 检测替代 MLM |
| DeBERTa | 134M | 分离注意力,解码增强 |
7.2 ELECTRA 的替换 token 检测
核心思想:
不是掩码,而是让一个小型的"生成器"替换某些 token,然后让"判别器"判断每个 token 是否被替换。
数学表示:
\mathcal{L}_{\text{Generator}} = -\sum_{t} \log P(w_t | w_t^{\text{corrupt}}) \quad \text{(生成器)} \tag{7.1}
\mathcal{L}_{\text{Discriminator}} = -\sum_{t} \log \mathbf{1}_{w_t = w_t^{\text{original}}} \quad \text{(判别器)} \tag{7.2}
优势:每个 token 位置都参与训练(而不只是 15% 的掩码位置),更高效。
7.3 从 BERT 到 GPT 的演进
演进路径:
BERT: Encoder-only (双向上下文, MLM)
↓
GPT-2: Decoder-only (单向, CLM)
↓
GPT-3: 更大规模 + Few-shot
↓
GPT-4: 多模态 + 更强推理
核心差异:
| 模型 | 架构 | 训练目标 | 上下文 |
|---|---|---|---|
| BERT | Encoder | MLM + NSP | 双向 |
| GPT-2/3 | Decoder | CLM | 单向 |
八、数学公式速查
8.1 ELMo 公式
前向 LM 概率:
P(w_t | w_1, \ldots, w_{t-1}) = \text{softmax}(\mathbf{h}_t^{\rightarrow} \mathbf{W}_o) \tag{8.1}
双向 LM 损失:
\mathcal{L} = \sum_{t=1}^T \left[ \log P(w_t | w_{<t}) + \log P(w_t | w_{>t}) \right] \tag{8.2}
ELMo 表示:
\mathbf{v}_t = \gamma \sum_{j=1}^L s_j \mathbf{h}_t^j \tag{8.3}
8.2 BERT 公式
MLM 损失:
\mathcal{L}_{\text{MLM}} = -\sum_{t \in \mathcal{M}} \log P(w_t | w_{\setminus t}) \tag{8.4}
NSP 损失:
\mathcal{L}_{\text{NSP}} = -\log P(\text{IsNext} | A, B) \tag{8.5}
总损失:
\mathcal{L} = \mathcal{L}_{\text{MLM}} + \mathcal{L}_{\text{NSP}} \tag{8.6}
8.3 注意力公式
缩放点积注意力:
\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^\top}{\sqrt{d_k}}\right) V \tag{8.7}
多头注意力:
\text{MultiHead}(H) = \text{Concat}(\text{head}_1, \ldots, \text{head}_h) W_O \tag{8.8}
九、总结
ELMo 与 BERT 的核心贡献:
| 模型 | 核心贡献 | 局限性 |
|---|---|---|
| ELMo | 双向 LSTM LM + 上下文表示 | 架构限制,无法长依赖 |
| BERT | Transformer + MLM + NSP | 仍是 Encoder,不是生成模型 |
为什么需要 BERT:
- 解决一词多义:上下文相关表示自动区分不同语义
- 捕获长距离依赖:Transformer attention 覆盖全部上下文
- 预训练 + 微调范式:在大规模无标注数据上预训练,在小规模标注数据上微调
BERT 对 NLP 的影响:
BERT 开启了"预训练 + 微调"的 NLP 新时代。在此之前,每个任务都需要从头训练;在此之后,所有任务都可以基于预训练模型微调。
核心公式:
- ELMo:双向 LSTM 的加权层拼接
- BERT:Masked LM 实现真正的双向上下文
- Fine-tuning:预训练参数初始化 + 任务特定层
延伸阅读:
- Peters et al., "Deep Contextualized Word Representations" (NAACL 2018) — ELMo
- Devlin et al., "BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding" (NAACL 2019)
- Radford et al., "GPT: Improving Language Understanding by Generative Pre-Training" (2018)
- Liu et al., "RoBERTa: A Robustly Optimized BERT Pretraining Approach" (2019)
- Clark et al., "ELECTRA: Pre-training Text Encoders as Discriminators Rather Than Generators" (ICLR 2020)