Skip to content

章节3:预训练语言模型


学习目标

  • 理解 ELMo 如何通过双向 LSTM 生成上下文相关的词向量
  • 掌握 BERT 的 Masked LM 与 Next Sentence Prediction 预训练任务
  • 了解 GPT 自回归语言模型的单向生成机制
  • 区分 RoBERTa、ALBERT 等变体的优化策略
  • 熟悉 MLM、PLM 等不同掩码策略及其设计动机

3.1 ELMo:上下文词向量

3.1.1 静态词向量的局限

Word2Vec / GloVe 为每个词分配固定向量,无法解决一词多义:

"苹果" → 同一个向量 → 水果 / 手机品牌

3.1.2 ELMo 的核心思想

ELMo(Embeddings from Language Models, AllenAI 2018)使用双向 LSTM 语言模型,根据上下文动态生成词向量。

前向 LSTM:   P(t_1,...,t_N) = Π P(t_k | t_1,...,t_{k-1})
后向 LSTM:   P(t_1,...,t_N) = Π P(t_k | t_{k+1},...,t_N)
ELMo向量 = γ · (s_layer0 + s_layer1·h1 + s_layer2·h2 + ...)  # 加权各层
python
# ELMo 使用示意(需安装 allennlp 或使用 HuggingFace)
from transformers import AutoTokenizer, AutoModel

tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
model = AutoModel.from_pretrained("bert-base-uncased")
# ELMo 类似的双向动态表示已在 BERT 中融合

# 同一词在不同上下文中的表示不同
text1 = "I like **apple** juice"           # 苹果汁
text2 = "I bought an **apple** phone"      # iPhone
# BERT 会为两处的 "apple" 生成不同的隐层向量

3.1.3 ELMo 的关键贡献

  • 上下文动态表示 — 解决了静态向量的一词多义问题
  • 多层表示融合 — 低层捕捉句法,高层捕捉语义
  • ❗ 使用 LSTM(非 Transformer),后续被 BERT 超越

3.2 BERT:双向预训练模型

3.2.1 BERT 架构(Google, 2018)

BERT = Bidirectional Encoder Representations from Transformers

核心创新:双向 Transformer 编码器 + 两个预训练任务。

                     [CLS] 我 爱 NLP [SEP]

                    [Transformer Encoder]
                    (12层 / 24层)

                    [CLS] → 分类向量
                    每个位置 → 上下文词向量

3.2.2 预训练任务一:Masked Language Model(MLM)

随机遮蔽15%的词,让模型根据上下文预测被遮蔽的词。

输入:  我 [MASK] 自然语言处理
目标: 预测 → "爱"
python
from transformers import BertTokenizer, BertForMaskedLM
import torch

tokenizer = BertTokenizer.from_pretrained("bert-base-chinese")
model = BertForMaskedLM.from_pretrained("bert-base-chinese")

text = "我 [MASK] 自然语言处理"
inputs = tokenizer(text, return_tensors="pt")

with torch.no_grad():
    outputs = model(**inputs)
    predictions = outputs.logits

masked_index = inputs["input_ids"][0].tolist().index(tokenizer.mask_token_id)
predicted_id = predictions[0, masked_index].argmax(dim=-1).item()
print("预测结果:", tokenizer.decode([predicted_id]))
# 输出: 爱(或类似合理的词)

3.2.3 预训练任务二:Next Sentence Prediction(NSP)

判断两个句子是否为连续的上下文。

输入: [CLS] 我 爱 NLP [SEP] NLP 很 有趣 [SEP] → 标签: IsNext
输入: [CLS] 我 爱 NLP [SEP] 北京 是 首都 [SEP] → 标签: NotNext

3.2.4 BERT 的输入表示

Input = Token Embedding + Segment Embedding + Position Embedding
          ↓                    ↓                    ↓
       word piece         句子A/B标记          位置编码
python
from transformers import BertTokenizer

tokenizer = BertTokenizer.from_pretrained("bert-base-chinese")
inputs = tokenizer("我爱自然语言处理", "NLP很有趣",
                   return_tensors="pt", padding=True, truncation=True)
print("input_ids:", inputs["input_ids"])
print("token_type_ids:", inputs["token_type_ids"])  # 区分句子A/B
print("attention_mask:", inputs["attention_mask"])

3.3 GPT:自回归语言模型

3.3.1 GPT 的核心思想

GPT(OpenAI, 2018)使用单向 Transformer 解码器,从左到右逐个预测下一个词。

P(t_1,...,t_N) = Π P(t_k | t_1,...,t_{k-1})

输入:  我 爱 → 预测: 自然
输入:  我 爱 自然 → 预测: 语言
输入:  我 爱 自然 语言 → 预测: 处理

3.3.2 BERT vs GPT 对比

维度BERTGPT
架构Transformer 编码器(双向)Transformer 解码器(单向)
预训练任务MLM + NSP自回归语言建模
注意力可看左右双向只能看左侧(因果掩码)
适合任务理解类(分类、NER、QA)生成类(文本生成、对话)
代表模型BERT, RoBERTa, ALBERTGPT-2, GPT-3, GPT-4
python
from transformers import GPT2Tokenizer, GPT2LMHeadModel

tokenizer = GPT2Tokenizer.from_pretrained("gpt2")
model = GPT2LMHeadModel.from_pretrained("gpt2")

text = "Natural language processing is"
inputs = tokenizer(text, return_tensors="pt")

with torch.no_grad():
    outputs = model(**inputs, labels=inputs["input_ids"])
    logits = outputs.logits

# 生成下一个词
next_token_logits = logits[0, -1, :]
next_token_id = next_token_logits.argmax(dim=-1).item()
print("下一个词:", tokenizer.decode([next_token_id]))

3.4 优化变体:RoBERTa 与 ALBERT

3.4.1 RoBERTa(Facebook, 2019)

A Robustly Optimized BERT Pretraining Approach

对 BERT 的改进:

改进点BERTRoBERTa
训练数据16GB(BooksCorpus+Wikipedia)160GB(+ 大规模额外语料)
动态掩码静态(预处理时确定)动态(每个 epoch 重新掩码)
NSP使用去掉(实验证明没必要)
训练步数100 万步500 万步
Batch Size2568000
python
from transformers import RobertaTokenizer, RobertaForMaskedLM

tokenizer = RobertaTokenizer.from_pretrained("roberta-base")
model = RobertaForMaskedLM.from_pretrained("roberta-base")

3.4.2 ALBERT(Google, 2019)

A Lite BERT — 减少参数量同时保持性能

两大创新:

  1. 分解式嵌入参数化(Factorized Embedding)

    • BERT: VocabSize × HiddenSize(大词表导致嵌入矩阵巨大)
    • ALBERT: VocabSize × SmallEmbedding + SmallEmbedding × HiddenSize(分解为两个小矩阵)
  2. 跨层参数共享(Cross-layer Parameter Sharing)

    • BERT 每层 Transformer 权重独立
    • ALBERT 所有层共享同一组参数
python
from transformers import AlbertTokenizer, AlbertForMaskedLM

tokenizer = AlbertTokenizer.from_pretrained("albert-base-v2")
model = AlbertForMaskedLM.from_pretrained("albert-base-v2")

模型参数对比:

模型参数量速度性能
BERT-base110M基准基准
RoBERTa-base125M稍慢↑ 提升
ALBERT-base12M更快≈ 持平
ALBERT-xxlarge235M≈ BERT-large 性能

3.5 预训练任务与掩码策略

3.5.1 MLM(Masked Language Model)

BERT 使用的策略:随机遮蔽 15% 的词。

遮蔽策略细节:

  • 80% → [MASK]
  • 10% → 随机替换为其他词
  • 10% → 保持不变

为什么要保留10%不变? 让模型知道即使输入"正确"也要输出正确——缓解预训练与微调阶段的 mismatch。

3.5.2 PLM(Permutation Language Model)

XLNet(2019)提出的排列语言模型

原始序列: [x1, x2, x3, x4]
排列之一: [x3, x2, x4, x1]
→ 预测 x1 时可以看到 x3, x2, x4(但看不到 x1 自己)

PLM 在保持自回归生成的前提下实现了双向上下文的建模。

3.5.3 其他掩码策略

策略代表模型描述
MLMBERT, RoBERTa, ALBERT随机遮蔽部分输入词
PLMXLNet排列预测顺序实现双向
UniLMUniLM统一 MLM + 自回归 LM
SpanBERTSpanBERT遮蔽连续片段而非单个词
ELECTRAELECTRA判别式(替换检测)替代生成式
python
# 不同掩码策略的效果对比示意
strategies = {
    "MLM (BERT)": "遮蔽15%词,预测被遮蔽词",
    "PLM (XLNet)": "排列分解,每个位置只看排列中的上文",
    "SpanBERT": "遮蔽连续词片段(如连续3个词)",
    "ELECTRA": "用小生成器替换词,用判别器判断哪些被替换"
}
for name, desc in strategies.items():
    print(f"{name}: {desc}")

小结

  1. ELMo 首次提出上下文词向量,使用双向 LSTM 解决一词多义。
  2. BERT 通过 MLM + NSP 双向预训练,成为 NLP 的基石模型。
  3. GPT 使用单向自回归方式,擅长文本生成任务。
  4. RoBERTa 通过更大数据、动态掩码、去掉 NSP 优化 BERT。
  5. ALBERT 用参数分解和跨层共享大幅减少参数量。
  6. 不同的掩码策略(MLM / PLM / SpanBERT)各有设计动机和适用场景。

练习

  1. 使用 BERT(bert-base-chinese)对句子"我在[银行]存钱"和"我在[银行]散步"中的"银行"提取向量,观察差异。
  2. 用 GPT-2 完成"人工智能的未来是______"的生成,尝试不同 temperature 值(0.1 / 0.8 / 1.5)观察输出变化。
  3. 对比 BERT-base 和 RoBERTa-base 对同一句 MLM 预测的差异,分析 RoBERTa 改进是否有效。
  4. 查阅 SpanBERT 论文,简述其"Span Boundary Objective"(SBO)如何辅助片段预测。
  5. 挑战题: 用 HuggingFace Trainer API 在自定义小语料上微调 BERT(MLM),训练完成后观察模型对领域词汇的预测能力。

Python 学习资料