微调模型:识别文本情感倾向(积极/消极)

651 阅读5分钟

背景

在通过微调谷歌的 bert-base-chinese 模型,实现文本情感分析。该过程将帮助我们更好地理解和应用预训练模型。

流程

  1. 数据集准备
  2. 使用分词器处理文本
  3. 准备训练数据
  4. 加载预训练模型
  5. 调整模型参数
  6. 训练模型
  7. 保存微调后的模型

平台

模型和数据集下载平台:

Hugging Face(需要魔法)

HF-Mirror

模型

使用谷歌的中文 BERT 模型(google-bert/bert-base-chinese),相较于 Word2Vec,BERT 更加强调上下文关系的理解。

举个例子,当你说到“苹果”时,可能会联想到它的颜色、形状和口感,比如红红的、圆圆的、脆脆的,当然也可能有人联想到青青的。在这种情况下,我们可以用这三个维度(颜色、形状、口感)来表示苹果。

但是如果你说“我不用苹果手机”,这里的“苹果”就有了不同的联想,可能让你想到系统流畅、高端、简约的设计,当然它也有颜色、形状和材料等维度(白色、长方形、硬)。此时,你会发现同一个词在不同的上下文中会产生不同的意思,这主要受到上下文的影响:一个是“吃”,另一个是“手机”。可以将这看作是在两种力量的拉扯,一个将“苹果”拉向食物的区域,另一个则将其拉向产品的区域。

ef8a8fd4-07ad-47b1-909d-aecd728a826d.png

简单了解一下分词器,像句子“我喜欢吃苹果”会被分词器处理为“[CLS]”、“我”、“喜欢”、“吃”、“苹果”、“[SEP]”。由于 BERT 是双向的,每个单词都包含了整个文本的信息。我们可以使用“[CLS]”的向量,通过全连接层将其映射到分类任务中(0和1)。

训练集

使用 lansinuote/ChnSentiCorp 数据集进行情感分析,标签示例如下:1 表示积极情感,0 表示消极情感,如图所示。 QQ20250219-110304.png

云上训练

我使用的是谷歌的 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几分钟,感觉还行。

QQ20250219-032431.png

本机训练

使用本机训练需要好的显卡。因为国内的网络问题,需要手动下载模型和训练数据集。

国内访问不了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

下载好的模型和数据集,如图:

QQ20250219-030847.png

安装必要库(使用阿里云镜像源)

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直接打满,显卡不行,还得在线上训练。

QQ20250219-080821.png

应用

我们可以看到今日头条中有些评论是有显示红方(积极)和蓝方(消极),如图下

Screenshot_2025-02-19-10-40-47-467_com.ss.android.jpg

我们就用那蓝方那个评论模型推理一下,如图输出0说明是消极(蓝方)

QQ20250219-104731.png