本文目录导读:

Python实战案例:如何用BERT进行文本分类(从原理到代码全解析)
文章导读目录
- 背景与痛点:为什么传统文本分类方法不够用?
- BERT核心原理:一分钟看懂Transformer与预训练机制
- 环境搭建:Python包安装与GPU配置要点
- 数据准备:中文情感分析数据集清洗与标签处理
- 加载预训练模型:使用
transformers库加载bert-base-chinese - 模型微调:自定义分类头,冻结部分层,训练循环代码
- 完整案例演示:训练日志、准确率指标、预测输出
- 常见FAQ问答:解决过拟合、OOM爆显存、长文本截断问题
- SEO友好总结:BERT文本分类的落地建议与资源推荐
背景与痛点
传统文本分类常用TF-IDF+朴素贝叶斯或Word2Vec+LSTM,但这类方法无法捕捉上下文语义——苹果很好吃”与“苹果发布了新手机”中的“苹果”词义完全不同,BERT(Bidirectional Encoder Representations from Transformers)通过双向注意力机制和大规模预训练,能根据上下文动态理解词义,显著提升分类准确率。
BERT核心原理(快速科普)
BERT基于Transformer的Encoder部分,创新点在于:
- 双向训练:同时看左边和右边的词语(传统RNN只能从左到右);
- 预训练+微调:先用海量无标注文本学习语言知识,再针对分类任务做简单调整;
- 输入表示:
[CLS]标签的最终隐层向量作为整句语义代表,直接接分类器。
了解这些即可开始实战,无需深究注意力公式。
环境搭建
# 推荐使用Python 3.8+,建议用conda创建虚拟环境 pip install torch transformers pandas scikit-learn
GPU提示:若显存小于6GB,请使用Google Colab的免费GPU(T4),或改用bert-base-uncased(英文)减少显存占用。
数据准备(中文情感分析为例)
我们使用IMDb中文翻译版(或爬取京东评论),格式如下:
| text | label |
|---|---|
| 物流很快,包装完好,非常满意 | 1 (正面) |
| 质量太差,用了三天就坏了 | 0 (负面) |
关键代码:
import pandas as pd
df = pd.read_csv('sentiment.csv')
# 标签必须从0开始编码
labels = df['label'].tolist()
texts = df['text'].tolist()
加载预训练模型与分词器
from transformers import BertTokenizer, BertForSequenceClassification
model_name = 'bert-base-chinese' # 中文BERT
tokenizer = BertTokenizer.from_pretrained(model_name)
model = BertForSequenceClassification.from_pretrained(model_name, num_labels=2)
# 将模型移到GPU
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model.to(device)
重要:
BertForSequenceClassification自动在BERT后添加了分类线性层,无需手动构建。
模型微调:核心代码
1 数据编码与DataLoader
from torch.utils.data import DataLoader, TensorDataset
def encode_texts(texts, labels, max_len=128):
inputs = tokenizer(texts, padding=True, truncation=True,
max_length=max_len, return_tensors='pt')
return TensorDataset(inputs['input_ids'], inputs['attention_mask'],
torch.tensor(labels))
train_dataset = encode_texts(train_texts, train_labels)
train_loader = DataLoader(train_dataset, batch_size=16, shuffle=True)
2 训练循环(仅需微调5~10个epoch)
from torch.optim import AdamW
from tqdm import tqdm
optimizer = AdamW(model.parameters(), lr=2e-5)
model.train()
for epoch in range(5):
total_loss = 0
for batch in tqdm(train_loader):
input_ids, attention_mask, labels = [b.to(device) for b in batch]
outputs = model(input_ids, attention_mask=attention_mask, labels=labels)
loss = outputs.loss
loss.backward()
optimizer.step()
optimizer.zero_grad()
total_loss += loss.item()
print(f"Epoch {epoch+1}, Loss: {total_loss/len(train_loader):.4f}")
技巧:若数据量<1万,建议冻结BERT前6层(
for param in model.bert.encoder.layer[:6].parameters(): param.requires_grad = False)以防止过拟合。
完整案例演示:预测新文本
model.eval()
test_text = ["这个产品真的太好了,下次还会买"]
inputs = tokenizer(test_text, return_tensors='pt', padding=True, truncation=True).to(device)
with torch.no_grad():
outputs = model(**inputs)
probs = torch.nn.functional.softmax(outputs.logits, dim=-1)
pred = torch.argmax(probs, dim=1)
print(f"预测标签: {pred.item()},正面概率: {probs[0][1]:.2f}")
输出示例:预测标签: 1,正面概率: 0.97(说明模型判断为正面)。
常见FAQ问答
Q1:训练时显存溢出(OOM)怎么办?
A:降低batch_size(改为8或4),或使用gradient_accumulation_steps累积梯度,另外max_len不要超过256。
Q2:模型在验证集上准确率低?
A:检查数据标签是否平衡;尝试使用torch.nn.CrossEntropyLoss的weight参数处理不平衡;或增加训练epoch到10轮。
Q3:长文本如何截断?
A:BERT最大输入长度512,超出的部分可截取开头和结尾(truncation='longest_first'),或使用Longformer替代。
Q4:如何保存和加载模型?
A:model.save_pretrained('./my_bert_model'),加载时用BertForSequenceClassification.from_pretrained('./my_bert_model')。
SEO友好总结
本文通过一个完整的Python案例,手把手教会你如何用BERT进行中文文本分类,核心要点:
- 使用预训练模型避免从头训练;
- 微调时设置小学习率(2e-5);
- 通过分词器统一处理输入格式;
- 注意显存限制与数据平衡。
如果你遇到具体代码问题,欢迎在评论区留言,未来可尝试将BERT替换为RoBERTa或DistilBERT(更轻量)以获得更佳效果。
推荐学习资源:
- Hugging Face官方文档:transformers文档(请手动复制到浏览器打开)
- 吴恩达《BERT情感分类》微调视频教程
(本文已整合Google、Bing搜索结果,并去除重复性内容,保留核心技术细节)