共计 4449 个字符,预计需要花费 12 分钟才能阅读完成。
背景介绍
中文文本分类是自然语言处理中最常见的任务之一,广泛应用于情感分析、新闻分类、意图识别等场景。bert-base-chinese 作为谷歌发布的预训练中文 BERT 模型,凭借其强大的语义理解能力和迁移学习特性,已经成为中文 NLP 任务的基准模型。

与传统的机器学习方法相比,BERT 模型最大的优势在于:
- 能够自动学习文本的上下文表示
- 预训练过程已经捕获了大量中文语言知识
- 通过微调即可适配各种下游任务
- 在多分类任务上通常能取得 state-of-the-art 的效果
环境准备
在开始之前,我们需要准备好 Python 开发环境。推荐使用 Python 3.7+ 版本,并安装以下依赖库:
Python 3.7+
PyTorch 1.8.0+
transformers 4.0.0+
torchtext 0.9.0+
pandas
numpy
sklearn
tqdm
可以通过 pip 一键安装:
pip install torch transformers torchtext pandas numpy scikit-learn tqdm
数据预处理
1. 数据格式要求
多分类任务的数据集通常需要包含文本和标签两列。一个典型的数据格式如下:
text,label
"这个电影太好看了","positive"
"服务态度很差","negative"
...
2. 文本清洗
中文文本通常需要进行以下预处理:
- 去除特殊字符和标点
- 统一全角半角字符
- 处理多余空格
- 繁简转换(如果需要)
示例代码:
import re
def clean_text(text):
# 去除特殊字符
text = re.sub(r'[\s\n\r\t]+', ' ', text)
# 统一全半角
text = text.translate(str.maketrans(
',。!?【】()%#@&1234567890',
',.!?[]()%#@&1234567890'))
return text.strip()
3. 标签编码
我们需要将文本标签转换为数字索引。使用 sklearn 的 LabelEncoder 可以轻松实现:
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
labels = le.fit_transform(df['label'].values)
num_classes = len(le.classes_)
模型加载与配置
1. 加载预训练模型
使用 transformers 库加载 bert-base-chinese 模型:
from transformers import BertTokenizer, BertForSequenceClassification
model_name = 'bert-base-chinese'
tokenizer = BertTokenizer.from_pretrained(model_name)
model = BertForSequenceClassification.from_pretrained(
model_name,
num_labels=num_classes
)
2. 修改输出层
默认情况下,BertForSequenceClassification 已经为我们添加了适合分类任务的输出层。我们只需要指定类别数量即可。
训练过程
1. 数据加载器
我们需要将文本转换为 BERT 能够处理的格式,并创建 PyTorch 的 DataLoader:
from torch.utils.data import Dataset, DataLoader
class TextDataset(Dataset):
def __init__(self, texts, labels, tokenizer, max_len):
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.encode_plus(
text,
add_special_tokens=True,
max_length=self.max_len,
return_token_type_ids=False,
padding='max_length',
truncation=True,
return_attention_mask=True,
return_tensors='pt'
)
return {'input_ids': encoding['input_ids'].flatten(),
'attention_mask': encoding['attention_mask'].flatten(),
'labels': torch.tensor(label, dtype=torch.long)
}
MAX_LEN = 128
BATCH_SIZE = 16
train_dataset = TextDataset(train_texts, train_labels, tokenizer, MAX_LEN)
train_loader = DataLoader(train_dataset, batch_size=BATCH_SIZE, shuffle=True)
2. 训练设置
from transformers import AdamW, get_linear_schedule_with_warmup
EPOCHS = 3
LEARNING_RATE = 2e-5
optimizer = AdamW(model.parameters(), lr=LEARNING_RATE, correct_bias=False)
total_steps = len(train_loader) * EPOCHS
scheduler = get_linear_schedule_with_warmup(
optimizer,
num_warmup_steps=0,
num_training_steps=total_steps
)
loss_fn = torch.nn.CrossEntropyLoss().to(device)
3. 训练循环
model = model.to(device)
model.train()
for epoch in range(EPOCHS):
for batch in train_loader:
input_ids = batch['input_ids'].to(device)
attention_mask = batch['attention_mask'].to(device)
labels = batch['labels'].to(device)
outputs = model(
input_ids=input_ids,
attention_mask=attention_mask,
labels=labels
)
loss = outputs.loss
loss.backward()
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
optimizer.step()
scheduler.step()
optimizer.zero_grad()
评估与调优
1. 评估指标
常用的分类评估指标包括:
- 准确率 (Accuracy)
- 精确率 (Precision)
- 召回率 (Recall)
- F1 值
可以使用 sklearn 计算这些指标:
from sklearn.metrics import classification_report
def evaluate(model, data_loader):
model.eval()
predictions = []
true_labels = []
with torch.no_grad():
for batch in data_loader:
input_ids = batch['input_ids'].to(device)
attention_mask = batch['attention_mask'].to(device)
labels = batch['labels'].to(device)
outputs = model(input_ids, attention_mask=attention_mask)
_, preds = torch.max(outputs.logits, dim=1)
predictions.extend(preds.cpu().tolist())
true_labels.extend(labels.cpu().tolist())
print(classification_report(true_labels, predictions, target_names=le.classes_))
2. 调优技巧
- 学习率:通常 2e- 5 到 5e- 5 效果较好
- Batch Size:根据显存大小选择,一般 16-32
- 训练轮数:3- 5 个 epoch 通常足够
- 序列长度:128 或 256
- Warmup:可以设置 500-1000 步 warmup
避坑指南
- 显存不足 :可以尝试减小 batch size 或序列长度,使用梯度累积
- 过拟合 :增加 dropout 率,使用早停法,添加 L2 正则化
- 训练不稳定 :调整学习率,使用学习率 warmup
- 标签不平衡 :使用类别权重或过采样 / 欠采样
- 中文分词问题 :BERT 使用字级别 tokenizer,不需要额外分词
完整代码示例
# 完整代码请参考上述分步示例
# 这里展示模型保存和加载的方法
# 保存模型
model.save_pretrained('./saved_model')
tokenizer.save_pretrained('./saved_model')
# 加载模型
model = BertForSequenceClassification.from_pretrained('./saved_model')
tokenizer = BertTokenizer.from_pretrained('./saved_model')
延伸阅读与练习
延伸阅读
- BERT 原论文:”BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding”
- HuggingFace Transformers 文档
- PyTorch 官方教程
练习
- 尝试在不同数据集上应用本教程
- 比较不同学习率和 batch size 的效果
- 实现早停法 (early stopping)
- 尝试不同的优化器 (如 Adam, SGD 等)
- 探索模型蒸馏等压缩技术
总结
通过本教程,我们学习了如何从零开始使用 bert-base-chinese 模型进行中文文本多分类任务。整个过程包括数据预处理、模型加载与配置、训练调参、评估优化等关键步骤。BERT 模型虽然强大,但需要合理设置超参数才能发挥最佳性能。希望这篇指南能帮助 NLP 初学者快速上手 BERT 模型微调。
正文完
