本文目录导读:
要实现高精度情感分析,微调BERT是一个经典且高效的方法,下面我会给你一个完整的端到端案例,包括数据准备、模型加载、微调、评估和推理,并附上关键优化技巧。
环境准备
pip install transformers datasets torch scikit-learn pandas
数据准备(以IMDB电影评论为例)
from datasets import load_dataset
# 加载IMDB数据集(5万条,二分类:positive/negative)
dataset = load_dataset("imdb")
print(dataset)
如果你的数据是自定义的CSV,这样加载:
import pandas as pd
df = pd.read_csv("your_data.csv") # 需要包含 'text' 和 'label' 列
核心微调代码
import torch
from transformers import BertTokenizer, BertForSequenceClassification, Trainer, TrainingArguments
from datasets import load_dataset
# 1. 加载预训练模型和分词器
model_name = "bert-base-uncased" # 或 "bert-base-chinese" 用于中文
tokenizer = BertTokenizer.from_pretrained(model_name)
model = BertForSequenceClassification.from_pretrained(model_name, num_labels=2)
# 2. 数据预处理(关键步骤)
def preprocess_function(examples):
# 分词并设置最大长度(平衡性能和精度)
return tokenizer(
examples["text"],
truncation=True,
padding="max_length",
max_length=256 # IMDB评论较长,建议128-512
)
# 应用预处理
dataset = load_dataset("imdb")
encoded_dataset = dataset.map(preprocess_function, batched=True)
# 3. 设置训练参数(重点关注以下参数)
training_args = TrainingArguments(
output_dir="./results",
learning_rate=2e-5, # BERT微调常用学习率
per_device_train_batch_size=8, # 根据GPU显存调整
per_device_eval_batch_size=8,
num_train_epochs=3, # 通常2-4轮足够
weight_decay=0.01, # 防止过拟合
evaluation_strategy="epoch",
save_strategy="epoch",
logging_dir="./logs",
logging_steps=100,
load_best_model_at_end=True,
metric_for_best_model="accuracy",
warmup_steps=500, # 学习率预热
lr_scheduler_type="linear", # 线性衰减
)
# 4. 定义评估指标
from sklearn.metrics import accuracy_score, f1_score
def compute_metrics(pred):
labels = pred.label_ids
preds = pred.predictions.argmax(-1)
return {
"accuracy": accuracy_score(labels, preds),
"f1": f1_score(labels, preds, average="binary")
}
# 5. 训练
trainer = Trainer(
model=model,
args=training_args,
train_dataset=encoded_dataset["train"].select(range(5000)), # 可用部分数据测试
eval_dataset=encoded_dataset["test"].select(range(2000)),
tokenizer=tokenizer,
compute_metrics=compute_metrics,
)
trainer.train()
推理预测
def predict_sentiment(text):
# 格式化输入(BERT要求加特殊token)
inputs = tokenizer(
text,
return_tensors="pt",
truncation=True,
padding=True,
max_length=256
)
with torch.no_grad():
outputs = model(**inputs)
probs = torch.nn.functional.softmax(outputs.logits, dim=-1)
prediction = torch.argmax(probs, dim=-1).item()
return {
"sentiment": "positive" if prediction == 1 else "negative",
"confidence": probs[0][prediction].item()
}
# 测试
print(predict_sentiment("This movie was absolutely fantastic!"))
print(predict_sentiment("Waste of time, terrible acting."))
提升精度的5个关键技巧
① 学习率与优化器
- 使用AdamW(已默认),学习率
2e-5到5e-5 - 添加warmup steps(占总步数的10%)
② 处理序列长度
- 情感分析中,256-512 token 通常最佳
- 可分析数据长度分布后设置合理max_length
③ 类别平衡
如果你的数据不平衡:
from torch.utils.data import WeightedRandomSampler # 计算权重,给少数类更大采样权重
④ 数据增强(提升泛化)
# 可尝试:同义词替换、回译(back translation) # 对于中文:nlpcda库提供文本增强
⑤ 分层学习率(可选高级技巧)
# BERT层用较小学习率,分类头用较大学习率
optimizer_grouped_parameters = [
{"params": model.bert.parameters(), "lr": 1e-5},
{"params": model.classifier.parameters(), "lr": 2e-5}
]
预期结果
使用IMDB全量数据(25000训练/25000测试)微调3轮: | 模型 | 准确率 | F1分数 | |------|--------|--------| | BERT-base | 93-94% | 0.93-0.94 | | DistilBERT | 91-92% | 0.91-0.92 | | RoBERTa | 94-95% | 0.94-0.95 |
完整训练脚本
如果你想一键运行,这是精简版:
import torch from transformers import AutoTokenizer, AutoModelForSequenceClassification, Trainer # 一行代码微调(使用HF的AutoModel) model_name = "distilbert-base-uncased" # 更轻量,精度略低但速度快 tokenizer = AutoTokenizer.from_pretrained(model_name) model = AutoModelForSequenceClassification.from_pretrained(model_name, num_labels=2) # 其余代码同上...
遇到问题怎么办?
- 显存不足:减小batch_size或max_length
- 训练太慢:尝试DistilBERT或使用梯度累积
- 过拟合:增加weight_decay、减小epoch、使用dropout
- 中文效果差:切换为
bert-base-chinese或chinese-roberta-wwm-ext
需要我帮你针对中文情感分析或多分类情感(如积极/消极/中性)调整代码吗?
标签: 情感分析