第3讲:BERT——“完形填空“炼成的语言理解大师
第3讲:BERT——"完形填空"炼成的语言理解大师
一、从一个课堂游戏开始
1.1 你小时候玩过"完形填空"吗?
题目:
"今天____很好,我们一起去____玩。"
选项:
A. 天气 / 公园
B. 心情 / 游戏
C. 运气 / 赌场
正确答案:A
你是怎么选出A的?
- “今天____很好” → "天气"最搭配("心情很好"也可以,但"天气"更常见)
- “一起去____玩” → "公园"最合理("游戏"是动词,"赌场"不适合课堂语境)
关键能力:你同时看了整句话的前面和后面,综合判断中间该填什么。
1.2 这就是BERT的核心思想
BERT的全称是 Bidirectional Encoder Representations from Transformers。
拆解:
- Bidirectional = 双向(同时看左边和右边)
- Encoder = 编码器(只理解,不生成)
- Representations = 表示/向量(把文字变成数字)
- from Transformers = 用Transformer架构
一句话:BERT是一个**只会"阅读理解",不会"写作文"**的模型。
二、BERT的诞生背景:为什么需要它?
2.1 2018年之前的问题
在BERT出现之前,NLP模型大多是**“从左到右”**阅读的:
输入:"今天天气很好"
模型处理过程:
看到"今" → 预测下一个字是"天"
看到"今天" → 预测下一个字是"气"
看到"今天天" → 预测下一个字是"气"
...
问题:模型永远看不到右边的信息!
句子:"他很高兴,因为考试通过了。"
如果只能从左到右:
看到"他很高兴"时,还不知道"为什么高兴"!
必须等到看到"因为考试通过了",才能回头理解——但已经晚了。
这就像闭着眼睛走路,只能摸前面,不能看全貌。
2.2 BERT的革命:双向阅读
BERT的做法:把某些词遮住,让模型根据上下文猜出来。
原始句子:今天 [MASK] 很 [MASK],我们一起去公园玩。
模型输入:今天 [MASK] 很 [MASK],我们一起去公园玩。
↑ 遮住"天气"和"好"
模型任务:猜 [MASK] 是什么?
第1个[MASK]:根据"今天___很好" → 猜"天气"
第2个[MASK]:根据"天气很___"和"我们一起去公园" → 猜"好"
关键:模型必须同时看左边和右边,才能猜对。
就像做填空题时,你自然会前后文对照着看。BERT通过这种方式,"被迫"学会了双向理解。
三、BERT的两大预训练任务
3.1 任务一:MLM(Masked Language Model)——完形填空
怎么"遮"?
原始句子:今天天气很好,我们一起去公园玩。
处理步骤:
1. 随机选15%的词
2. 对选中的词,按以下规则处理:
- 80%概率 → 换成 [MASK]
- 10%概率 → 换成随机词(如"香蕉")
- 10%概率 → 保持不变
例子:
原始:今天 天气 很 好 ,我们 一起 去 公园 玩 。
处理后(假设选中"天气"和"好"):
今天 [MASK] 很 好 ,我们 一起 去 公园 玩 。
("天气"被换成[MASK],"好"保持不变——这是10%的情况)
或者:
今天 [MASK] 很 香蕉 ,我们 一起 去 公园 玩 。
("天气"被换成[MASK],"好"被换成随机词"香蕉")
为什么要加随机词和保持不变?
防止模型"偷懒"!如果模型知道[MASK]位置一定是被遮住的词,它就不会好好学上下文。加入噪声,让模型必须认真对待每个位置。
模型怎么"猜"?
输入:[CLS] 今天 [MASK] 很 好 ,我们 一起 去 公园 玩 。[SEP]
↑BERT的特殊标记
处理流程:
1. 经过Transformer编码器 → 每个词变成一个向量
2. [MASK]位置的向量 → 输入一个分类层
3. 分类层输出:词汇表中每个词的概率
4. 目标:让"天气"的概率最高
可视化:
[MASK]位置的向量(768维)
↓
┌─────────┐
│ 分类层 │ → 输出:P("天气")=0.85, P("心情")=0.10, P("运气")=0.05, ...
└─────────┘
↓
损失函数:-log(P("天气")) ← 让正确答案概率越大越好
3.2 任务二:NSP(Next Sentence Prediction)——句子关系判断
为什么要这个任务?
很多NLP任务需要理解两个句子的关系,比如:
- 问答:问题和答案是否匹配?
- 语义相似度:两句话意思一样吗?
- entailment:第二句是第一句的推论吗?
怎么做?
从语料库中采样句子对:
正例(50%概率):
句子A:今天天气很好。
句子B:我们一起去公园玩。
标签:IsNext(是连续的)
负例(50%概率):
句子A:今天天气很好。
句子B:量子力学是研究微观粒子的物理学分支。
标签:NotNext(不相关)
输入格式:
[CLS] 今天天气很好。[SEP] 我们一起去公园玩。[SEP]
↑ ↑
特殊标记 分隔两个句子
[CLS]位置的输出向量 → 二分类:IsNext or NotNext
[CLS]标记的输出被训练成"整个句子对的语义摘要",下游任务可以直接用它。
四、BERT的架构细节
4.1 Encoder-only:只理解,不生成
BERT的架构 = Transformer的Encoder部分 × 12层(或24层)
输入嵌入 + 位置编码
↓
┌─────────────────┐
│ Transformer │ ← 第1层
│ Encoder Block │
└─────────────────┘
↓
┌─────────────────┐
│ Transformer │ ← 第2层
│ Encoder Block │
└─────────────────┘
↓
... × 12
↓
┌─────────────────┐
│ Transformer │ ← 第12层(最后一层输出用于预测)
│ Encoder Block │
└─────────────────┘
↓
[MASK]预测 / [CLS]分类
为什么不用Decoder?
| 组件 | 功能 | BERT需要吗? |
|---|---|---|
| Encoder | 双向理解上下文 | ✅ 需要 |
| Decoder | 自回归生成(一个词一个词写) | ❌ 不需要 |
BERT的目标是"理解",不是"写作"。Decoder的"因果掩码"(只能看左边)会妨碍双向理解。
4.2 BERT的两个版本
| 版本 | 层数 | 隐藏维度 | 参数量 | 用途 |
|---|---|---|---|---|
| BERT-Base | 12 | 768 | 1.1亿 | 研究、中小任务 |
| BERT-Large | 24 | 1024 | 3.4亿 | 高精度需求 |
对比GPT-3(1750亿参数),BERT算是"小模型"了。但BERT证明了:预训练+微调的范式威力巨大。
4.3 输入表示的三合一体
BERT的每个词向量 = 词嵌入 + 位置嵌入 + 句子嵌入
输入:[CLS] 我 喜欢 猫 [SEP] 它 很 可爱 [SEP]
词嵌入(Token Embedding):
[CLS]→[0.1, 0.2, ...] 我→[0.3, -0.1, ...] 喜欢→[0.5, 0.8, ...]
位置嵌入(Position Embedding):
位置0→[0.01, 0.02, ...] 位置1→[0.03, -0.01, ...]
句子嵌入(Segment Embedding):
句子A→[0.1, 0.1, ...] 句子B→[0.2, 0.2, ...]
最终输入 = 三者相加
Segment Embedding的作用:告诉模型"这个词属于第1句还是第2句"。
五、BERT vs GPT:理解 vs 生成的根本分歧
5.1 架构对比
┌─────────────────────────────────────────────────────────┐
│ BERT(理解大师) │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ 词1 │ ←→ │ 词2 │ ←→ │ 词3 │ ← 双向箭头! │
│ └─────────┘ └─────────┘ └─────────┘ │
│ ↓ ↓ ↓ │
│ 每个词都能看到所有其他词(左边+右边) │
│ 任务:完形填空(MLM)+ 句子关系(NSP) │
│ 用途:文本分类、情感分析、命名实体识别、问答... │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ GPT(生成天才) │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ 词1 │ ─→ │ 词2 │ ─→ │ 词3 │ ← 单向箭头! │
│ └─────────┘ └─────────┘ └─────────┘ │
│ ↓ ↓ ↓ │
│ 每个词只能看到左边的词(因果掩码) │
│ 任务:预测下一个词(自回归) │
│ 用途:写文章、聊天、代码生成、创意写作... │
└─────────────────────────────────────────────────────────┘
5.2 用一个例子说明区别
任务:理解句子"他很高兴,因为考试通过了。"
| 模型 | 处理"高兴"时能看到什么? | 理解效果 |
|---|---|---|
| BERT | “他 [MASK] ,因为考试通过了” | ✅ 看到"考试通过",知道高兴的原因 |
| GPT | “他 很” → 预测下一个词 | ❌ 还没看到"考试通过",只能猜"开心?" |
任务:续写句子"今天天气很好,"
| 模型 | 能力 | 输出 |
|---|---|---|
| BERT | 不擅长生成 | 只能给[MASK]位置填词,不能流畅续写 |
| GPT | 擅长生成 | “我们一起去公园野餐吧。阳光洒在脸上…” |
5.3 选择指南
| 你的需求 | 选BERT | 选GPT |
|---|---|---|
| 判断情感(正面/负面) | ✅ | ❌ |
| 找句子中的实体(人名/地名) | ✅ | ❌ |
| 判断两句话是否相似 | ✅ | ❌ |
| 写文章、聊天对话 | ❌ | ✅ |
| 代码自动补全 | ❌ | ✅ |
| 创意写作、头脑风暴 | ❌ | ✅ |
现代大模型(如GPT-4、Claude)已经融合了两者能力,但理解BERT和GPT的区别,对理解架构演进至关重要。
六、应用场景:BERT能做什么?
6.1 文本分类( sentiment analysis)
输入:"这部电影太精彩了,强烈推荐!"
BERT处理:
[CLS] 这 部 电影 太 精彩 了 , 强烈 推荐 ! [SEP]
↓
[CLS]位置的向量 → 分类层 → 正面(0.95) / 负面(0.05)
输出:正面情感,置信度95%
6.2 命名实体识别(NER)
输入:"李明在北京大学学习计算机科学。"
BERT输出每个词的标签:
李(B-PER) 明(I-PER) 在(O) 北(B-ORG) 京(I-ORG) 大(I-ORG) 学(I-ORG)
学(O) 习(O) 计(B-FIELD) 算(I-FIELD) 机(I-FIELD) 科(I-FIELD) 学(I-FIELD) 。(O)
标签含义:
B-PER = 人名开始 I-PER = 人名中间
B-ORG = 机构开始 I-ORG = 机构中间
O = 无关
6.3 语义相似度
句子A:"今天天气很好"
句子B:"今天的天气真不错"
BERT输出:[CLS]向量A vs [CLS]向量B 的余弦相似度 = 0.92(很相似)
句子C:"我喜欢吃苹果"
相似度 = 0.15(不相似)
七、动手实验:Hugging Face加载BERT做情感分析
7.1 环境准备
# 安装依赖
pip install transformers datasets torch
7.2 实验1:用预训练BERT做推理(零样本)
from transformers import BertTokenizer, BertForSequenceClassification
import torch
# ============================================
# 步骤1:加载预训练模型和分词器
# ============================================
# 使用中文BERT(bert-base-chinese)
# 如果是英文情感分析,可用 "nlptown/bert-base-multilingual-uncased-sentiment"
model_name = "bert-base-chinese"
print("正在加载模型,首次需要下载约400MB...")
tokenizer = BertTokenizer.from_pretrained(model_name)
# 加载用于序列分类的BERT(有额外的分类头)
# num_labels=2 表示二分类(正面/负面)
model = BertForSequenceClassification.from_pretrained(
"bert-base-chinese",
num_labels=2
)
# 把模型设为评估模式(不更新参数)
model.eval()
print("✅ 模型加载完成!")
# ============================================
# 步骤2:准备输入文本
# ============================================
texts = [
"这部电影太精彩了,演员演技炸裂!", # 应该正面
"浪费我两个小时,剧情烂透了", # 应该负面
"一般般吧,没什么特别的印象", # 中性偏负
]
# BERT需要特殊格式:[CLS] + 文本 + [SEP]
# tokenizer会自动添加这些标记
print("\n" + "=" * 50)
print("【实验1】预训练BERT的零样本预测")
print("=" * 50)
for text in texts:
# 分词并转换为ID
inputs = tokenizer(
text,
padding=True,
truncation=True,
max_length=128,
return_tensors="pt" # 返回PyTorch张量
)
# 查看分词结果(帮助理解)
tokens = tokenizer.convert_ids_to_tokens(inputs['input_ids'][0])
print(f"\n原文:{text}")
print(f"分词:{' '.join(tokens)}")
# 模型推理
with torch.no_grad(): # 不计算梯度,节省内存
outputs = model(**inputs)
# 获取预测结果
logits = outputs.logits # [batch_size, num_labels]
probabilities = torch.softmax(logits, dim=-1)
# 因为用的是随机初始化的分类头,结果可能不准
# 但这演示了完整流程
pred_label = torch.argmax(probabilities, dim=-1).item()
confidence = probabilities[0][pred_label].item()
label_name = "正面" if pred_label == 1 else "负面"
print(f"预测:{label_name}(置信度:{confidence:.2%})")
print(f"原始分数:{logits[0].tolist()}")
print("\n⚠️ 注意:上面结果可能不准,因为分类头是随机初始化的!")
print(" 下面我们用微调后的模型,或者自己微调。")
7.3 实验2:加载已微调的英文情感分析BERT
from transformers import pipeline
print("\n" + "=" * 50)
print("【实验2】使用Hugging Face现成的情感分析管道")
print("=" * 50)
# 自动下载并加载已微调好的模型(约400MB)
# 这个模型在大量标注数据上训练过,效果可靠
sentiment_analyzer = pipeline(
"sentiment-analysis",
model="nlptown/bert-base-multilingual-uncased-sentiment"
)
test_texts = [
"I love this product! It's amazing.",
"This is the worst experience ever.",
"Not bad, but could be better.",
"Absolutely fantastic! Highly recommended.",
"Terrible quality, complete waste of money.",
]
print("\n英文情感分析结果:")
for text in test_texts:
result = sentiment_analyzer(text)[0]
print(f" 文本:{text}")
print(f" 结果:{result['label']}(置信度:{result['score']:.2%})")
print()
# ============================================
# 实验3:自己微调BERT做中文情感分析
# ============================================
print("=" * 50)
print("【实验3】微调BERT做中文情感分析(完整流程)")
print("=" * 50)
import torch
from torch.utils.data import DataLoader
from transformers import (
BertTokenizer,
BertForSequenceClassification,
AdamW,
get_linear_schedule_with_warmup
)
from datasets import load_dataset
import numpy as np
from sklearn.metrics import accuracy_score
# 设置设备
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"使用设备:{device}")
# 加载中文BERT
model_name = "bert-base-chinese"
tokenizer = BertTokenizer.from_pretrained(model_name)
model = BertForSequenceClassification.from_pretrained(model_name, num_labels=2)
model = model.to(device)
# 准备模拟数据(实际应用时替换为真实数据集)
# 这里用简单的列表演示,真实场景可用 load_dataset("chinese_sentiment")
train_texts = [
"这部电影太棒了", "演员演技出色", "剧情紧凑刺激", "视觉效果震撼",
"导演功力深厚", "配乐恰到好处", "强烈推荐观看", "年度最佳影片",
"烂片一部", "浪费生命", "演技尴尬", "剧情狗血",
"特效五毛", "逻辑混乱", "看得想睡觉", "退票!",
] * 10 # 重复扩充数据量
train_labels = [1] * 8 * 10 + [0] * 8 * 10 # 1=正面, 0=负面
# 构建Dataset类
class SentimentDataset(torch.utils.data.Dataset):
def __init__(self, texts, labels, tokenizer, max_len=128):
self.texts = texts
self.labels = labels
self.tokenizer = tokenizer
self.max_len = max_len
def __len__(self):
return len(self.texts)
def __getitem__(self, idx):
text = str(self.texts[idx])
label = self.labels[idx]
encoding = self.tokenizer(
text,
max_length=self.max_len,
padding='max_length',
truncation=True,
return_tensors='pt'
)
return {
'input_ids': encoding['input_ids'].flatten(),
'attention_mask': encoding['attention_mask'].flatten(),
'label': torch.tensor(label, dtype=torch.long)
}
# 创建数据加载器
train_dataset = SentimentDataset(train_texts, train_labels, tokenizer)
train_loader = DataLoader(train_dataset, batch_size=4, shuffle=True)
# 训练配置
optimizer = AdamW(model.parameters(), lr=2e-5, weight_decay=0.01)
epochs = 3
total_steps = len(train_loader) * epochs
scheduler = get_linear_schedule_with_warmup(
optimizer,
num_warmup_steps=0,
num_training_steps=total_steps
)
# 训练循环
print(f"\n开始训练({epochs}轮)...")
model.train()
for epoch in range(epochs):
total_loss = 0
correct = 0
total = 0
for batch_idx, batch in enumerate(train_loader):
input_ids = batch['input_ids'].to(device)
attention_mask = batch['attention_mask'].to(device)
labels = batch['label'].to(device)
# 清零梯度
optimizer.zero_grad()
# 前向传播
outputs = model(
input_ids=input_ids,
attention_mask=attention_mask,
labels=labels
)
loss = outputs.loss
logits = outputs.logits
# 计算准确率
preds = torch.argmax(logits, dim=-1)
correct += (preds == labels).sum().item()
total += labels.size(0)
# 反向传播
loss.backward()
# 梯度裁剪(防止梯度爆炸)
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
# 更新参数
optimizer.step()
scheduler.step()
total_loss += loss.item()
if (batch_idx + 1) % 10 == 0:
print(f" Epoch {epoch+1}, Batch {batch_idx+1}, "
f"Loss: {loss.item():.4f}, Acc: {correct/total:.2%}")
avg_loss = total_loss / len(train_loader)
accuracy = correct / total
print(f"Epoch {epoch+1} 完成:平均损失={avg_loss:.4f}, 准确率={accuracy:.2%}")
# 测试微调后的模型
print("\n" + "=" * 50)
print("【测试】微调后的模型预测")
print("=" * 50)
model.eval()
test_texts = [
"这部电影真好看,感动哭了", # 应该正面
"太差了,完全看不下去", # 应该负面
"演员表演很到位", # 应该正面
"剧情莫名其妙", # 应该负面
]
for text in test_texts:
inputs = tokenizer(
text,
padding=True,
truncation=True,
max_length=128,
return_tensors="pt"
).to(device)
with torch.no_grad():
outputs = model(**inputs)
logits = outputs.logits
probabilities = torch.softmax(logits, dim=-1)
pred_label = torch.argmax(probabilities, dim=-1).item()
confidence = probabilities[0][pred_label].item()
label_name = "正面😊" if pred_label == 1 else "负面😞"
print(f"文本:{text}")
print(f"预测:{label_name}(置信度:{confidence:.2%})")
print(f"分数:{logits[0].tolist()}")
print()
print("=" * 50)
print("✅ 实验完成!你刚刚亲手微调了一个BERT模型!")
print("=" * 50)
7.4 实验4:可视化BERT的注意力权重
from transformers import BertTokenizer, BertModel
import torch
import matplotlib.pyplot as plt
import numpy as np
print("=" * 50)
print("【实验4】可视化BERT的注意力权重")
print("=" * 50)
# 加载BERT(不带分类头,只取编码器输出)
tokenizer = BertTokenizer.from_pretrained("bert-base-chinese")
model = BertModel.from_pretrained("bert-base-chinese", output_attentions=True)
model.eval()
# 输入句子
text = "猫坐在垫子上"
inputs = tokenizer(text, return_tensors="pt")
# 获取注意力权重
with torch.no_grad():
outputs = model(**inputs)
# attentions是一个元组,12层,每层[batch, heads, seq, seq]
attentions = outputs.attentions # 12层
# 查看形状
print(f"层数:{len(attentions)}")
print(f"每层注意力形状:{attentions[0].shape}")
# [1, 12, 6, 6] = [batch=1, heads=12, seq_len=6, seq_len=6]
# 获取分词结果
tokens = tokenizer.convert_ids_to_tokens(inputs['input_ids'][0])
print(f"\n分词结果:{tokens}")
# ['[CLS]', '猫', '坐', '在', '垫', '子', '上', '[SEP]']
# 可视化第1层第1个头的注意力
layer = 0 # 第1层
head = 0 # 第1个头
attn_matrix = attentions[layer][0, head].numpy() # [seq, seq]
plt.figure(figsize=(8, 6))
plt.imshow(attn_matrix, cmap='hot', interpolation='nearest')
plt.colorbar(label='Attention Weight')
plt.xticks(range(len(tokens)), tokens, rotation=45)
plt.yticks(range(len(tokens)), tokens)
plt.title(f'BERT Layer {layer+1}, Head {head+1} Attention')
plt.xlabel('Key (被关注的词)')
plt.ylabel('Query (当前处理的词)')
# 在每个格子里标注数值
for i in range(len(tokens)):
for j in range(len(tokens)):
text_color = "white" if attn_matrix[i, j] > 0.5 else "black"
plt.text(j, i, f'{attn_matrix[i, j]:.2f}',
ha="center", va="center", color=text_color, fontsize=8)
plt.tight_layout()
plt.savefig('/mnt/agents/output/bert_attention_viz.png', dpi=150)
plt.show()
print("\n✅ 注意力可视化图已保存!")
print("""
解读热力图:
- 行 = Query(当前在处理哪个词)
- 列 = Key(在看哪些词)
- 颜色越亮 = 注意力权重越高
观察重点:
1. [CLS]通常关注所有词(收集全局信息)
2. 代词(如"它")会高度关注其指代对象
3. 不同头关注不同模式(语法 vs 语义)
""")
# 对比不同层的注意力模式
fig, axes = plt.subplots(2, 3, figsize=(15, 10))
layers_to_plot = [0, 2, 5, 8, 10, 11] # 第1,3,6,9,11,12层
for idx, layer in enumerate(layers_to_plot):
ax = axes[idx // 3, idx % 3]
attn_matrix = attentions[layer][0, 0].numpy() # 取第1个头
im = ax.imshow(attn_matrix, cmap='hot', interpolation='nearest')
ax.set_xticks(range(len(tokens)))
ax.set_yticks(range(len(tokens)))
ax.set_xticklabels(tokens, rotation=45, fontsize=8)
ax.set_yticklabels(tokens, fontsize=8)
ax.set_title(f'Layer {layer+1}')
# 添加数值标注
for i in range(len(tokens)):
for j in range(len(tokens)):
text_color = "white" if attn_matrix[i, j] > 0.5 else "black"
ax.text(j, i, f'{attn_matrix[i, j]:.2f}',
ha="center", va="center", color=text_color, fontsize=6)
plt.suptitle('BERT Attention Evolution Across Layers', fontsize=14)
plt.tight_layout()
plt.savefig('/mnt/agents/output/bert_attention_layers.png', dpi=150)
plt.show()
print("\n✅ 多层对比图已保存!")
print("观察:浅层关注局部/语法,深层关注全局/语义")
八、核心总结
| 概念 | 一句话解释 |
|---|---|
| BERT | 双向Transformer编码器,专门做"理解" |
| MLM | 完形填空——遮住词,让模型根据上下文猜 |
| NSP | 判断两句话是否连续,学习句子关系 |
| [CLS] | 特殊标记,输出代表整句语义 |
| [SEP] | 分隔标记,区分两个句子 |
| 预训练 | 在大语料上自监督学习通用语言表示 |
| 微调 | 在具体任务上用小数据调整,快速适配 |
| BERT vs GPT | 理解 vs 生成;双向 vs 单向 |
九、面试高频题
Q1:BERT和GPT的本质区别是什么?
答:架构上,BERT是Encoder-only,双向注意力,适合理解任务;GPT是Decoder-only,单向因果注意力,适合生成任务。训练目标上,BERT用MLM(完形填空)和NSP,GPT用自回归预测下一个词。
Q2:为什么BERT用MLM而不是直接预测下一个词?
答:预测下一个词只能利用左边的信息,是单向的。MLM遮住中间的词,迫使模型同时利用左右两边的上下文,实现真正的双向理解。
Q3:BERT的[CLS]标记有什么用?
答:[CLS]位置的输出向量经过NSP任务训练,编码了整个输入序列的语义信息。下游分类任务可以直接用这个向量,无需对整个序列做额外处理。
Q4:BERT处理长文本有什么限制?
答:BERT-base的最大序列长度通常是512个token。更长的文本需要截断或分段处理。这是Transformer O(n²)注意力复杂度的限制。
十、课后作业
作业1:修改实验代码
# 尝试:
# 1. 把MLM任务应用到英文句子,观察BERT如何填词
# 2. 比较BERT-base和BERT-large在同一任务上的表现
# 3. 用不同的随机种子,观察注意力权重的变化
作业2:思考题
问题:BERT的NSP任务在后续研究中被发现效果有限,
RoBERTa等模型甚至去掉了NSP。为什么?
提示:可能的原因包括——
1. NSP太简单(负样本随机采样,和正样本差异太大)
2. 句子对任务不如更细粒度的词级别任务有效
3. 现代模型用更大的数据和更好的预训练目标
十一、下讲预告
第4讲:GPT系列——"预测下一个词"的生成天才
我们将:
- 理解GPT的自回归生成机制
- 用Hugging Face实现文本续写
- 探索Temperature、Top-p等生成参数的影响
- 理解RLHF(人类反馈强化学习)如何让GPT"说人话"
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐




所有评论(0)