共计 1708 个字符,预计需要花费 5 分钟才能阅读完成。
背景:自监督学习的革命性意义
在自然语言处理(NLP)领域,BERT 的出现标志着自监督学习时代的到来。传统监督学习需要大量人工标注数据,而自监督学习通过设计巧妙的预训练任务,让模型从原始文本中自动学习语言规律。这就好比教孩子认字时,我们不会直接解释每个词的含义,而是通过填空游戏(如 ” 猫喜欢喝__”)让他自己推理出 ” 牛奶 ” 这个答案。

MLM 任务核心原理
1. Transformer 架构基础
BERT 基于 Transformer 编码器堆叠而成,其核心是自注意力机制。想象教室里讨论问题:每个单词(学生)都会根据与其他单词的关系(注意力权重)来调整自己的理解。
2. 掩码处理流程(文字示意图)
假设原始句子为:” 深度学习改变自然语言处理 ”
- Tokenizer 分词结果:[“ 深 ”, “## 度 ”, “ 学 ”, “## 习 ”, “ 改 ”, “## 变 ”, “ 自 ”, “## 然 ”, “ 语 ”, “## 言 ”, “ 处 ”, “## 理 ”]
- 随机选择 15% 的 token 进行掩码(示例选择 ”##习 ” 和 ”## 然 ”)
- 替换策略:
- 80% 概率替换为[MASK]:[“ 深 ”,”##度 ”,” 学 ”,[MASK],” 改 ”,”##变 ”,” 自 ”,[MASK],” 语 ”,”##言 ”,” 处 ”,”## 理 ”]
- 10% 概率随机替换:如将 ”##然 ” 替换为 ”## 快 ”
- 10% 保留原词
PyTorch 实现详解
import torch
import random
from transformers import BertTokenizer, BertForMaskedLM
# 初始化
tokenizer = BertTokenizer.from_pretrained('bert-base-chinese')
model = BertForMaskedLM.from_pretrained('bert-base-chinese')
def mask_inputs(text: str, mask_prob: float = 0.15) -> dict:
"""生成掩码输入"""
tokens = tokenizer.tokenize(text)
inputs = tokenizer.encode(text, return_tensors='pt')
# 生成掩码位置 (排除 [CLS] 和[SEP])
mask_indices = []
for i in range(1, len(tokens)+1):
if random.random() < mask_prob:
# 80-10-10 规则
rand = random.random()
if rand < 0.8:
inputs[0,i] = tokenizer.mask_token_id
elif rand < 0.9:
inputs[0,i] = random.randint(100, tokenizer.vocab_size-1)
mask_indices.append(i)
return {'input_ids': inputs, 'mask_indices': mask_indices}
# 示例使用
inputs = mask_inputs("深度学习改变自然语言处理")
outputs = model(**inputs)
loss = outputs.loss
关键训练考量
- 掩码比例选择:
- 典型值:10%-20%(BERT 论文用 15%)
- 比例过高:模型难以建立上下文关联
-
比例过低:学习信号不足
-
子词边界处理:
- 完整单词掩码优于只掩码子词(如同时掩码 ”##度 ” 和 ”## 习 ”)
-
防止模型仅学习简单的子词模式
-
计算优化技巧:
- 动态掩码:每 epoch 重新生成掩码(HuggingFace 实现)
- 梯度累积:小批次累加解决显存限制
生产环境建议
- 小数据训练:
- 冻结底层参数,仅微调顶层
-
使用领域内未标注数据继续预训练
-
常见失败模式:
- 损失不下降:检查 tokenizer 是否匹配、学习率是否过高
-
预测结果重复:可能是掩码比例过高导致
-
多任务组合:
- 结合下一句预测 (NSP) 任务
- 最新研究趋势:替换 token 检测 (RTD) 等
延伸思考
为什么 MLM 能提升语义理解?关键在于:
1. 必须同时考虑左右上下文(双向性)
2. 预测任务迫使模型建立词语深层次关联
3. 子词掩码促进形态学特征学习
通过这种 ” 完形填空 ” 式的训练,模型逐渐构建起对语言系统的整体认知,这正是 BERT 强大泛化能力的源泉。
正文完
