BERT文本分类实战----美团外卖评论情绪分类

HuggingFace 提供了巨大的模型库,虽然其中的很多模型性能表现出色,但这些模型往往是在广义的数据集上训练的,缺乏针对特定数据集的优化,所以在获得一个合适的模型之后,往往还要针对具体任务的特定数据集进行二次训练,这就是所谓的迁移学习。迁移学习的训练难度低,要求的数据集数量少,对计算资源的要求也低。

HuggingFace 提供了训练工具,统一了模型的再训练过程,使调用者无须了解具体模型的计算过程,只需针对具体的任务准备好数据集,便可以再训练模型。

本次将使用一个情感分类任务的例子来再训练一个模型,以此来讲解HuggingFace训练工具的使用方法

本文的代码和数据集已上传至GitHub

GitHub - w11aaa/Comment-sentiment-classificationContribute to w11aaa/Comment-sentiment-classification development by creating an account on GitHub.https://github.com/w11aaa/Comment-sentiment-classification

正片开始

首先,我们将导入所需的模块。 我们使用 `datasets` 模块来处理数据集,使用 `matplotlib` 来绘制结果,使用 `numpy` 来处理数值,使用 `torch` 来计算张量,使用 `torch.nn` 来处理神经网络,使用 `torch.optim` 来处理神经网络优化器,使用 `torchtext` 来处理文本,使用 `tqdm` 来衡量进度。

python 复制代码
import collections
import datasets
import matplotlib.pyplot as plt
import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
import torchtext
import tqdm

我们还将确保为"torch"和"numpy"设置随机种子。这是为了确保此笔记本可重现,即每次运行它时我们都会得到相同的结果。

通常,使用不同的随机种子多次运行实验是一种很好的做法------既可以测量模型的方差,也可以避免仅使用"好"或"坏"种子计算结果,即在训练过程中的随机性方面非常幸运或不幸。

python 复制代码
seed = 1234
np.random.seed(seed)
torch.manual_seed(seed)
torch.cuda.manual_seed(seed)
torch.backends.cudnn.deterministic = True

使用 datasets.load_dataset 函数从 Hugging Face 的数据集仓库中加载 XiangPan/waimai_10k (https://huggingface.co/datasets/XiangPan/waimai_10k) 数据集的训练集部分。通过观察原始数据分布发现数据分布不均匀,使用 shuffle 方法对加载的训练集数据进行打乱,随机种子设置为 42,以确保结果的可重复性。使用 train_test_split 方法将打乱后的数据集按照 8:2 的比例划分为训练集和测试集。

python 复制代码
train_data = datasets.load_dataset("XiangPan/waimai_10k", split="train")
train_data=train_data.shuffle(42)
train_data, test_data = train_data.train_test_split(test_size=0.2).values()
train_data, test_data
python 复制代码
(Dataset({
     features: ['label', 'text'],
     num_rows: 9589
 }),
 Dataset({
     features: ['label', 'text'],
     num_rows: 2398
 }))

接下来我们指定要使用的预训练模型名称为 "bert-base-chinese"。bert-base-chinese 是一个基于中文语料库预训练的 BERT 模型,它在许多中文自然语言处理任务中都有很好的表现。使用 transformers 库中的 AutoTokenizer 类来加载与指定预训练模型对应的分词器。

python 复制代码
transformer_name = "bert-base-chinese"

tokenizer = transformers.AutoTokenizer.from_pretrained(transformer_name)

现在的数据集还是文本数据,使用编码工具将这些抽象的文字编码成计算机善于处理的数字。

python 复制代码
def tokenize_and_numericalize_example(example, tokenizer):
    """
    对输入的文本数据进行分词并将其转换为对应的词元 ID。

    参数:
    example (dict): 包含文本数据的字典,通常包含一个键 "text"。
    tokenizer: 分词器对象,用于将文本分词并转换为词元 ID。

    返回:
    dict: 包含词元 ID 列表的字典,键为 "ids"。
    """
    try:
        # 从输入的字典中提取文本数据
        text = example["text"]
        # 使用分词器对文本进行处理,并截断过长的文本
        tokenized_output = tokenizer(text, truncation=True)
        # 从分词器的输出中提取词元 ID 列表
        ids = tokenized_output["input_ids"]
    except KeyError:
        print("输入的字典中缺少 'text' 键。")
        return {"ids": []}
    except Exception as e:
        print(f"处理文本时发生错误: {e}")
        return {"ids": []}
    return {"ids": ids}
python 复制代码
train_data = train_data.map(
    tokenize_and_numericalize_example, fn_kwargs={"tokenizer": tokenizer}
)
test_data = test_data.map(
    tokenize_and_numericalize_example, fn_kwargs={"tokenizer": tokenizer}
)

下面我们将数据集格式转换为pytorch张量格式,并且只保留 ids 和 label 这两列数据。

python 复制代码
train_data = train_data.with_format(type="torch", columns=["ids", "label"])
test_data = test_data.with_format(type="torch", columns=["ids", "label"])
python 复制代码
def get_collate_fn(pad_index):
    """
    该函数是一个高阶函数,用于生成一个适用于 DataLoader 的 collate_fn 函数。
    :param pad_index: 填充 token 对应的索引,用于对序列进行填充
    :return: 一个 collate_fn 函数,用于处理一批数据
    """
    def collate_fn(batch):
        """
        对输入的一批数据进行处理,将文本对应的 ids 序列进行填充对齐,同时将标签组合成张量。
        :param batch: 一个包含多个样本的列表,每个样本是一个字典,包含 "ids" 和 "label" 字段
        :return: 一个字典,包含填充对齐后的 "ids" 张量和组合后的 "label" 张量
        """
        # 从 batch 中提取每个样本的 "ids" 字段,组成一个列表
        batch_ids = [i["ids"] for i in batch]
        # 使用 nn.utils.rnn.pad_sequence 对 ids 序列进行填充对齐,使其长度一致
        # padding_value=pad_index 指定填充的值为 pad_index
        # batch_first=True 表示输出的张量维度是 [batch_size, seq_len]
        batch_ids = nn.utils.rnn.pad_sequence(
            batch_ids, padding_value=pad_index, batch_first=True
        )
        # 从 batch 中提取每个样本的 "label" 字段,组成一个列表
        batch_label = [i["label"] for i in batch]
        # 使用 torch.stack 将列表中的标签组合成一个张量
        batch_label = torch.stack(batch_label)
        # 将填充对齐后的 ids 张量和组合后的标签张量封装成一个字典
        batch = {"ids": batch_ids, "label": batch_label}
        return batch

    return collate_fn
python 复制代码
def get_data_loader(dataset, batch_size, pad_index, shuffle=False):
    """
    创建一个 PyTorch 的 DataLoader 对象,用于批量加载数据集。

    参数:
    dataset (torch.utils.data.Dataset): 要加载的数据集。
    batch_size (int): 每个批次包含的样本数量。
    pad_index (int): 填充 token 的索引,用于填充序列到相同长度。
    shuffle (bool, 可选): 是否在每个 epoch 开始时打乱数据集,默认为 False。

    返回:
    torch.utils.data.DataLoader: 用于批量加载数据的 DataLoader 对象。
    """
    # 获取 collate 函数,用于处理每个批次的数据
    collate_fn = get_collate_fn(pad_index)
    # 创建 DataLoader 对象
    data_loader = torch.utils.data.DataLoader(
        # 要加载的数据集
        dataset=dataset,
        # 每个批次的样本数量
        batch_size=batch_size,
        # 用于处理每个批次数据的函数
        collate_fn=collate_fn,
        # 是否在每个 epoch 开始时打乱数据集
        shuffle=shuffle,
    )
    return data_loader

创建训练集和测试集的数据加载器,以便在训练和评估模型时批量加载数据

python 复制代码
pad_index = tokenizer.pad_token_id
batch_size = 8

train_data_loader = get_data_loader(train_data, batch_size, pad_index, shuffle=True)
test_data_loader = get_data_loader(test_data, batch_size, pad_index)

定义一个名为 Transformer 的 PyTorch 神经网络模块,该模块基于预训练的 Transformer 模型构建,用于完成分类任务。

python 复制代码
class Transformer(nn.Module):
    def __init__(self, transformer, output_dim, freeze):
        super().__init__()
        self.transformer = transformer
        hidden_dim = transformer.config.hidden_size
        self.fc = nn.Linear(hidden_dim, output_dim)
        if freeze:
            for param in self.transformer.parameters():
                param.requires_grad = False

    def forward(self, ids):
        output = self.transformer(ids, output_attentions=True)
        hidden = output.last_hidden_state
        attention = output.attentions[-1]
        cls_hidden = hidden[:, 0, :]
        prediction = self.fc(torch.tanh(cls_hidden))
        return prediction

transformer = transformers.AutoModel.from_pretrained("bert-base-chinese")
model=Transformer(transformer, len(train_data["label"].unique()), freeze=False)

最后的训练效果图为

相关推荐
51WORLD官方账号44 分钟前
AI时代智慧园区新标杆:华为联合51WORLD打造智能运营中心2.0
人工智能·数字孪生
RockLiu@8055 小时前
PlainUSR|LIA: 追求更快的卷积网络实现高效的超分辨率重建
网络·人工智能·超分辨率重建
蹦蹦跳跳真可爱5896 小时前
Python----计算机视觉处理(Opencv:直方图均衡化)
人工智能·python·opencv·计算机视觉
胡耀超6 小时前
7.模型选择与评估:构建科学的参数调优与性能评估体系——Python数据挖掘代码实践
开发语言·人工智能·python·机器学习·数据挖掘
果冻人工智能6 小时前
课堂里的人工智能,或者说,狂野西部闯进了教育界
人工智能
wd2099886 小时前
PPT制作,分享下2025年国内外做PPT的AI工具,一健生成PPT
人工智能·ppt
百锦再7 小时前
DeepSeek与GPT的全方位对比及其为编程工作带来的巨大变革
人工智能·python·gpt·nlp·deepseek
Wnq100727 小时前
企业为何青睐数字孪生大屏?技术驱动与价值重构的双重逻辑
人工智能·机器学习·计算机视觉·重构·机器人·aigc
技能咖7 小时前
AI赋能职教革新:生成式人工智能(GAI)认证重构技能人才培养新范式
人工智能
灵途科技7 小时前
AWE 2025 |AI科技引领智能生活,传感器赋能智慧时代
人工智能·科技·生活