掘金 人工智能 22小时前
微调篇--超长文本微调训练
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文深入探讨了评论分析任务中数据集与模型的更换流程,涵盖了数据集加载、预训练模型选择、训练与测试等关键环节。通过代码示例,详细阐述了如何更换数据集、微调预训练的BERT模型,以及处理超长文本的策略。文章还介绍了资讯评论数据集的加载方法,并提供了扩展词汇表和匹配模型的指导,旨在帮助读者快速上手评论分析任务。

💬 更换数据集是评论分析任务的基础。文章介绍了使用`datasets`库加载CSV格式的数据集,并提供了自定义数据集类的创建方法。关键在于确保数据集路径和CSV文件中的列名与代码中的字段匹配,例如“text”和“label”。

💡 预训练模型更换是提升性能的关键。文章建议通过微调预训练的BERT模型来完成评论分析任务,并提供了代码示例,展示了如何加载Hugging Face提供的预训练BERT模型。同时,需要根据任务类型(如二分类)调整全连接层的输出维度。

🚀 训练与测试是模型优化的核心。文章介绍了使用`DataLoader`批量加载数据,并使用`AdamW`作为优化器进行模型参数的优化。训练过程中,需要关注损失函数和准确率,并定期保存模型参数。

📏 处理超长文本是实际应用中的挑战。文章介绍了文本截断和增加`max_position_embeddings`两种策略来应对超长文本。 增加`max_position_embeddings`虽然能支持更长的输入,但也需要更多的计算资源。


分享内容

    新闻评论分析任务训练流程加载自定义数据集处理超长文本的训练问题扩展词汇表并匹配模型修改模型配置信息评论分析任务概述

评论分析是情感分析的一个应用场景,旨在通过文本分类技术识别评论的情感倾向。本次将详细介绍如何更换数据集和模型来实现这一任务。

训练流程

1.1 数据集更换

在自然语言处理(NLP)任务中,数据集通常包含文本和对应的标签。文章评论分析的数据集可以采用CSV格式,其中一列存储评论文本,另一列存储情感标签(如正面或负面)。

加载CSV格式的数据

我们可以使用datasets库来加载本地的CSV文件。以下是一个示例代码:

CustomData.pyfrom torch.utils.data import Dataset  # 从torch库中导入Dataset类,用于创建自定义数据集类from datasets import load_dataset  # 从datasets库中导入loaddataset函数,用于加载数据集class <span class="hljs-title class">CustomDataset(Dataset):  # 定义一个名为MyDataset的类,继承自Dataset类    def init(self,split):  # 定义类的初始化方法,接收一个参数split,表示数据集的分割类型        #使用load_dataset函数加载csv文件,路径为"./data/{split}.csv",并指定数据集分割为"train"        self.dataset = load_dataset(path="csv",datafiles=f"./data/{split}.csv",split="train")    def <span class="hljs-title function">len(self):  # 定义一个方法用于返回数据集的长度        return len(self.dataset)  # 返回加载的数据集的长度,即数据集中的样本数量    def getitem(self, item):  # 定义一个方法用于获取数据集中的某个样本        text = self.dataset[item]["text"]  # 获取数据集中第item个样本的"text"字段        label = self.dataset[item]["label"]  # 获取数据集中第item个样本的"label"字段        return text,label  # 返回获取的文本和标签if name == 'main':  # 判断是否在主程序中运行    dataset = CustomDataset("test")  # 创建MyDataset类的实例,传入"test"作为split参数    for data in dataset:  # 遍历数据集中的每个样本        print(data)  # 打印每个样本的内容

代码解析

注意事项

1.2 预训练模型更换

文章评论分析任务可以通过微调预训练的BERT模型来完成。可以选择不同的中文预训练模型,如bert-base-chinesehfl/chinese-roberta-wwm-ext

代码示例

net.pyfrom transformers import BertModel, BertConfig  # 导入Bert模型和Bert配置类import torch  # 导入PyTorch库DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")  # 设置设备为CUDA(如果可用),否则为CPUpretrained = BertModel.from_pretrained(r"bert-base-chinese").to(DEVICE)pretrained.embeddings.position_embeddings = torch.nn.Embedding(1500,768).to(DEVICE)print(pretrained)config = pretrained.configconfiguration = BertConfig.from_pretrained(r"bert-base-chinese")  # 从预训练模型加载配置configuration.max_position_embeddings = 1500  # 设置最大位置嵌入为1500print(configuration)  # 打印配置信息初始化模型pretrained = BertModel(configuration).to(DEVICE)  # 使用配置初始化Bert模型并移动到指定设备print(pretrained.embeddings.position_embeddings)  # 打印模型的位置嵌入print(pretrained)  # 打印整个模型定义下游任务模型(将主干网络所提取的特征分类)class Model(torch.nn.Module):  # 定义一个PyTorch模型    def init(self):        super().init()  # 调用父类构造函数        self.fc = torch.nn.Linear(768, 8)  # 定义一个全连接层,输入768维,输出8维    # def forward(self,input_ids,attention_mask,token_type_ids):    #     # with torch.no_grad():    #     #     out = pretrained(input_ids=input_ids,attention_mask=attention_mask,token_type_ids=token_type_ids)    #     out = pretrained(input_ids=input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids)    #     out = self.fc(out.last_hiddenstate[:,0])    #     out = out.softmax(dim=1)    #     return out    # 调整模型的前向计算,让embeddings部分参与到模型的训练过程(修改了embeddings)    def <span class="hljs-title function">forward(self, input_ids, attention_mask, token_type_ids):  # 定义模型的前向传播        # 让embeddings参与训练        embeddings_output = pretrained.embeddings(input_ids=input_ids)  # 获取嵌入层的输出        attention_mask = attention_mask.to(torch.float)  # 将注意力掩码转换为浮点类型        # 将数据形状转换为[N,1,1,sequence_length]使其匹配attention层的输入形状        attention_mask = attention_mask.unsqueeze(1).unsqueeze(2)  # 增加两个维度        attention_mask = attention_mask.to(embeddings_output.dtype)  # 将注意力掩码的数据类型与嵌入层输出对齐        # 冻结encoder和pooler,使用torch.no_grade()节省显存        with torch.no_grad():  # 在不计算梯度的情况下执行            encoder_output = pretrained.encoder(embeddings_output, attention_mask=attention_mask)  # 获取编码器的输出        out = self.fc(encoder_output.last_hidden_state[:, 0])  # 使用全连接层处理编码器的最后一个隐藏状态        return out  # 返回输出

代码解析

注意事项

1.3 训练与测试

训练是微调模型的关键步骤。我们使用DataLoader来批量加载数据,并使用AdamW作为优化器来进行模型参数的优化。

训练代码

trainer.pyimport torch  # 导入PyTorch库from CustomData import CustomDataset  # 导入自定义数据集类from torch.utils.data import DataLoader  # 导入PyTorch的数据加载器from net import Model  # 导入自定义的模型类from transformers import AdamW, BertTokenizer  # 导入AdamW优化器和Bert分词器DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")  # 设置设备为CUDA(如果可用),否则为CPUEPOCH = 1  # 设置训练的总轮数token = BertTokenizer.from_pretrained(r"bert-base-chinese")  # 加载预训练的Bert分词器def collate_fn(data):    sentes = [i[0] for i in data]  # 提取数据集中的句子    label = [i[1] for i in data]  # 提取数据集中的标签    # print(sentes)    # 编码句子    data = token.batch_encode_plus(batch_text_or_text_pairs=sentes,  # 使用BertTokenizer对句子进行批量编码,类似于将句子转换为模型可以理解的数字形式                                   truncation=True,  # 启用截断功能,确保每个句子不会超过指定的最大长度                                   padding="max_length",  # 使用最大长度进行填充,确保所有句子长度一致                                   max_length=1500,  # 设置最大长度为1500,超过的部分会被截断,未达到的部分会被填充                                   return_tensors="pt",  # 返回PyTorch张量格式的数据,方便后续在模型中使用                                   return_length=True)  # 返回每个句子的实际长度,便于后续处理    input_ids = data["input_ids"]  # 获取输入ID,这些ID是词汇表中每个词的唯一标识符    attention_mask = data["attention_mask"]  # 获取注意力掩码,用于指示哪些词是填充的,哪些是实际内容    token_type_ids = data["token_type_ids"]  # 获取token类型ID,用于区分句子对中的不同句子    labels = torch.LongTensor(label)  # 将标签转换为LongTensor格式,便于在PyTorch中进行计算    # print(input_ids,attention_mask,token_type_ids)    return input_ids, attention_mask, token_type_ids, labels  # 返回处理后的数据,包括输入ID、注意力掩码、token类型ID和标签创建数据集train_dataset = CustomDataset("train")  # 创建训练数据集,类似于准备好一组用于训练的样本val_dataset = CustomDataset("validation")  # 创建验证数据集,用于在训练过程中评估模型性能创建数据加载器train_laoder = DataLoader(dataset=train_dataset,  # 使用DataLoader为训练数据集创建数据加载器,便于批量处理数据                          batch_size=1,  # 设置每个批次的大小为1,即每次只处理一个样本                          shuffle=True,  # 启用随机打乱功能,确保每次训练时数据顺序不同,增加模型的泛化能力                          drop_last=True,  # 如果最后一个批次的数据量不足,则丢弃该批次,确保每个批次的数据量一致                          collate_fn=collate_fn)  # 使用自定义的collate_fn函数来处理每个批次的数据if name == 'main':    # 开始训练    print(DEVICE)  # 打印使用的设备,告诉用户当前使用的是CPU还是GPU    model = Model().to(DEVICE)  # 初始化模型并将其移动到指定设备上,确保计算在合适的硬件上进行    optimizer = AdamW(model.parameters(), lr=5e-4)  # 使用AdamW优化器,设置学习率为5e-4,优化器用于更新模型参数    loss_func = torch.nn.CrossEntropyLoss()  # 使用交叉熵损失函数,常用于分类问题中计算预测值与真实值之间的差异    model.train()  # 设置模型为训练模式,启用dropout等训练时特有的功能    for epoch in range(EPOCH):  # 训练EPOCH轮,EPOCH表示完整遍历一次训练数据集        sum_val_acc = 0  # 初始化验证准确率的累加器        sum_val_loss = 0  # 初始化验证损失的累加器        # 训练        for i, (input_ids, attention_mask, token_type_ids, labels) in enumerate(train_laoder):  # 遍历训练数据集            # print(input_ids)            input_ids, attention_mask, token_type_ids, labels = input_ids.to(DEVICE), attention_mask.to(                DEVICE), token_type_ids.to(DEVICE), labels.to(DEVICE)  # 将数据移动到指定设备上            out = model(input_ids, attention_mask, token_type_ids)  # 前向传播,计算模型的输出            loss = loss_func(out, labels)  # 计算损失,衡量模型输出与真实标签之间的差异            optimizer.zero_grad()  # 清空优化器的梯度,防止梯度累积            loss.backward()  # 反向传播,计算梯度            optimizer.step()  # 更新模型参数,根据计算出的梯度调整参数值            if i % 5 == 0:  # 每5个批次打印一次信息,便于观察训练过程                out = out.argmax(dim=1)  # 获取预测结果,选择概率最大的类别                acc = (out == labels).sum().item() / len(labels)  # 计算准确率,预测正确的样本数除以总样本数                print(epoch, i, loss.item(), acc)  # 打印当前轮数、批次、损失和准确率        torch.save(model.state_dict(), f"model/{epoch}-bert.pth")  # 保存模型参数到文件,便于后续加载和使用        print(epoch, "参数保存成功!")  # 打印成功信息,告知用户模型参数已保存

代码解析

变量说明

在自然语言处理(NLP)任务中,input_idsattention_masktoken_type_ids 是使用预训练的BERT模型进行文本处理时常用的输入格式。让我们逐一解释这些变量的作用,并通过一个简单的例子来说明。

    input_ids:

      作用: input_ids 是文本经过分词器(如BertTokenizer)处理后得到的词汇表索引。每个单词或子词被映射到一个唯一的整数ID。例子: 假设我们有一个句子 "我爱编程"。分词器可能会将其分成 ["我", "爱", "编", "程"],并将每个词映射到相应的ID,比如 [101, 1001, 2001, 3001]。

    attention_mask:

      作用: attention_mask 用于指示模型在处理输入时应该关注哪些词。值为1的地方表示模型应该关注,值为0的地方表示模型应该忽略(通常是填充的部分)。例子: 如果句子 "我爱编程" 被填充到最大长度5,可能会变成 ["我", "爱", "编", "程", "[PAD]"],对应的 attention_mask 为 [1, 1, 1, 1, 0]。

    token_type_ids:

      作用: token_type_ids 用于区分不同的句子对(如句子A和句子B)在输入中。对于单个句子输入,通常全为0。例子: 在句子对任务中,比如句子A是 "我爱编程",句子B是 "编程很有趣",token_type_ids 可能是 [0, 0, 0, 0, 1, 1, 1, 1],表示前四个词属于句子A,后四个词属于句子B。

    labels:

      作用: labels 是目标标签,用于监督学习中的损失计算。通常是一个整数,表示类别。例子: 如果我们在做情感分析,句子 "我爱编程" 的标签可能是1(表示正面情感)。

这些变量共同作用,使得模型能够有效地理解和处理输入文本。通过这种结构化的输入,BERT模型可以更好地捕捉文本中的语义信息。

注意事项

2. 资讯评论数据集介绍

资讯评论是NLP中的经典任务,通常需要对评论文本进行分类,将其归入不同的类别。

2.1 加载Hugging Face的资讯评论数据集

我们可以使用Hugging Face的datasets库来加载资讯评论数据集,如THUCNews。这是一个中文资讯评论数据集,适合用于文本分类任务。

2.2 加载自定义CSV数据集

如果有自定义的资讯评论数据集,可以将其保存为CSV文件,并通过datasets库加载。

代码示例

数据集地址:huggingface.co/datasets/se…

data.pyfrom datasets import load_dataset加载Hugging Face上的THUCNews数据集data = load_dataset(path="seamew/THUCNewsText", split="train")print(data)遍历数据集查看样本for i in data:    print(i)data = load_dataset(path="csv", data_files="data/train.csv", split="train")

注意事项

22

3.处理超长文本的训练问题

BERT模型的最大输入长度为512个token,但在实际应用中,文本长度可能会超过该限制,导致信息丢失或无法输入模型。

3.1 文本截断

对于长度超过最大输入长度的文本,可以通过截断的方式保留前512个token。

3.2 增加max_position_embeddings

如果文本长度远远超过512个token,可以通过调整BERT模型的配置来增加max_position_embeddings,使模型支持更长的输入。

代码示例

from transformers import BertConfig, BertModel# 修改max_position_embeddings参数configuration = BertConfig.from_pretrained("yechen/bert-large-chinese")configuration.max_position_embeddings = 1500  # 增加最大输入长度model = BertModel(configuration)

注意事项

4.扩展词汇表并匹配模型

在实际应用中,数据集中可能会出现未包含在预训练模型词汇表中的新词汇。这时我们需要扩展模型的vocab

4.1 添加新词汇到词汇表

通过BertTokenizeradd_tokens方法添加新词汇:

token = BertTokenizer.from_pretrained("yechen/bert-large-chinese")token.add_tokens(["新词汇1", "新词汇2"])

4.2 调整模型的嵌入层

添加新词汇后,需要调整模型的嵌入层,以便模型能够处理新的词汇。

代码示例

model.resize_token_embeddings(len(token))

注意事项

5.修改模型配置信息

模型配置(如max_position_embeddingshidden_size)可以根据任务需求进行调整,特别是在处理不同长度的文本或需要调整模型容量时。

5.1 修改模型配置

通过BertConfig可以定制化模型配置。

代码示例

from transformers import BertConfig, BertModel# 自定义BERT配置configuration = BertConfig.from_pretrained("yechen/bert-large-chinese")configuration.max_position_embeddings = 1500  # 修改最大输入长度configuration.hidden_size = 1024  # 修改隐藏层大小# 使用自定义配置初始化模型model = BertModel(configuration)

注意事项

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

评论分析 BERT模型 数据集更换 NLP
相关文章