迁移学习 - 中文分类案例 - 模型搭建
1 课程概览
本课讲解迁移学习中文分类案例的模型搭建。搭建自定义下游模型,基于 BERT 的文本分类模型。将 BERT 的 768 维输出转成 2 维(二分类)。下游模型是在 BERT 处理之后的模型。冻结 BERT 参数,只训练自定义分类层。
2 核心概念与定义
- 下游模型:在 BERT 处理之后的模型,将 768 维转成 2 维。
- 上游模型:BERT 预训练模型,处理数据之前。
- 全连接层(FC, Fully Connected):将 768 维转成 2 维。
- 冻结参数:不计算 BERT 的梯度,只训练自定义分类层。
3 模型与算法详解
下游模型概念
在 BERT 处理之后的模型,将 768 维转成 2 维。
- BERT 词向量维度:768 维
- 二分类:2 维(好评/差评)
- 下游模型:全连接层
模型输入
| 输入 | 说明 | 形状 |
|---|---|---|
| input_ids | 文本的数字编码 | [batch_size, max_len](8, 300) |
| token_type_ids | 句子类型标记 | [batch_size, max_len](8, 300) |
| attention_mask | 注意力掩码(是否填充) | [batch_size, max_len](8, 300) |
冻结 BERT 参数
不计算 BERT 的梯度,只训练自定义分类层。
with torch.no_grad():
# BERT 前向传播
output = my_bert_model(...)
模型结构
输入 → BERT(冻结参数) → 768维 → 全连接层 → 2维 → softmax → 分类结果
4 数学原理与推导
下游模型
$$\text{features} = \text{BERT}(\text{input_ids}, \text{attention_mask}, \text{token_type_ids})$$
$$\text{output} = \text{FC}(\text{features})$$
$$\text{prediction} = \text{softmax}(\text{output})$$
其中:
- $\text{BERT}$ 是预训练模型(768 维输出)
- $\text{FC}$ 是全连接层(768 → 2)
- $\text{output}$ 是 2 维输出
全连接层
$$\text{output} = W \cdot \text{features} + b$$
其中:
- $W$ 是权重矩阵(768 × 2)
- $b$ 是偏置(2)
5 代码示例
import torch
import torch.nn as nn
from transformers import BertModel
class AiModel(nn.Module):
"""自定义下游模型:基于 BERT 的文本分类模型"""
def __init__(self, my_bert_model):
super(AiModel, self).__init__()
# 1. BERT 预训练模型
self.bert = my_bert_model
# 2. 全连接层:768 → 2(二分类)
self.fc = nn.Linear(768, 2)
def forward(self, input_ids, attention_mask, token_type_ids):
"""
前向传播
Args:
input_ids: 文本的数字编码 [batch_size, max_len]
attention_mask: 注意力掩码 [batch_size, max_len]
token_type_ids: 句子类型标记 [batch_size, max_len]
Returns:
output: 二分类结果 [batch_size, 2]
"""
# 1. 不计算 BERT 的梯度(冻结参数)
with torch.no_grad():
# 获取 BERT 模型的输出
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. 取 [CLS] 位置的输出(第 0 个位置)
cls_output = last_hidden_state[:, 0, :] # [batch_size, 768]
# 4. 全连接层分类
output = self.fc(cls_output) # [batch_size, 2]
return output
# 测试
if __name__ == "__main__":
print("=== 迁移学习:中文分类案例 - 模型搭建 ===")
# 加载 BERT 预训练模型
model_name = "bert-base-chinese"
my_bert_model = BertModel.from_pretrained(model_name)
# 创建下游模型
my_model = AiModel(my_bert_model)
# 测试模型结构
print(my_model)
代码说明
| 代码 | 说明 |
|---|---|
nn.Module | 继承 PyTorch 模型基类 |
self.bert = my_bert_model | BERT 预训练模型 |
self.fc = nn.Linear(768, 2) | 全连接层(768 → 2) |
with torch.no_grad(): | 不计算梯度(冻结参数) |
bert_output.last_hidden_state | 最后一个隐藏层 |
cls_output = last_hidden_state[:, 0, :] | 取 [CLS] 位置 |
self.fc(cls_output) | 全连接层分类 |
6 重难点与易错提醒
- ❗重点:下游模型是在 BERT 处理之后的模型。
- ❗重点:BERT 词向量维度是 768 维。
- ❗重点:冻结 BERT 参数,只训练自定义分类层。
- ⚠️易错:取 [CLS] 位置(第 0 个位置)的输出。
- 💡技巧:全连接层用
nn.Linear(768, 2)。
7 课堂问答精选
Q1:为什么叫下游模型?
A:因为是在 BERT 处理之后的模型。BERT 处理完后得到 768 维数据,下游模型将 768 维转成 2 维。
Q2:为什么是 768 维转成 2 维?
A:BERT 词向量维度是 768 维,二分类(好评/差评)是 2 维。
Q3:为什么要冻结 BERT 参数?
A:BERT 是已经预训练好的模型,如果再更新参数就是模型微调。这里只训练自定义分类层,所以冻结 BERT 参数。
Q4:如何冻结 BERT 参数?
A:使用 with torch.no_grad(): 包裹 BERT 的前向传播,不计算梯度。
8 本课小结
- 下游模型:在 BERT 处理之后的模型。
- 全连接层:768 维 → 2 维(二分类)。
- 冻结 BERT 参数:
with torch.no_grad():。 - 取 [CLS] 位置的输出进行分类。
9 延伸思考
- 如何进行模型训练?
- 训练流程是什么?