背景
在通过微调谷歌的 bert-base-chinese 模型,实现文本情感分析。该过程将帮助我们更好地理解和应用预训练模型。
流程
- 数据集准备
- 使用分词器处理文本
- 准备训练数据
- 加载预训练模型
- 调整模型参数
- 训练模型
- 保存微调后的模型
平台
模型和数据集下载平台:
Hugging Face(需要魔法)
模型
使用谷歌的中文 BERT 模型(google-bert/bert-base-chinese),相较于 Word2Vec,BERT 更加强调上下文关系的理解。
举个例子,当你说到“苹果”时,可能会联想到它的颜色、形状和口感,比如红红的、圆圆的、脆脆的,当然也可能有人联想到青青的。在这种情况下,我们可以用这三个维度(颜色、形状、口感)来表示苹果。
但是如果你说“我不用苹果手机”,这里的“苹果”就有了不同的联想,可能让你想到系统流畅、高端、简约的设计,当然它也有颜色、形状和材料等维度(白色、长方形、硬)。此时,你会发现同一个词在不同的上下文中会产生不同的意思,这主要受到上下文的影响:一个是“吃”,另一个是“手机”。可以将这看作是在两种力量的拉扯,一个将“苹果”拉向食物的区域,另一个则将其拉向产品的区域。
简单了解一下分词器,像句子“我喜欢吃苹果”会被分词器处理为“[CLS]”、“我”、“喜欢”、“吃”、“苹果”、“[SEP]”。由于 BERT 是双向的,每个单词都包含了整个文本的信息。我们可以使用“[CLS]”的向量,通过全连接层将其映射到分类任务中(0和1)。
训练集
使用 lansinuote/ChnSentiCorp 数据集进行情感分析,标签示例如下:1 表示积极情感,0 表示消极情感,如图所示。
云上训练
我使用的是谷歌的 Colab 平台(需要魔法),利用免费的 T4 GPU 进行训练,因为本机的性能较慢。
以下是 Colab 中的代码,用于安装所需环境:
pip install datasets transformers
训练代码:
from datasets import load_dataset
from transformers import AutoTokenizer
from transformers import AutoModelForSequenceClassification
from transformers import TrainingArguments, Trainer
import numpy as np
tokenizer = AutoTokenizer.from_pretrained("google-bert/bert-base-chinese")
model = AutoModelForSequenceClassification.from_pretrained("google-bert/bert-base-chinese", num_labels=2)
def tokenize_function(examples):
return tokenizer(examples["text"], padding="max_length", truncation=True)
# metric = evaluate.load("accuracy")
# 自定义评估函数
def compute_metrics(eval_pred):
logits, labels = eval_pred
predictions = np.argmax(logits, axis=-1) # 取最可能的类别
accuracy = np.sum(predictions == labels) / len(labels) # 计算准确率
return {"accuracy": accuracy}
training_args = TrainingArguments(output_dir="test_trainer", eval_strategy="epoch")
if __name__ == '__main__':
# 加载本地数据集
dataset = load_dataset("lansinuote/ChnSentiCorp")
print()
# 打印训练集的第 100 条样本
print(dataset["train"][100])
tokenized_datasets = dataset.map(tokenize_function, batched=True)
small_train_dataset = tokenized_datasets["train"]
small_eval_dataset = tokenized_datasets["test"]
trainer = Trainer(
model=model,
args=training_args,
train_dataset=small_train_dataset,
eval_dataset=small_eval_dataset,
compute_metrics=compute_metrics,
)
trainer.train()
# 保存模型
model.save_pretrained("./fine-tuned-bert")
tokenizer.save_pretrained("./fine-tuned-bert")
加载模型:
from transformers import AutoTokenizer, AutoModelForSequenceClassification
# 加载保存的模型和分词器
model = AutoModelForSequenceClassification.from_pretrained("./fine-tuned-bert")
tokenizer = AutoTokenizer.from_pretrained("./fine-tuned-bert")
进行推理:
# 假设我们有一个新的文本数据
text = "除了院线等分成,还有宣传等费用,主创难暴富"
# 使用分词器对文本进行编码
inputs = tokenizer(text, return_tensors="pt", padding=True, truncation=True)
# 使用模型进行推理
with torch.no_grad():
logits = model(**inputs).logits
# 获取预测的类别
_class = torch.argmax(logits, dim=-1).item()
# 打印预测结果
print(f"Predicted class: {predicted_class}")
下面是部分的截图,这个模型训练了50几分钟,感觉还行。
本机训练
使用本机训练需要好的显卡。因为国内的网络问题,需要手动下载模型和训练数据集。
国内访问不了Hugging Face,可以使用HF-Mirror代替。
下面是我使用到的下载模型和数据集的命令,在控制台打开输入:
1.安装依赖
pip install -U huggingface_hub
2.设置环境变量(windows环境)
$env:HF_ENDPOINT = "https://hf-mirror.com"
3-1.下载模型
huggingface-cli download --resume-download google-bert/bert-base-chinese --local-dir ./models/bert-base-chinese
3-2.下载数据集
huggingface-cli download --repo-type dataset --resume-download lansinuote/chnsenticorp --local-dir ./data/chnsenticorp
下载好的模型和数据集,如图:
安装必要库(使用阿里云镜像源)
pip install transformers transformers[torch] datasets torch -i https://mirrors.aliyun.com/pypi/simple/
安装 GPU 版本的 PyTorch
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
下面微调训练代码:
from transformers import BertTokenizer, BertForSequenceClassification, Trainer, TrainingArguments
from datasets import load_dataset
import numpy as np
if __name__ == '__main__':
# 加载数据集
dataset = load_dataset("./data/chnsenticorp")
# 加载分词器和模型
tokenizer = BertTokenizer.from_pretrained("./models/bert-base-chinese")
model = BertForSequenceClassification.from_pretrained("./models/bert-base-chinese", num_labels=2)
# 数据预处理
def preprocess_function(examples):
return tokenizer(examples["text"], padding="max_length", truncation=True)
encoded_dataset = dataset.map(preprocess_function, batched=True)
def compute_metrics(eval_pred):
logits, labels = eval_pred
# 使用 argmax 获得每个输入的最大分数对应的索引作为预测类别
predictions = np.argmax(logits, axis=-1)
# 计算准确性
acc = np.sum(predictions == labels) / len(labels)
return {"accuracy": acc}
# 设置训练参数
training_args = TrainingArguments(
output_dir="./results",
evaluation_strategy="epoch",
learning_rate=2e-5,
per_device_train_batch_size=16,
per_device_eval_batch_size=16,
num_train_epochs=3,
weight_decay=0.01,
save_strategy="epoch",
logging_dir="./logs",
)
# 创建 Trainer
trainer = Trainer(
model=model,
args=training_args,
train_dataset=encoded_dataset["train"],
eval_dataset=encoded_dataset["test"],
tokenizer=tokenizer,
compute_metrics=compute_metrics,
)
# 开始训练
trainer.train()
# 保存模型
model.save_pretrained("./fine-tuned-bert")
tokenizer.save_pretrained("./fine-tuned-bert")
加载模型进行推理代码:
from transformers import AutoTokenizer, AutoModelForSequenceClassification
import torch
if __name__ == '__main__':
# 加载保存的模型和分词器
model = AutoModelForSequenceClassification.from_pretrained("./fine-tuned-bert2")
tokenizer = AutoTokenizer.from_pretrained("./fine-tuned-bert2")
# 假设我们有一个新的文本数据
text = "我很快乐"
# 使用分词器对文本进行编码
inputs = tokenizer(text, return_tensors="pt", padding=True, truncation=True)
# 使用模型进行推理
with torch.no_grad():
logits = model(**inputs).logits
# 获取预测的类别
predicted_class = torch.argmax(logits, dim=-1).item()
# 打印预测结果
print(f"Predicted class: {predicted_class}")
下面是我本机训练的性能图,GPU直接打满,显卡不行,还得在线上训练。
应用
我们可以看到今日头条中有些评论是有显示红方(积极)和蓝方(消极),如图下
我们就用那蓝方那个评论模型推理一下,如图输出0说明是消极(蓝方)