Hugging Face模子微调训练(基于BERT的中文评价感情分析)

[复制链接]
发表于 2025-10-1 10:40:07 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
学习视频所在



  • HuggingFace教程
项目所在



  • HuggingFaceStu
数据集的下载


  • 下载数据集,然后举行文件调解,调解效果如下图所示
  1. # 将数据集下载到本地
  2. from datasets import load_dataset
  3. # 在代码开头添加(抑制所有警告)
  4. import os
  5. os.environ["HF_HUB_DISABLE_SYMLINKS_WARNING"] = "1"
  6. # 指定数据集名称和本地缓存路径
  7. dataset_name = "lansinuote/ChnSentiCorp"
  8. cache_dir = "data/lansinuote/ChnSentiCorp"
  9. # 下载并加载数据集
  10. # 下载并加载数据集(添加信任远程代码参数)
  11. dataset = load_dataset(
  12.     dataset_name,
  13.     cache_dir=cache_dir,
  14.     trust_remote_code=True  # 关键修复参数
  15. )
  16. print(f"数据集已下载到:{cache_dir}")
  17. print("\n第一条数据样例:")
  18. print(dataset["train"][0])
复制代码


  • 测试:加载数据,并在终端输出
  1. from datasets import Dataset
  2. # 取出测试集
  3. test_set = Dataset.from_file("./data/lansinuote/ChnSentiCorp/chn_senti_corp-test.arrow")
  4. print(test_set)
  5. # 查看数据
  6. for data in test_set:
  7.     print(data)
  8. # 取出训练集
  9. train_set = Dataset.from_file(".//data/lansinuote/ChnSentiCorp/chn_senti_corp-train.arrow")
  10. print(train_set)
  11. # 查看数据
  12. for data in train_set:
  13.     print(data)
  14. # 取出验证集
  15. validation_set = Dataset.from_file("./data/lansinuote/ChnSentiCorp/chn_senti_corp-validation.arrow")
  16. print(validation_set)
  17. # 查看数据
  18. for data in validation_set:
  19.     print(data)
复制代码
模子微调的根本概念与流程



  • 微调指在预训练模子的底子上,通过进一步的训练来顺应特定的卑鄙使命。BERT模子通过预训练来学习语言的通用模式,然后通过微调来顺应特定使命,如感情分析、定名实体辨认等。微调过程中,通常冻结BERT的预训练层,只训练与卑鄙使命相干的层。
加载数据集



  • 感情分析使命的数据通常包罗文本及其对应的感情标签。利用HuggingFace的datasets库可以轻松地加载和处置惩罚数据集。
  1. from datasets import load_dataset
  2. #加载数据集
  3. dataset =load_dataset('csv',data_files="data/chnsenticorp.csv")
  4. #查看数据集信息
  5. print(dataset)
复制代码
数据集格式



  • Hugging Face 的 datasets 库支持多种数据集格式,如 CSV、JSON、TFRecord 等。在本案例中,利用CSV格式,CSV文件应包罗两列:一列是文本数据,另一列是感情标签。
数据集信息



  • 加载数据集后,可以查察数据集的根本信息,如数据集巨细、字段名称等。
制作Dataset



  • 加载数据集后,须要对其举行处置惩罚以顺应模子的输入格式。这包罗数据洗濯、格式转换等操纵。
  1. from torch.utils.data import Dataset, DataLoader
  2. from datasets import Dataset as HFDataset  # 重命名以避免冲突
  3. class MyDataset(Dataset):
  4.     def __init__(self, split):
  5.         # 根据 split 确定 .arrow 文件路径
  6.         if split == "train":
  7.             data_path = "./data/train/chn_senti_corp-train.arrow"
  8.         elif split == "test":
  9.             data_path = "./data/test/chn_senti_corp-test.arrow"
  10.         elif split == "validation":
  11.             data_path = "./data/validation/chn_senti_corp-validation.arrow"
  12.         else:
  13.             raise ValueError("无效的数据集类型,必须是 train/test/validation")
  14.         # 加载 Hugging Face Dataset
  15.         self.hf_dataset = HFDataset.from_file(data_path)
  16.     def __len__(self):
  17.         return len(self.hf_dataset)
  18.     def __getitem__(self, idx):
  19.         text = self.hf_dataset[idx]["text"]
  20.         label = self.hf_dataset[idx]["label"]
  21.         return text, label
  22. if __name__ == "__main__":
  23.     # 创建 PyTorch Dataset
  24.     dataset = MyDataset("train")
  25.     # 使用 DataLoader 进行迭代
  26.     dataloader = DataLoader(dataset, batch_size=1, shuffle=True)
  27.     for data in dataloader:
  28.         print(data)
复制代码
数据集字段



  • 在制作Dataset时,需界说数据集的字段。在本案例中,界说了两个字段:text(文本)和labe1(感情标签)。每个字段都须要与模子的输入和输出匹配。
数据集信息



  • 制作Dataset后,可以通过dataset.info等方法查察其巨细、字段名称等信息,以确保数据集的精确性和完备性。
vocab字典操纵

词汇表



  • BERT模子利用词汇表(vocab)将文本转换为模子可以明白的输入格式。词汇表包罗全部模子已知的单词及其对应的索引。确保数据会合的全部文本都能找到对应的词汇索引是至关告急的。
  1. from transformers import BertTokenizer
  2. model_name="./model/google-bert/bert-base-chinese/models--google-bert--bert-base-chinese/snapshots/c30a6ed22ab4564dc1e3b2ecbf6e766b0611a33f"
  3. # 加载字典和分词工具
  4. # token=BertTokenizer.from_pretrained("bert-base-chinese") # 在线方式
  5. token=BertTokenizer.from_pretrained(model_name) # 使用本地方式(推荐)
  6. '''
  7. sents=["酒店太旧,大堂感觉像三星级水平,在郑州这样的酒店水平,绝对算不上四星水平,早餐走了两圈也没有可以吃的,太差",
  8.        "已经贴完了,又给小区的妈妈买了一套,值得推荐",
  9.        "屏幕大,本子薄。自带数字小键盘,比较少见,声音很好,usb接口也很多,性价比高",
  10.        "酒店环境很好,就是有一点偏僻,交通不是很好,不太好打车,酒店应该想办法解决一下"]
  11. '''
  12. # 批量编码句子
  13. '''
  14. out=token.batch_encode_plus(
  15.     batch_text_or_text_pairs=[sents[0],sents[1]],
  16.     add_special_tokens=True,
  17.     truncation=True, # 句子过长截断
  18.     padding="max_length", # 一律补零到max_length长度
  19.     max_length=30,
  20.     return_tensors=None, # 默认返回list
  21.     return_attention_mask=True, # 返回 attention_mask
  22.     return_token_type_ids=False,
  23.     return_special_tokens_mask=True, #特殊符号标识
  24.     return_length=True, # 返回length,标识长度
  25.     )
  26. print(out)
  27. '''
  28. # 获取字典
  29. # vocab=token.get_vocab()
  30. # print(vocab)
  31. # print("阳" in vocab)
  32. # 添加新词
  33. token.add_tokens(new_tokens=["阳光","大志"])
  34. # 重新获取字典
  35. vocab=token.get_vocab()
  36. print("大志" in vocab)
  37. # 添加新的特殊符号 本质键值对
  38. # token.add_special_tokens({"eos_token":"[EOS]"})
  39. # 编码新句子
  40. res=token.encode(
  41.     text="阳光照在大地上[EOS]",
  42.     text_pair=None,
  43.     truncation=True,
  44.     padding="longest",
  45.     longest=10,
  46.     add_special_tokens=True,
  47.     return_tensors=None
  48.     )
  49. print(res)
  50. # 解码为源字符串
  51. print(token.decode(res))
复制代码
文本转换



  • 利用tokenizer将文天职割成词汇表中的单词,并转换为相应的索引l。此步调须要确保文本长度、特别字符处置惩罚等都与BERT模子的预训练设置相同等。
卑鄙使命模子筹划



  • 在微调BERT模子之前,须要筹划一个顺应感情分析使命的卑鄙模子布局。通常包罗一个或多个全毗连层,用于将BERT输出的特性向量转换为分类效果。
  1. # 加载预训练模型
  2. from transformers import BertModel
  3. import torch
  4. # 定义训练设备
  5. DEVICE=torch.device('cuda' if torch.cuda.is_available() else 'cpu')
  6. model_dir="./model/google-bert/bert-base-chinese/models--google-bert--bert-base-chinese/snapshots/c30a6ed22ab4564dc1e3b2ecbf6e766b0611a33f"
  7. pretrained=BertModel.from_pretrained(model_dir).to(DEVICE)
  8. # 定义下游任务模型(将主干网络所提取的特征进行分类)
  9. class Model(torch.nn.Module):
  10.     def __init__(self):
  11.         super().__init__()
  12.         # 上一步 最后输出全连接模型 Linear(in_features=768, out_features=768, bias=True)
  13.         self.fc = torch.nn.Linear(768, 2)
  14.     # 训练推理
  15.     def forward(self,input_ids,attention_mask,token_type_ids):
  16.         # 上游任务不参与训练 不参与反向传播,只参与前向训练
  17.        with torch.no_grad():
  18.            out=pretrained(input_ids=input_ids,attention_mask=attention_mask,token_type_ids=token_type_ids)
  19.        # 下游任务参与训练
  20.        output=self.fc(out.last_hidden_state[:0])
  21.        output=output.softmax(dim=1)
  22.        return output;
复制代码
模子训练与生存

数据加载



  • 利用DataLoader实现批量数据加载。DataLoader主动处置惩罚数据的批处置惩罚和随机打乱,确保训l练的高效性和数据的多样性。
优化器



  • Adamw是一种实用于BERT模子的优化器,联合了Adam和权重衰减的特点,可以大概有用地防止过拟合。
训练循环



  • 训练循环包罗前向传播(forward pass)、丧失盘算(loss calculation)、反向传播(backward pass)、参数更新(parameter update)等步调。每个epoch 都会对整个数据集举行一次遍历,更新模子参数。通常训练过程中会跟踪丧失值的厘革,以判定模子的收敛环境。
  1. import torch
  2. from torch.optim import AdamW
  3. from MyData import MyDataset
  4. from torch.utils.data import DataLoader
  5. from Net import Model
  6. from transformers import BertTokenizer
  7. # 定义训练设备
  8. DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
  9. EPOCHS = 100
  10. BATCH_SIZE = 32
  11. # 加载分词器
  12. model_name = "./model/google-bert/bert-base-chinese/models--google-bert--bert-base-chinese/snapshots/c30a6ed22ab4564dc1e3b2ecbf6e766b0611a33f"
  13. token = BertTokenizer.from_pretrained(model_name)
  14. # 自定义数据编码处理函数
  15. def collate_fn(data):
  16.     sente = [i[0] for i in data]
  17.     label = [i[1] for i in data]
  18.     # 编码处理
  19.     data = token.batch_encode_plus(
  20.         batch_text_or_text_pairs=sente,
  21.         truncation=True,
  22.         padding='max_length',
  23.         max_length=300,
  24.         return_tensors='pt',
  25.         return_length=True
  26.     )
  27.     input_ids = data['input_ids']
  28.     attention_mask = data['attention_mask']
  29.     token_type_ids = data['token_type_ids']
  30.     labels = torch.LongTensor(label)
  31.     return input_ids, attention_mask, token_type_ids, labels
  32. # 创建数据集
  33. train_dataset = MyDataset("train")
  34. # 创建数据加载器
  35. train_loader = DataLoader(
  36.     dataset=train_dataset,
  37.     batch_size=BATCH_SIZE,
  38.     shuffle=True,
  39.     drop_last=True,
  40.     collate_fn=collate_fn  # 只传递函数名
  41. )
  42. if __name__ == '__main__':
  43.     # start train
  44.     print(DEVICE)
  45.     model = Model().to(DEVICE)
  46.     # 优化器
  47.     optimizer = AdamW(model.parameters(), lr=5e-4)
  48.     # loss function
  49.     loss_func=torch.nn.CrossEntropyLoss()
  50.     # train model
  51.     model.train()
  52.     for epoch in range(EPOCHS):
  53.         for i,(input_ids, attention_mask, token_type_ids, labels) in enumerate(train_loader):
  54.             # 将数据放到DEVICE上
  55.             input_ids, attention_mask, token_type_ids, labels=input_ids.to(DEVICE), attention_mask.to(DEVICE), token_type_ids.to(DEVICE), labels.to(DEVICE)
  56.             # 执行前向计算
  57.             out=model(input_ids, attention_mask, token_type_ids)
  58.             # print("Output shape:", out.shape)
  59.             # 计算损失
  60.             loss = loss_func(out, labels)
  61.             # 优化模型 清空权重 反向传播 更新梯度
  62.             optimizer.zero_grad()
  63.             loss.backward()
  64.             optimizer.step()
  65.             # 每5个查看一下
  66.             if i%20==0:
  67.                 out=out.argmax(dim=1)
  68.                 #  准确率
  69.                 acc=(out==labels).sum()/len(labels)
  70.                 print(epoch,i,loss.item(),acc)
  71.         # 保存模型参数
  72.         torch.save(model.state_dict(),f"./params/{epoch}bert.pt")
  73.         print(epoch)
复制代码
终极效果评估与测试



  • 在模子训练完成后,须要评估其在测试集上的性能。通常利用精确率、准确率、召回率和F1分数等指标来衡量模子的效果。

    • 精确率是衡量分类模子团体性能的根本指标,盘算公式为精确分类的样本数量除以总样本数量。
    • 准确率、召回率是分类模子的另两个告急指标,分别反映模子在正例推测上的准确性和召回本领。
    • F1分数是准确率和召回率的调和匀称数,通常用于不平衡数据集的评估。

  1. import torch
  2. from Net import Model
  3. from transformers import BertTokenizer
  4. from MyData import MyDataset
  5. from torch.utils.data import DataLoader
  6. DEVICE = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
  7. # 加载分词器
  8. model_name = "./model/google-bert/bert-base-chinese/models--google-bert--bert-base-chinese/snapshots/c30a6ed22ab4564dc1e3b2ecbf6e766b0611a33f"
  9. token = BertTokenizer.from_pretrained(model_name)
  10. # 自定义数据编码处理函数
  11. def collate_fn(data):
  12.     sente = [i[0] for i in data]
  13.     label = [i[1] for i in data]
  14.     # 编码处理
  15.     data = token.batch_encode_plus(
  16.         batch_text_or_text_pairs=sente,
  17.         truncation=True,
  18.         padding='max_length',
  19.         max_length=300,
  20.         return_tensors='pt',
  21.         return_length=True
  22.     )
  23.     input_ids = data['input_ids']
  24.     attention_mask = data['attention_mask']
  25.     token_type_ids = data['token_type_ids']
  26.     labels = torch.LongTensor(label)
  27.     return input_ids, attention_mask, token_type_ids, labels
  28. # 创建数据集
  29. train_dataset = MyDataset("train")
  30. # 创建数据加载器
  31. train_loader = DataLoader(
  32.     dataset=train_dataset,
  33.     batch_size=32,
  34.     shuffle=True,
  35.     drop_last=True,
  36.     collate_fn=collate_fn  # 只传递函数名
  37. )
  38. if __name__ == "__main__":
  39.     acc=0
  40.     total=0
  41.     model=Model().to(DEVICE)
  42.     model.load_state_dict(torch.load("./params/1bert.pt"))
  43.     model.eval() # 开启模型测试模式
  44.     for i, (input_ids, attention_mask, token_type_ids, labels) in enumerate(train_loader):
  45.         # 将数据放到DEVICE上
  46.         input_ids, attention_mask, token_type_ids, labels = input_ids.to(DEVICE), attention_mask.to(
  47.             DEVICE), token_type_ids.to(DEVICE), labels.to(DEVICE)
  48.         # 执行前向计算
  49.         out = model(input_ids, attention_mask, token_type_ids)
  50.         out=out.argmax(dim=1)
  51.         acc+=(out==labels).sum().item()
  52.         total+=len(labels)
  53.     print(acc/total)
复制代码
模子加载和测试



  • 利用模子举行测试
  1. import torch
  2. from transformers import BertTokenizer
  3. from emotionAnalysis.Net import Model
  4. DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
  5. print(DEVICE)
  6. values=["负向评价","正向评价"]
  7. model=Model().to(DEVICE)
  8. # 加载分词器
  9. model_name = "./model/google-bert/bert-base-chinese/models--google-bert--bert-base-chinese/snapshots/c30a6ed22ab4564dc1e3b2ecbf6e766b0611a33f"
  10. token = BertTokenizer.from_pretrained(model_name)
  11. # 自定义数据编码处理函数
  12. def collate_fn(data):
  13.     sente = [data]
  14.     # 编码处理
  15.     data = token.batch_encode_plus(
  16.         batch_text_or_text_pairs=sente,
  17.         truncation=True,
  18.         padding='max_length',
  19.         max_length=300,
  20.         return_tensors='pt',
  21.         return_length=True
  22.     )
  23.     input_ids = data['input_ids']
  24.     attention_mask = data['attention_mask']
  25.     token_type_ids = data['token_type_ids']
  26.     return input_ids, attention_mask, token_type_ids
  27. def test():
  28.     model.load_state_dict(torch.load("./params/1bert.pt"))
  29.     model.eval()
  30.     while True:
  31.         data=input("请输入测试数据(输入‘q’退出):")
  32.         if data=="q":
  33.             print("测试结束")
  34.             break
  35.         input_ids, attention_mask, token_type_ids=collate_fn(data)
  36.         input_ids, attention_mask, token_type_ids=input_ids.to(DEVICE), attention_mask.to(DEVICE), token_type_ids.to(DEVICE)
  37.         with torch.no_grad():
  38.             out=model(input_ids=input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids)
  39.             out=out.argmax(dim=1)
  40.             print("模型判定:",values[out],"\n")
  41. if __name__=="__main__":
  42.     test()
复制代码
  1. cuda
  2. 请输入测试数据(输入‘q’退出):酒店服务不错,环境也还比较好!特别是好像是48楼那个旋转餐厅满有特色,至少我觉得住这个酒店还满满意!
  3. 模型判定: 正向评价
  4. 请输入测试数据(输入‘q’退出):东西很差
  5. 模型判定: 负向评价
  6. 请输入测试数据(输入‘q’退出):东西很好,我要再买一个
  7. 模型判定: 正向评价
  8. 请输入测试数据(输入‘q’退出):我真的会谢谢你
  9. 模型判定: 正向评价
  10. 请输入测试数据(输入‘q’退出):真的很栓Q
  11. 模型判定: 负向评价
复制代码
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表