--- title: 上下文化表示:ELMo 与 BERT 的双向上下文建模 draft: false tags: - ELMo - BERT - 上下文化表示 - BiLSTM - 双向语言模型 --- # 上下文化表示: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)的内部状态作为词的上下文相关表示。 **关键创新**: 1. **字符卷积嵌入**:ELMo 使用字符级卷积网络(CNN)生成词嵌入,天生具备极强的 OOV(未登录词)处理能力,远超 Word2Vec/GloVe 等基于词的静态嵌入 2. **双向**:同时考虑左上下文和右上下文 3. **深层**:使用多层 LSTM 的不同层捕捉不同粒度的信息 4. **预训练 + 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 在下游任务的使用 **固定特征提取器模式**: 1. 冻结 BiLSTM LM 的权重 2. 在下游任务上添加 task-specific 层 3. 只微调新增层的权重 **数学表示**: 设下游任务的输入是句子 $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)** 目标,实现真正的**双向上下文表示**。 **关键创新**: 1. **真正的双向上下文**:不是像 ELMo 那样简单拼接前后向(伪双向,时序依赖无法突破),而是通过掩码机制同时看到左右上下文,实现原生全局双向建模 2. **Transformer 架构**:用 Self-Attention 替代 LSTM,解决长距离依赖和并行问题 3. **大规模预训练**:在大规模语料(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**: 1. **Multi-Head Self-Attention** 2. **Add & LayerNorm** 3. **Feed-Forward Network** 4. **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 范式 **核心思想**: 1. **在大规模语料上预训练**:学习通用语言表示 2. **在下游任务上微调**:添加任务特定层,调整所有权重 **数学表示**: 预训练目标: $$\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 - 梯度消失 **解决方案**: 1. 使用 AdamW 优化器(权重衰减解耦,适配预训练模型) 2. 学习率 warmup(预热步数为总步数的 1%~2%) 3. 梯度裁剪 4. 使用适当的权重衰减 5. 混合精度 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}) \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**: 1. **解决一词多义**:上下文相关表示自动区分不同语义 2. **捕获长距离依赖**:Transformer attention 覆盖全部上下文 3. **预训练 + 微调范式**:在大规模无标注数据上预训练,在小规模标注数据上微调 **BERT 对 NLP 的影响**: > BERT 开启了"预训练 + 微调"的 NLP 新时代。在此之前,每个任务都需要从头训练;在此之后,所有任务都可以基于预训练模型微调。 **核心公式**: - **ELMo**:双向 LSTM 的加权层拼接 - **BERT**:Masked LM 实现真正的双向上下文 - **Fine-tuning**:预训练参数初始化 + 任务特定层 --- **延伸阅读**: 1. Peters et al., "Deep Contextualized Word Representations" (NAACL 2018) — ELMo 2. Devlin et al., "BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding" (NAACL 2019) 3. Radford et al., "GPT: Improving Language Understanding by Generative Pre-Training" (2018) 4. Liu et al., "RoBERTa: A Robustly Optimized BERT Pretraining Approach" (2019) 5. Clark et al., "ELECTRA: Pre-training Text Encoders as Discriminators Rather Than Generators" (ICLR 2020)