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)

最后的训练效果图为

相关推荐
m0_751336391 小时前
突破性进展:超短等离子体脉冲实现单电子量子干涉,为飞行量子比特奠定基础
人工智能·深度学习·量子计算·材料科学·光子器件·光子学·无线电电子
美狐美颜sdk4 小时前
跨平台直播美颜SDK集成实录:Android/iOS如何适配贴纸功能
android·人工智能·ios·架构·音视频·美颜sdk·第三方美颜sdk
DeepSeek-大模型系统教程4 小时前
推荐 7 个本周 yyds 的 GitHub 项目。
人工智能·ai·语言模型·大模型·github·ai大模型·大模型学习
有Li4 小时前
通过具有一致性嵌入的大语言模型实现端到端乳腺癌放射治疗计划制定|文献速递-最新论文分享
论文阅读·深度学习·分类·医学生
郭庆汝5 小时前
pytorch、torchvision与python版本对应关系
人工智能·pytorch·python
小雷FansUnion6 小时前
深入理解MCP架构:智能服务编排、上下文管理与动态路由实战
人工智能·架构·大模型·mcp
资讯分享周7 小时前
扣子空间PPT生产力升级:AI智能生成与多模态创作新时代
人工智能·powerpoint
叶子爱分享8 小时前
计算机视觉与图像处理的关系
图像处理·人工智能·计算机视觉
鱼摆摆拜拜8 小时前
第 3 章:神经网络如何学习
人工智能·神经网络·学习
一只鹿鹿鹿8 小时前
信息化项目验收,软件工程评审和检查表单
大数据·人工智能·后端·智慧城市·软件工程