共计 1766 个字符,预计需要花费 5 分钟才能阅读完成。
NLP 发展背景与 RNN 的局限性
在 Transformer 出现之前,循环神经网络(RNN)及其变体 LSTM、GRU 是处理序列任务的主流架构。但这些模型存在两个致命缺陷:

- 顺序计算瓶颈:必须逐个处理序列中的 token,无法并行化。处理 100 个 token 的文本所需时间大约是处理 10 个 token 的 10 倍。
- 长程依赖丢失:随着序列长度增加,早期 token 的信息在传递过程中逐渐衰减。实验显示 LSTM 在超过 200 个 token 时召回率下降 37%。
Transformer 架构解析
2017 年提出的 Transformer 完全摒弃了循环结构,其核心是下图所示的 self-attention 机制:
[Input Embedding] -> [Positional Encoding]
-> [Multi-Head Attention] -> [Feed Forward]
-> [Layer Norm] -> (重复 N 次)
关键组件说明:
- 多头注意力 :将输入投影到 Q(查询)、K(键)、V(值) 三个空间,计算相似度得分。例如 8 个头时,每个头处理 64 维子空间(假设 512 维嵌入)。
- 位置编码:通过正弦函数注入位置信息,使模型感知 token 顺序。公式为 PE(pos,2i)=sin(pos/10000^(2i/d_model))。
- 层归一化:对每个子层输出进行归一化,稳定训练过程。相比批归一化更适合变长输入。
BERT 的预训练与微调
BERT 通过两种任务预训练语言表示:
- 掩码语言模型(MLM):随机遮盖 15% 的 token,其中 80% 替换为[MASK],10% 替换为随机 token,10% 保持不变。目标预测原始 token。
- 下一句预测(NSP):判断两个句子是否连续,正负样本各 50%。
微调时只需添加任务特定层。例如文本分类的典型结构:
from transformers import BertForSequenceClassification
model = BertForSequenceClassification.from_pretrained(
'bert-base-uncased',
num_labels=2
)
完整代码示例(PyTorch)
环境要求:Python 3.8+, torch 1.12+, transformers 4.30+
# 数据预处理
from transformers import BertTokenizer
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
text = "This is a BERT tutorial."
inputs = tokenizer(text, return_tensors="pt", padding=True, truncation=True)
# 模型加载
model = BertModel.from_pretrained('bert-base-uncased')
outputs = model(**inputs)
# 获取最后一层隐藏状态
last_hidden_states = outputs.last_hidden_state # [1, seq_len, 768]
计算资源优化
在 RTX 3090(24GB)上的实测数据:
| 模型变体 | 最大批处理大小 | 显存占用 |
|---|---|---|
| bert-base | 32 | 18GB |
| bert-large | 8 | 22GB |
优化技巧:
- 梯度累积 :通过多次前向传播累积梯度再更新参数。例如设置
accumulation_steps=4等效增大批大小 4 倍。 - 混合精度 :使用
torch.cuda.amp自动管理 fp16/fp32 转换,可节省 30% 显存。
新手避坑指南
常见问题与解决方案:
- OOM 错误:
- 降低
max_seq_length(通常 128-256 足够) - 启用
gradient_checkpointing(计算时间换显存) - 注意力权重异常:
- 检查输入是否包含过多[PAD] token
- 可视化注意力矩阵定位问题层
延伸思考
留给读者的三个开放性问题:
- 当处理中文时,基于字和基于词的输入哪种更适合 BERT?为什么?
- 如何设计实验验证不同注意力头确实学习了不同的特征?
- 在低资源语言场景下,哪些预训练策略可以提升 BERT 效果?
通过本指南,你应该已经掌握了 BERT 的核心原理和实践方法。建议从 bert-base 开始实验,逐步探索更复杂的应用场景。记住,理解模型行为最好的方式就是不断尝试和观察其输出。
正文完
发表至: 自然语言处理
近一天内
