Day 20: 预训练语言模型 (Pre-trained Language Models)
摘要 :在 Word2Vec 时代,每个词只有一个固定的向量,无法解决"一词多义"的问题(比如 "Apple" 既是水果也是公司)。2018 年,ELMo 和 BERT 的横空出世彻底改变了局面,NLP 进入了 "Pre-training + Fine-tuning" (预训练+微调) 的新纪元。本文将带你梳理从 ELMo 到 BERT 再到 GPT 的演进之路。
1. 从静态到动态:解决多义词难题
- 静态向量 (Word2Vec/GloVe) :
- 字典里 "Bank" 只有一行数据。
- 无论句子是 "I sat on the river bank " 还是 "I went to the bank to deposit money",取出来的向量完全一样。
- 动态向量 (Contextualized Embeddings) :
- 词的向量不再是查表得来的 ,而是模型算出来的。
- 输入句子不同,同一个词经过模型计算后的向量也不同。
1.1 ELMo (Embeddings from Language Models)
- 架构:双向 LSTM (Bi-LSTM)。
- 思路:预训练一个语言模型。用它来提取特征,把提取出的 Hidden State 作为动态词向量,拼接到下游任务的模型中。
- 地位:它是动态向量的开创者,但因为还在用 LSTM,特征提取能力不如后来的 Transformer。
2. BERT:NLP 的"ImageNet 时刻"
2018年,Google 发布 BERT (Bidirectional Encoder Representations from Transformers),横扫 11 项 NLP 榜单。
2.1 核心架构
- 结构 :Transformer Encoder (双向,能同时看到上下文)。
- 范式 :Masked Language Model (MLM)。
2.2 预训练任务
BERT 不用预测下一个词(因为那样只能看上文),它发明了两个新任务:
- MLM (完形填空) :
- 随机遮住句子中 15% 的词(替换为
[MASK])。 - 任务:根据上下文猜出被遮住的词是什么。
- 例子 :The cat sat on the
[MASK]. →\to→mat.
- 随机遮住句子中 15% 的词(替换为
- NSP (Next Sentence Prediction) :
- 给两个句子 A 和 B。
- 任务:判断 B 是不是 A 的下一句?(二分类)。
- 作用:让模型理解句子间的逻辑关系(对问答、推理任务很重要)。
2.3 BERT 家族变体
- RoBERTa (Facebook):优化版 BERT。去掉了 NSP 任务(发现没啥用),更大的 Batch Size,更多的数据,训练更久。效果显著优于 BERT。
- ALBERT:参数共享的小型 BERT。
- DeBERTa:解耦注意力机制,进一步刷榜。
3. GPT 系列:生成式王者的潜伏
当全世界都在为 BERT 狂欢时,OpenAI 坚持走 Decoder-Only 的路子。
3.1 核心架构
- 结构 :Transformer Decoder (单向,只能看上文,Masked Attention)。
- 范式 :Causal Language Model (CLM) / 自回归 (Auto-Regressive)。
3.2 演进之路
- GPT-1 :和 BERT 差不多,先预训练,再下游微调 (Fine-tuning)。效果不如 BERT。
- GPT-2 :Zero-shot 尝试。数据量激增,发现模型不需要微调也能做一些任务。
- GPT-3 :In-context Learning (上下文学习) 。参数量达到 1750 亿。不需要改参数,只需要给几个例子(Prompt),模型就能照猫画虎。这就开启了大模型 (LLM) 时代。
4. T5:大一统模型 (Text-to-Text)
Google 的 T5 (Text-to-Text Transfer Transformer) 试图统一所有 NLP 任务。
- 思想 :万物皆可是文本生成 。
- 翻译 :Input: "Translate English to German: That is good." →\to→ Output: "Das ist gut."
- 分类 :Input: "Cola sentence: The course is jumping well." →\to→ Output: "not acceptable."
- 架构 :标准的 Encoder-Decoder (像原始 Transformer 一样)。
5. 模型架构对比总结
| 模型 | 架构 | 视野 (Attention) | 预训练目标 | 优势领域 | 典型代表 |
|---|---|---|---|---|---|
| BERT | Encoder | 双向 (Bi-directional) | 完形填空 (MLM) | 理解任务 (分类、实体识别、搜索) | BERT, RoBERTa |
| GPT | Decoder | 单向 (Left-to-Right) | 预测下词 (CLM) | 生成任务 (写作、对话) | GPT-3, LLaMA |
| T5/BART | Enc-Dec | 混合 | Span Masking | 序列到序列 (翻译、摘要) | T5, GLM |
6. 代码实践:使用 HuggingFace Transformers
现在我们要使用 BERT,只需要几行代码。
python
from transformers import BertTokenizer, BertModel
import torch
# 1. 加载预训练的 Tokenizer 和 Model
model_name = 'bert-base-uncased'
tokenizer = BertTokenizer.from_pretrained(model_name)
model = BertModel.from_pretrained(model_name)
# 2. 准备输入文本
text = "The bank of the river."
# text2 = "The bank robbery."
# 3. 转化为 Tensor
inputs = tokenizer(text, return_tensors="pt")
print(f"Input IDs: {inputs['input_ids']}")
# [101, 1996, 2924, 1997, 1996, 2314, 1012, 102]
# 101=[CLS], 102=[SEP] 是 BERT 特有的特殊 Token
# 4. 模型前向传播
with torch.no_grad():
outputs = model(**inputs)
# 5. 获取输出
# last_hidden_state shape: [Batch_Size, Seq_Len, Hidden_Dim(768)]
last_hidden_states = outputs.last_hidden_state
# [CLS] token 的向量通常用于代表整句话的语义,用于分类任务
cls_embedding = last_hidden_states[0, 0, :]
print(f"CLS Vector Shape: {cls_embedding.shape}")
7. 总结
- ELMo 开启了动态向量时代。
- BERT (Encoder) 是理解大师,通过 MLM 任务学会了极好的语义表示,统治了判别式任务。
- GPT (Decoder) 是生成大师,通过海量数据的自回归训练,涌现出了惊人的推理能力。
- 预告 :知道了模型怎么预训练,接下来我们要解决具体的 NLP 任务了。明天我们将学习 文本分类、情感分析与 NER,看看如何把 BERT 应用到实际生产中。
思考:为什么 BERT 用双向 Transformer 效果好,但最后大模型(LLM)却都选了 GPT 的单向 Decoder 路线?
- 因为生成是最高级的理解。而且在海量数据下,自回归任务 (NTP) 的上限似乎比完形填空更高,且更适合 Zero-shot 通用任务。