迁移学习 - 中文填空案例 - 模型搭建
1 课程概览
本课讲解迁移学习中文填空案例的模型搭建。搭建自定义下游模型,基于 BERT 的填空任务模型。将 BERT 的 768 维输出转成 21128 维(词汇表大小)。只取出被掩码位置的预测概率。使用 bias=False 不考虑偏置。
2 核心概念与定义
- 下游模型:基于 BERT 的填空任务模型。
- vocab_size:词汇表大小(21128)。
- bias=False:不考虑偏置。
- last_hidden_state:最后一个隐藏层。
3 模型与算法详解
模型结构
输入 → BERT(冻结参数) → 768维 → 全连接层 → 21128维 → softmax → 预测字
与中文分类的区别
| 任务 | 输出维度 | 说明 |
|---|---|---|
| 中文分类 | 2 | 二分类(好评/差评) |
| 中文填空 | 21128 | 词汇表大小 |
全连接层
768 → 21128(词汇表大小)
self.fc = nn.Linear(768, my_tokenizer.vocab_size, bias=False)
取出掩码位置
只取出被掩码位置的预测概率。
- 假设句子中只有第 16 个位置被掩码
- 只取第 16 个位置的预测概率
- 如果掩码了多个位置,就取多个
last_hidden_state
最后一个隐藏层。
last_hidden_state = bert_output.last_hidden_state # [batch_size, max_len, 768]
取出指定位置
取出 8 个句子的第 16 个位置。
output = last_hidden_state[:, 16, :] # [batch_size, 768]
4 数学原理与推导
下游模型
$$\text{features} = \text{BERT}(\text{input_ids}, \text{attention_mask}, \text{token_type_ids})$$
$$\text{output} = \text{FC}(\text{features}_{\text{mask_position}})$$
$$\text{prediction} = \text{softmax}(\text{output})$$
其中:
- $\text{features}_{\text{mask_position}}$ 是掩码位置的特征
- $\text{FC}$ 是全连接层(768 → 21128)
- $\text{output}$ 是 21128 维输出
全连接层
$$\text{output} = W \cdot \text{features}$$
其中:
- $W$ 是权重矩阵(768 × 21128)
- 不考虑偏置(bias=False)
5 代码示例
import torch
import torch.nn as nn
from transformers import BertModel
class AiModel(nn.Module):
"""自定义下游模型:基于 BERT 的填空任务模型"""
def __init__(self, my_bert_model, vocab_size):
super(AiModel, self).__init__()
# 1. BERT 预训练模型
self.bert = my_bert_model
# 2. 全连接层:768 → vocab_size(21128),不考虑偏置
self.fc = nn.Linear(768, vocab_size, bias=False)
def forward(self, input_ids, attention_mask, token_type_ids, mask_position=16):
"""
前向传播
Args:
input_ids: 文本的数字编码 [batch_size, max_len]
attention_mask: 注意力掩码 [batch_size, max_len]
token_type_ids: 句子类型标记 [batch_size, max_len]
mask_position: 掩码位置(默认 16)
Returns:
output: 预测概率 [batch_size, vocab_size]
"""
# 1. 不计算 BERT 的梯度(冻结参数)
with torch.no_grad():
bert_output = self.bert(
input_ids=input_ids,
attention_mask=attention_mask,
token_type_ids=token_type_ids
)
# 2. 取最后一个隐藏层
last_hidden_state = bert_output.last_hidden_state # [batch_size, max_len, 768]
# 3. 取出掩码位置的输出
# 8 个句子的第 mask_position 个位置
output = last_hidden_state[:, mask_position, :] # [batch_size, 768]
# 4. 全连接层分类
output = self.fc(output) # [batch_size, vocab_size]
return output
# 测试
if __name__ == "__main__":
print("=== 迁移学习:中文填空案例 - 模型搭建 ===")
# 加载 BERT 预训练模型
model_name = "bert-base-chinese"
my_bert_model = BertModel.from_pretrained(model_name)
# 词汇表大小
from transformers import BertTokenizer
my_tokenizer = BertTokenizer.from_pretrained(model_name)
vocab_size = my_tokenizer.vocab_size # 21128
# 创建下游模型
my_model = AiModel(my_bert_model, vocab_size)
# 测试模型结构
print(my_model)
print(f"词汇表大小: {vocab_size}")
代码说明
| 代码 | 说明 |
|---|---|
nn.Linear(768, vocab_size, bias=False) | 全连接层(768 → 21128) |
bert_output.last_hidden_state | 最后一个隐藏层 |
last_hidden_state[:, mask_position, :] | 取掩码位置 |
self.fc(output) | 全连接层分类 |
bias=False | 不考虑偏置 |
6 重难点与易错提醒
- ❗重点:全连接层将 768 维转成 21128 维(词汇表大小)。
- ❗重点:只取出被掩码位置的预测概率。
- ❗重点:使用
bias=False不考虑偏置。 - ⚠️易错:
last_hidden_state[:, mask_position, :]取指定位置。 - 💡技巧:使用
my_tokenizer.vocab_size获取词汇表大小。
7 课堂问答精选
Q1:中文填空模型的全连接层输出多少维?
A:输出 21128 维,即词汇表大小。因为要预测 21128 个字中的一个。
Q2:为什么要 bias=False?
A:因为参数已经很多了,偏置可以不考虑。
Q3:如何取出掩码位置的预测概率?
A:使用 last_hidden_state[:, mask_position, :],取出 8 个句子的第 mask_position 个位置。
Q4:中文填空模型和中文分类模型有什么区别?
A:全连接层输出维度不同。中文分类输出 2 维(二分类),中文填空输出 21128 维(词汇表大小)。
8 本课小结
- 下游模型:基于 BERT 的填空任务模型。
- 全连接层:768 → 21128(词汇表大小),bias=False。
- 只取出被掩码位置的预测概率。
- 使用
last_hidden_state[:, mask_position, :]取指定位置。
9 延伸思考
- 如何进行模型训练?
- 训练流程和中文分类有什么区别?