预训练范式演变 - 从BERT到ChatGPT的训练策略
发布时间:2024-09-10
作者:AI技术研究者
标签:预训练, BERT, GPT, 训练策略, 自监督学习
前言
如果说Transformer是大模型的"硬件基础",那么预训练范式就是大模型的"软件系统"。从2018年BERT的横空出世,到2022年ChatGPT的现象级成功,预训练技术经历了从理念创新到工程突破的完整演进。作为一个深度参与这个过程的研究者,我见证了每一次范式转变带来的震撼。
我记得第一次看到BERT在11个NLP任务上全面刷榜时的惊讶,也记得GPT-3展现出few-shot能力时的兴奋,更记得ChatGPT发布后整个AI圈的沸腾。每一次突破都不是偶然,而是预训练技术不断演进的必然结果。今天,让我们深入探讨这个改变AI历史的技术范式。
预训练的理论基础
迁移学习的启发
预训练的核心思想来源于迁移学习,但在深度学习时代得到了全新的诠释:
传统迁移学习:
特征工程时代:
- 手工设计特征
- 在不同任务间复用特征
- 依赖领域专家知识
- 泛化能力有限
深度学习早期:
- 在ImageNet上预训练CNN
- 微调到特定视觉任务
- 证明了预训练的有效性
- 但主要限于监督学习
自监督预训练的突破:
核心洞察:
- 语言本身包含丰富的监督信号
- 无需人工标注即可学习表示
- 大规模无标注数据容易获得
- 学到的表示具有通用性
技术优势:
- 数据规模:无标注数据远超标注数据
- 成本效益:避免昂贵的人工标注
- 通用性:一个模型适用多个任务
- 可扩展性:支持大规模模型训练
语言模型的演进
统计语言模型时代:
N-gram模型:
- P(w_i | w_{i-n+1}, ..., w_{i-1})
- 基于词频统计
- 数据稀疏问题严重
- 无法捕获长距离依赖
神经语言模型:
- 词向量表示
- 循环神经网络
- 缓解数据稀疏问题
- 但计算效率低
Transformer时代的语言模型:
技术突破:
- 并行化训练
- 长距离依赖建模
- 可扩展到大规模
- 为预训练奠定基础
预训练目标:
- 自回归语言模型(GPT系列)
- 掩码语言模型(BERT系列)
- 序列到序列(T5系列)
BERT:双向编码的革命
技术创新
2018年10月,Google发布BERT(Bidirectional Encoder Representations from Transformers),开启了预训练的新时代。
核心创新:
双向上下文:
- 同时利用左右上下文信息
- 突破传统语言模型的单向限制
- 更好地理解语言语义
掩码语言模型(MLM):
- 随机掩盖输入中的部分词汇
- 预测被掩盖的词汇
- 学习双向语言表示
下一句预测(NSP):
- 判断两个句子是否连续
- 学习句子间的关系
- 适用于句子对任务
预训练过程:
python
def bert_pretraining_loss(model, input_ids, attention_mask, labels):
"""
BERT预训练损失函数
"""
# 掩码语言模型损失
mlm_outputs = model(
input_ids=input_ids,
attention_mask=attention_mask,
labels=labels['mlm_labels']
)
mlm_loss = mlm_outputs.loss
# 下一句预测损失
nsp_outputs = model(
input_ids=input_ids,
attention_mask=attention_mask,
next_sentence_label=labels['nsp_labels']
)
nsp_loss = nsp_outputs.loss
# 总损失
total_loss = mlm_loss + nsp_loss
return total_loss
def create_masked_lm_predictions(tokens, masked_lm_prob=0.15):
"""
创建掩码语言模型的训练数据
"""
cand_indexes = []
for i, token in enumerate(tokens):
if token == "[CLS]" or token == "[SEP]":
continue
cand_indexes.append(i)
random.shuffle(cand_indexes)
num_to_predict = min(max(1, int(round(len(tokens) * masked_lm_prob))),
len(cand_indexes))
masked_lms = []
covered_indexes = set()
for index in cand_indexes:
if len(masked_lms) >= num_to_predict:
break
if index in covered_indexes:
continue
covered_indexes.add(index)
# 80%的时间替换为[MASK]
if random.random() < 0.8:
masked_token = "[MASK]"
else:
# 10%的时间保持原词
if random.random() < 0.5:
masked_token = tokens[index]
# 10%的时间替换为随机词
else:
masked_token = random.choice(vocab_list)
masked_lms.append({
"index": index,
"label": tokens[index]
})
tokens[index] = masked_token
return tokens, masked_lms
微调策略
BERT的成功很大程度上归功于其优雅的微调策略:
任务适配方法:
分类任务:
- 在[CLS]位置添加分类头
- 微调整个模型参数
- 适用于情感分析、文本分类等
序列标注:
- 在每个token位置添加标注头
- 预测每个token的标签
- 适用于命名实体识别、词性标注等
句子对任务:
- 利用[SEP]分隔两个句子
- 在[CLS]位置进行分类
- 适用于自然语言推理、问答等
抽取式问答:
- 预测答案的起始和结束位置
- 两个线性层分别预测start和end
- 适用于阅读理解任务
微调技巧:
python
def bert_fine_tuning(model, train_dataloader, num_epochs=3):
"""
BERT微调训练循环
"""
# 使用较小的学习率
optimizer = AdamW(model.parameters(), lr=2e-5)
# 学习率预热
total_steps = len(train_dataloader) * num_epochs
scheduler = get_linear_schedule_with_warmup(
optimizer,
num_warmup_steps=int(0.1 * total_steps),
num_training_steps=total_steps
)
model.train()
for epoch in range(num_epochs):
for batch in train_dataloader:
optimizer.zero_grad()
outputs = model(
input_ids=batch['input_ids'],
attention_mask=batch['attention_mask'],
labels=batch['labels']
)
loss = outputs.loss
loss.backward()
# 梯度裁剪
torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
optimizer.step()
scheduler.step()
影响与局限
BERT的影响:
技术影响:
- 在11个NLP任务上达到SOTA
- 证明了预训练+微调范式的有效性
- 推动了预训练模型的发展
- 成为NLP的新基线
产业影响:
- 降低了NLP应用的门槛
- 推动了NLP技术的产业化
- 催生了大量基于BERT的应用
- 改变了NLP研究的方向
BERT的局限:
生成能力不足:
- 主要适用于理解类任务
- 生成任务表现一般
- 无法进行开放式生成
计算效率问题:
- 双向注意力计算复杂度高
- 推理速度相对较慢
- 不适合实时应用
预训练目标限制:
- MLM目标与生成任务不匹配
- NSP任务的有效性存疑
- 预训练和微调存在差异
GPT:自回归生成的崛起
技术路线
OpenAI选择了与BERT完全不同的技术路线:
自回归语言模型:
核心思想:
- 从左到右生成文本
- 每个位置只能看到之前的信息
- 符合自然的文本生成过程
预训练目标:
- 最大化似然估计
- P(x) = ∏P(x_i | x_1, ..., x_{i-1})
- 简单而有效的目标函数
架构选择:
- 仅使用Transformer Decoder
- 因果掩码注意力
- 单向信息流动
GPT-1的探索:
python
def gpt_pretraining_loss(model, input_ids, attention_mask):
"""
GPT预训练损失函数
"""
# 输入和标签错位一个位置
inputs = input_ids[:, :-1]
labels = input_ids[:, 1:]
outputs = model(
input_ids=inputs,
attention_mask=attention_mask[:, :-1]
)
# 计算交叉熵损失
loss_fct = CrossEntropyLoss()
loss = loss_fct(
outputs.logits.view(-1, outputs.logits.size(-1)),
labels.view(-1)
)
return loss
def gpt_generation(model, prompt, max_length=100, temperature=1.0):
"""
GPT文本生成
"""
model.eval()
input_ids = tokenizer.encode(prompt, return_tensors='pt')
with torch.no_grad():
for _ in range(max_length):
outputs = model(input_ids)
logits = outputs.logits[:, -1, :] / temperature
probs = F.softmax(logits, dim=-1)
next_token = torch.multinomial(probs, 1)
input_ids = torch.cat([input_ids, next_token], dim=-1)
if next_token.item() == tokenizer.eos_token_id:
break
return tokenizer.decode(input_ids[0])
GPT-2的突破
GPT-2展现了规模化的力量:
Zero-shot能力的涌现:
任务格式化:
- 将任务描述为文本生成
- 通过prompt引导模型行为
- 无需任务特定的微调
能力表现:
- 阅读理解:在CoQA上达到55 F1
- 摘要生成:生成连贯的摘要
- 翻译任务:英法翻译达到可用水平
- 问答系统:回答常识性问题
In-context Learning的雏形:
学习机制:
- 在输入中提供示例
- 模型从示例中学习模式
- 无需参数更新
示例格式:
Input: "Translate English to French:
Hello → Bonjour
Goodbye → Au revoir
Thank you → "
Output: "Merci"
GPT-3的飞跃
GPT-3将规模化推向极致:
Few-shot Learning:
python
def few_shot_prompting(model, task_description, examples, query):
"""
Few-shot学习示例
"""
prompt = task_description + "\n\n"
# 添加示例
for example in examples:
prompt += f"Input: {example['input']}\n"
prompt += f"Output: {example['output']}\n\n"
# 添加查询
prompt += f"Input: {query}\n"
prompt += "Output:"
# 生成回答
response = model.generate(prompt, max_length=50)
return response
# 使用示例
examples = [
{"input": "I love this movie!", "output": "Positive"},
{"input": "This film is terrible.", "output": "Negative"},
{"input": "Not bad, could be better.", "output": "Neutral"}
]
result = few_shot_prompting(
model=gpt3,
task_description="Classify the sentiment of the following text:",
examples=examples,
query="This movie is amazing!"
)
涌现能力:
数学推理:
- 基本算术运算
- 简单的代数问题
- 逻辑推理
代码生成:
- 多种编程语言
- 算法实现
- 代码解释
创意写作:
- 故事创作
- 诗歌生成
- 剧本编写
知识问答:
- 广泛的知识覆盖
- 常识推理
- 事实查询
InstructGPT/ChatGPT:对齐的突破
RLHF技术
2022年,OpenAI发布InstructGPT,引入了RLHF(Reinforcement Learning from Human Feedback)技术:
三阶段训练流程:
阶段1:监督微调(SFT)
- 收集高质量的指令-回答对
- 在GPT-3基础上进行监督微调
- 学习遵循指令的基本能力
阶段2:奖励模型训练(RM)
- 收集人类偏好数据
- 训练奖励模型预测人类偏好
- 将人类价值观编码到模型中
阶段3:强化学习优化(PPO)
- 使用PPO算法优化策略
- 最大化奖励模型的分数
- 平衡性能和对齐
技术实现:
python
def train_reward_model(model, preference_data):
"""
训练奖励模型
"""
optimizer = AdamW(model.parameters(), lr=1e-5)
for batch in preference_data:
chosen_inputs = batch['chosen']
rejected_inputs = batch['rejected']
# 计算奖励分数
chosen_rewards = model(chosen_inputs)
rejected_rewards = model(rejected_inputs)
# 偏好损失
loss = -torch.log(torch.sigmoid(chosen_rewards - rejected_rewards)).mean()
optimizer.zero_grad()
loss.backward()
optimizer.step()
def ppo_training(policy_model, reward_model, prompts):
"""
PPO强化学习训练
"""
for prompt_batch in prompts:
# 生成回答
responses = policy_model.generate(prompt_batch)
# 计算奖励
rewards = reward_model(prompt_batch, responses)
# 计算优势函数
advantages = compute_advantages(rewards)
# PPO更新
policy_loss = compute_policy_loss(
policy_model, prompt_batch, responses, advantages
)
optimizer.zero_grad()
policy_loss.backward()
optimizer.step()
对齐目标
HHH原则:
Helpful(有用性):
- 能够帮助用户解决问题
- 提供准确和相关的信息
- 理解用户的真实意图
Harmless(无害性):
- 避免生成有害内容
- 拒绝不当请求
- 保护用户和社会安全
Honest(诚实性):
- 承认知识的局限性
- 不编造虚假信息
- 表达不确定性
效果提升:
指令遵循能力:
- 更好地理解和执行指令
- 减少无关或错误的回答
- 提高任务完成质量
对话连贯性:
- 保持多轮对话的一致性
- 理解上下文和历史信息
- 自然的对话流程
安全性改善:
- 显著减少有害内容生成
- 更好的内容过滤
- 提高用户信任度
预训练数据的演进
数据规模的增长
数据规模趋势:
GPT-1: 5GB (BooksCorpus)
GPT-2: 40GB (WebText)
GPT-3: 570GB (Common Crawl + Books + Wikipedia)
PaLM: 780GB (高质量网页、书籍、代码)
GPT-4: 估计数TB级别
数据质量的提升
数据清洗技术:
python
def data_quality_filtering(text):
"""
数据质量过滤
"""
# 长度过滤
if len(text) < 100 or len(text) > 100000:
return False
# 语言检测
if detect_language(text) != 'en':
return False
# 重复内容检测
if is_duplicate(text):
return False
# 质量评分
quality_score = compute_quality_score(text)
if quality_score < 0.7:
return False
# 有害内容过滤
if contains_harmful_content(text):
return False
return True
def compute_quality_score(text):
"""
计算文本质量分数
"""
score = 0.0
# 语法正确性
score += grammar_score(text) * 0.3
# 信息密度
score += information_density(text) * 0.3
# 可读性
score += readability_score(text) * 0.2
# 事实准确性
score += factual_accuracy(text) * 0.2
return score
数据多样性:
数据来源多样化:
- 网页内容:Common Crawl
- 书籍文献:Project Gutenberg, OpenLibrary
- 学术论文:arXiv, PubMed
- 代码仓库:GitHub
- 百科全书:Wikipedia
- 新闻文章:各大新闻网站
领域覆盖:
- 科学技术
- 人文社科
- 艺术文学
- 商业金融
- 日常生活
数据去重技术
精确去重:
python
def exact_deduplication(documents):
"""
精确去重
"""
seen = set()
unique_docs = []
for doc in documents:
doc_hash = hashlib.md5(doc.encode()).hexdigest()
if doc_hash not in seen:
seen.add(doc_hash)
unique_docs.append(doc)
return unique_docs
近似去重:
python
def fuzzy_deduplication(documents, threshold=0.8):
"""
基于MinHash的近似去重
"""
from datasketch import MinHashLSH, MinHash
lsh = MinHashLSH(threshold=threshold, num_perm=128)
minhashes = {}
for i, doc in enumerate(documents):
m = MinHash(num_perm=128)
for word in doc.split():
m.update(word.encode('utf8'))
# 检查是否有近似重复
result = lsh.query(m)
if not result:
lsh.insert(i, m)
minhashes[i] = doc
return list(minhashes.values())
训练技术的进步
分布式训练
数据并行:
python
def data_parallel_training(model, train_dataloader, num_gpus):
"""
数据并行训练
"""
model = nn.DataParallel(model, device_ids=list(range(num_gpus)))
model = model.cuda()
optimizer = AdamW(model.parameters(), lr=1e-4)
for batch in train_dataloader:
batch = {k: v.cuda() for k, v in batch.items()}
optimizer.zero_grad()
outputs = model(**batch)
loss = outputs.loss
loss.backward()
optimizer.step()
模型并行:
python
class ModelParallelTransformer(nn.Module):
def __init__(self, config):
super().__init__()
self.num_layers = config.num_layers
self.layers_per_device = self.num_layers // torch.cuda.device_count()
# 将层分布到不同GPU
self.layers = nn.ModuleList()
for i in range(self.num_layers):
device = i // self.layers_per_device
layer = TransformerLayer(config).to(f'cuda:{device}')
self.layers.append(layer)
def forward(self, x):
for i, layer in enumerate(self.layers):
device = i // self.layers_per_device
x = x.to(f'cuda:{device}')
x = layer(x)
return x
混合精度训练
python
def mixed_precision_training(model, train_dataloader):
"""
混合精度训练
"""
model = model.cuda()
optimizer = AdamW(model.parameters(), lr=1e-4)
scaler = torch.cuda.amp.GradScaler()
for batch in train_dataloader:
batch = {k: v.cuda() for k, v in batch.items()}
optimizer.zero_grad()
# 使用autocast进行前向传播
with torch.cuda.amp.autocast():
outputs = model(**batch)
loss = outputs.loss
# 缩放损失并反向传播
scaler.scale(loss).backward()
scaler.step(optimizer)
scaler.update()
梯度累积
python
def gradient_accumulation_training(model, train_dataloader, accumulation_steps=4):
"""
梯度累积训练
"""
optimizer = AdamW(model.parameters(), lr=1e-4)
for i, batch in enumerate(train_dataloader):
outputs = model(**batch)
loss = outputs.loss / accumulation_steps
loss.backward()
if (i + 1) % accumulation_steps == 0:
optimizer.step()
optimizer.zero_grad()
评估与基准测试
内在评估
困惑度(Perplexity):
python
def compute_perplexity(model, test_dataloader):
"""
计算困惑度
"""
model.eval()
total_loss = 0
total_tokens = 0
with torch.no_grad():
for batch in test_dataloader:
outputs = model(**batch)
loss = outputs.loss
# 计算有效token数量
attention_mask = batch['attention_mask']
num_tokens = attention_mask.sum().item()
total_loss += loss.item() * num_tokens
total_tokens += num_tokens
avg_loss = total_loss / total_tokens
perplexity = math.exp(avg_loss)
return perplexity
外在评估
GLUE基准:
任务类型:
- CoLA: 语法可接受性判断
- SST-2: 情感分析
- MRPC: 释义检测
- STS-B: 语义相似度
- QQP: 问题对等价性
- MNLI: 自然语言推理
- QNLI: 问答自然语言推理
- RTE: 文本蕴含识别
- WNLI: 代词消歧
SuperGLUE基准:
更具挑战性的任务:
- BoolQ: 布尔问答
- CB: 承诺银行
- COPA: 常识因果推理
- MultiRC: 多句阅读理解
- ReCoRD: 阅读理解与常识推理
- RTE: 文本蕴含识别
- WiC: 上下文中的词义
- WSC: 代词消歧挑战
未来发展趋势
预训练目标的创新
自监督学习新方法:
对比学习:
- SimCLR, MoCo等方法
- 学习更好的表示
- 减少对标注数据的依赖
掩码自编码:
- MAE (Masked Autoencoder)
- 重建被掩盖的内容
- 学习更丰富的表示
多模态预训练:
- CLIP, DALL-E等
- 跨模态表示学习
- 统一的多模态理解
效率优化
模型压缩:
知识蒸馏:
- 大模型指导小模型
- 保持性能的同时减少参数
- 适合部署到边缘设备
剪枝技术:
- 结构化剪枝
- 非结构化剪枝
- 动态剪枝
量化技术:
- 权重量化
- 激活量化
- 混合精度量化
长上下文建模
技术方向:
稀疏注意力:
- Longformer, BigBird
- 减少注意力计算复杂度
- 支持更长的序列
分层注意力:
- Hierarchical Transformer
- 多尺度信息处理
- 提高长序列建模能力
记忆机制:
- Transformer-XL
- 外部记忆模块
- 持续学习能力
总结
预训练范式的演进是AI发展史上的重要篇章,它不仅改变了NLP领域,也为整个AI技术的发展指明了方向:
✅ 技术演进脉络:
- BERT:双向编码,理解为王
- GPT:自回归生成,规模制胜
- InstructGPT/ChatGPT:人类对齐,价值导向
✅ 核心技术突破:
- 自监督学习:无需标注数据的表示学习
- 规模化定律:更大的模型,更强的能力
- 人类反馈:将人类价值观融入AI系统
✅ 工程技术进步:
- 分布式训练:支持大规模模型训练
- 数据工程:高质量数据的重要性
- 评估体系:全面的模型评估框架
关键启示:
- 数据是基础:高质量、大规模的数据是成功的前提
- 规模是关键:模型规模的增长带来能力的跃迁
- 对齐是方向:技术发展必须与人类价值观对齐
- 工程是保障:强大的工程能力支撑技术突破
- 评估是指南:科学的评估体系指导技术发展
预训练技术的发展还在继续,我们正站在通用人工智能的门槛上。未来的预训练技术将更加高效、更加智能、更加安全,为人类社会带来更大的价值。
相关文章推荐:
想了解更多预训练技术的实现细节,欢迎关注后续文章!