大模子工程师学习日记(十六):Bert-base-chinese模子基于微博数据集进行增量 ...

打印 上一主题 下一主题

主题 971|帖子 971|积分 2913

1.获取数据集

  1. from datasets import load_dataset
  2. data = load_dataset(path="csv",data_files="data/news/train.csv",split="train")
  3. print(data)
  4. for i in data:
  5.     print(data["text"])
复制代码
2.统计数据分布环境
        这一步是为了验证数据集的质量。
  1. import pandas as pd
  2. df = pd.read_csv("data/news/train.csv")
  3. #统计每个类别的数据量
  4. category_counts = df["label"].value_counts()
  5. #统计每个类别的比值
  6. total_data = len(df)
  7. category_ratios = (category_counts / total_data) *100
  8. print(category_counts)
  9. print(category_ratios)
复制代码
使用这行之后,可以看到数据集非常的紊乱,分布非常的不匀称。所有我们需要进行数据清洗。
3.数据采样

一、数据过采样(Oversampling)

定义:通过增长少数类样本的数量,使各类别样本趋于均衡。
适用场景:


  • 数据集较小

    • 当数据集整体规模较小时,欠采样大概导致信息丢失,而过采样可以在不损失数据的环境下均衡类别分布。
    • 比方:医疗诊断数据中,罕见病例的样本数量较少,过采样可以保留这些关键信息。

  • 少数类样本非常告急

    • 当少数类样本对任务至关告急时(如诓骗检测、罕见疾病诊断),过采样可以增强模子对少数类的识别能力。
    • 比方:在光荣卡诓骗检测中,诓骗交易占比极低,但漏检代价高昂。

  • 模子对数据量敏感

    • 某些模子(如深度学习模子)需要大量数据才能有效训练,过采样可以提供更多样本,制止模子欠拟合。

常用方法:



  • 随机过采样:简朴复制少数类样本。
  • SMOTE(Synthetic Minority Oversampling Technique):通过插值生成新的少数类样本。
  • ADASYN(Adaptive Synthetic Sampling):根据样天职布自顺应生成新样本。
注意事项:



  • 过采样大概导致过拟合,尤其是随机过采样时,模子大概过度依靠重复样本。
  • 生成新样本时需确保其公道性,制止引入噪声。

二、数据欠采样(Undersampling)

定义:通过减少多数类样本的数量,使各类别样本趋于均衡。
适用场景:


  • 数据集较大

    • 当数据集规模较大时,欠采样可以明显减少盘算本钱,同时制止过采样带来的过拟合风险。
    • 比方:在文天职类任务中,多数类样本数量庞大,欠采样可以加快训练过程。

  • 多数类样本冗余

    • 当多数类样本中存在大量相似或重复数据时,欠采样可以去除冗余信息,提升模子服从。
    • 比方:在图像分类中,某些类别的图像大概高度相似,欠采样可以减少冗余。

  • 盘算资源有限

    • 当盘算资源有限时,欠采样可以低落数据规模,使模子训练更加高效。

常用方法:



  • 随机欠采样:随机删除多数类样本。
  • NearMiss:基于隔断选择与少数类样本最接近的多数类样本。
  • Tomek Links:去除界限上容易导致分类错误的样本。
注意事项:



  • 欠采样大概导致信息丢失,尤其是当多数类样本中包罗告急信息时。
  • 大概削弱模子对多数类的识别能力。

三、选择依据


  • 数据集规模

    • 小数据集:优先思量过采样。
    • 大数据集:优先思量欠采样。

  • 任务目标

    • 少数类样本告急:优先思量过采样。
    • 多数类样本冗余:优先思量欠采样。

  • 盘算资源

    • 资源有限:优先思量欠采样。
    • 资源充足:优先思量过采样。

  • 模子特性

    • 对数据量敏感:优先思量过采样。
    • 对噪声敏感:优先思量欠采样。


四、综合计谋

在实际应用中,可以结合过采样和欠采样的长处,采用混淆计谋:


  • SMOTE + Tomek Links:先使用SMOTE生成少数类样本,再用Tomek Links清理界限样本。
  • 集成方法:如EasyEnsemble或BalanceCascade,通过多次欠采样构建多个均衡子集,训练集成模子。

总结



  • 过采样适用于小数据集、少数类样本告急或模子对数据量敏感的场景,但需注意过拟合风险。
  • 欠采样适用于大数据集、多数类样本冗余或盘算资源有限的场景,但需注意信息丢失问题。
  • 根据详细任务需求和数据特点,灵活选择或结合两种方法,以达到最佳模子性能。
这里我们使用欠采样
  1. import pandas as pd
  2. from imblearn.under_sampling import RandomUnderSampler
  3. from imblearn.over_sampling import RandomOverSampler
  4. #读取CSV文件
  5. csv_file_path = "data/Weibo/train.csv"
  6. df = pd.read_csv(csv_file_path)
  7. #定义重采样策略
  8. #如果想要过采样,使用RandomOverSampler
  9. #如果想要欠采样,使用RandomUnderSampler
  10. #我们在这里使用RandomUnderSampler进行欠采样
  11. #random_state控制随机数生成器的种子
  12. rus = RandomUnderSampler(sampling_strategy="auto",random_state=42)
  13. #将特征和标签分开
  14. X = df[["text"]]
  15. Y = df[["label"]]
  16. print(Y)
  17. #应用重采样
  18. X_resampled,Y_resampled = rus.fit_resample(X,Y)
  19. print(Y_resampled)
  20. #合并特征和标签,创建系的DataFrame
  21. df_resampled = pd.concat([X_resampled,Y_resampled],axis=1)
  22. print(df_resampled)
  23. #保存均衡数据到新的csv文件
  24. df_resampled.to_csv("train.csv",index=False)
复制代码
输出效果
  1. D:\miniconda3\envs\shenduxuexi\python.exe D:\JKAI\demo_7\data_test.py
  2. label
  3. 9    5045
  4. 6    5040
  5. 0    5040
  6. 7    5017
  7. 3    5000
  8. 4    4994
  9. 8    4983
  10. 1    4981
  11. 5    4950
  12. 2    4950
  13. Name: count, dtype: int64
  14. label
  15. 9    10.090
  16. 6    10.080
  17. 0    10.080
  18. 7    10.034
  19. 3    10.000
  20. 4     9.988
  21. 8     9.966
  22. 1     9.962
  23. 5     9.900
  24. 2     9.900
  25. Name: count, dtype: float64
复制代码
现在的数据分布非常的匀称
4.数据管理

  1. from torch.utils.data import Dataset
  2. from datasets import load_dataset
  3. class MyDataset(Dataset):
  4.     def __init__(self,split):
  5.         #从磁盘加载数据
  6.         self.dataset = load_dataset(path="csv",data_files=f"train.csv",split="train")
  7.     def __len__(self):
  8.         return len(self.dataset)
  9.     def __getitem__(self, item):
  10.         text = self.dataset[item]["text"]
  11.         label = self.dataset[item]["label"]
  12.         return text,label
  13. if __name__ == '__main__':
  14.     dataset = MyDataset("test")
  15.     for data in dataset:
  16.         print(data)
复制代码
5.定义网络布局

  1. from transformers import BertModel,BertConfig
  2. import torch
  3. DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
  4. #加载预训练模型
  5. pretrained = BertModel.from_pretrained(r"D:\JKAI\demo_7\model\bert-base-chinese\models--bert-base-chinese\snapshots\c30a6ed22ab4564dc1e3b2ecbf6e766b0611a33f").to(DEVICE)
  6. # pretrained.embeddings.position_embeddings = torch.nn.Embedding(1024,768).to(DEVICE)
  7. #config = BertConfig.from_pretrained(r"E:\PycharmProjects\demo_7\model\bert-base-chinese\models--bert-base-chinese\snapshots\c30a6ed22ab4564dc1e3b2ecbf6e766b0611a33f")
  8. #config.max_position_embeddings = 1024
  9. #print(config)
  10. #使用配置文件初始化模型
  11. #pretrained = BertModel(config).to(DEVICE)
  12. #print(pretrained)
  13. #定义下游任务
  14. class Model(torch.nn.Module):
  15.     def __init__(self):
  16.         super().__init__()
  17.         #设计全连接网络,实现二分类任务
  18.         self.fc = torch.nn.Linear(768,8)
  19.     def forward(self,input_ids,attention_mask,token_type_ids):
  20.         #冻结Bert模型的参数,让其不参与训练
  21.         with torch.no_grad():
  22.             out = pretrained(input_ids=input_ids,attention_mask=attention_mask,token_type_ids=token_type_ids)
  23.         #增量模型参与训练
  24.         out = self.fc(out.last_hidden_state[:,0])
  25.         return out
复制代码
6.模子训练
  1. #模型训练
  2. import torch
  3. from MyData import MyDataset
  4. from torch.utils.data import DataLoader
  5. from net import Model
  6. from transformers import BertTokenizer,AdamW
  7. #定义设备信息
  8. DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
  9. #定义训练的轮次
  10. EPOCH= 3000
  11. token = BertTokenizer.from_pretrained(r"D:\JKAI\demo_7\model\bert-base-chinese\models--bert-base-chinese\snapshots\c30a6ed22ab4564dc1e3b2ecbf6e766b0611a33f")
  12. def collate_fn(data):
  13.     sents = [i[0]for i in data]
  14.     label = [i[1] for i in data]
  15.     #编码
  16.     data = token.batch_encode_plus(
  17.         batch_text_or_text_pairs=sents,
  18.         truncation=True,
  19.         max_length=512,
  20.         padding="max_length",
  21.         return_tensors="pt",
  22.         return_length=True
  23.     )
  24.     input_ids = data["input_ids"]
  25.     attention_mask = data["attention_mask"]
  26.     token_type_ids = data["token_type_ids"]
  27.     labels = torch.LongTensor(label)
  28.     return input_ids,attention_mask,token_type_ids,labels
  29. #创建数据集
  30. train_dataset = MyDataset("train")
  31. train_loader = DataLoader(
  32.     dataset=train_dataset,
  33.     batch_size=120,
  34.     shuffle=True,
  35.     #舍弃最后一个批次的数据,防止形状出错
  36.     drop_last=True,
  37.     #对加载进来的数据进行编码
  38.     collate_fn=collate_fn
  39. )
  40. val_dataset = MyDataset("validation")
  41. val_loader = DataLoader(
  42.     dataset=val_dataset,
  43.     batch_size=2,
  44.     shuffle=True,
  45.     #舍弃最后一个批次的数据,防止形状出错
  46.     drop_last=True,
  47.     #对加载进来的数据进行编码
  48.     collate_fn=collate_fn
  49. )
  50. if __name__ == '__main__':
  51.     #开始训练
  52.     print(DEVICE)
  53.     model = Model().to(DEVICE)
  54.     #定义优化器
  55.     optimizer = AdamW(model.parameters())
  56.     #定义损失函数
  57.     loss_func = torch.nn.CrossEntropyLoss()
  58.     #初始化最佳验证准确率
  59.     best_val_acc = 0.0
  60.     for epoch in range(EPOCH):
  61.         for i,(input_ids,attention_mask,token_type_ids,labels) in enumerate(train_loader):
  62.             #将数据存放到DEVICE上
  63.             input_ids, attention_mask, token_type_ids, labels = input_ids.to(DEVICE),attention_mask.to(DEVICE),token_type_ids.to(DEVICE),labels.to(DEVICE)
  64.             #前向计算(将数据输入模型,得到输出)
  65.             out = model(input_ids=input_ids,attention_mask=attention_mask,token_type_ids=token_type_ids)
  66.             #根据输出,计算损失
  67.             loss = loss_func(out,labels)
  68.             #根据损失,优化参数
  69.             optimizer.zero_grad()
  70.             loss.backward()
  71.             optimizer.step()
  72.             #每隔5个批次输出训练信息
  73.             if i%5==0:
  74.                 out = out.argmax(dim=1)
  75.                 acc = (out==labels).sum().item()/len(labels)
  76.                 print(f"epoch:{epoch},i:{i},loss:{loss.item()},acc:{acc}")
  77.         #验证模型(判断是否过拟合)
  78.         #设置为评估模式
  79.         model.eval()
  80.         #不需要模型参与训练
  81.         with torch.no_grad():
  82.             val_acc = 0.0
  83.             val_loss = 0.0
  84.             for i, (input_ids, attention_mask, token_type_ids, labels) in enumerate(val_loader):
  85.                 # 将数据存放到DEVICE上
  86.                 input_ids, attention_mask, token_type_ids, labels = input_ids.to(DEVICE), attention_mask.to(
  87.                     DEVICE), token_type_ids.to(DEVICE), labels.to(DEVICE)
  88.                 # 前向计算(将数据输入模型,得到输出)
  89.                 out = model(input_ids=input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids)
  90.                 # 根据输出,计算损失
  91.                 val_loss += loss_func(out, labels)
  92.                 out = out.argmax(dim=1)
  93.                 val_acc+=(out==labels).sum().item()
  94.             val_loss /= len(val_loader)
  95.             val_acc /= len(val_loader)
  96.             print(f"验证集:loss:{val_loss},acc:{val_acc}")
  97.             #根据验证准确率保存最优参数
  98.             if val_acc > best_val_acc:
  99.                 best_val_acc = val_acc
  100.                 torch.save(model.state_dict(),"params/best_bert.pth")
  101.                 print(f"Epoch:{epoch}:保存最优参数:acc:{best_val_acc}")
  102.         #保存最后一轮参数
  103.         torch.save(model.state_dict(),f"params/last_bert.pth")
  104.         print(epoch,f"Epcot:{epoch}最后一轮参数保存成功!")
复制代码
7.体验模子
  1. import torch
  2. from net import Model
  3. from transformers import BertTokenizer
  4. #定义设备信息
  5. DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
  6. print(DEVICE)
  7. token = BertTokenizer.from_pretrained(r"D:\JKAI\demo_7\model\bert-base-chinese\models--bert-base-chinese\snapshots\c30a6ed22ab4564dc1e3b2ecbf6e766b0611a33f")
  8. names = [   "like",
  9.                 "disgust",
  10.                 "happiness",
  11.                 "sadness",
  12.                 "anger",
  13.                 "surprise",
  14.                 "fear",
  15.                 "none"]
  16. model = Model().to(DEVICE)
  17. def collate_fn(data):
  18.     sents = []
  19.     sents.append(data)
  20.     #编码
  21.     data = token.batch_encode_plus(
  22.         batch_text_or_text_pairs=sents,
  23.         truncation=True,
  24.         max_length=500,
  25.         padding="max_length",
  26.         return_tensors="pt",
  27.         return_length=True
  28.     )
  29.     input_ids = data["input_ids"]
  30.     attention_mask = data["attention_mask"]
  31.     token_type_ids = data["token_type_ids"]
  32.     return input_ids, attention_mask, token_type_ids
  33. def test():
  34.     #加载训练参数
  35.     model.load_state_dict(torch.load("params/best_bert.pth",map_location=DEVICE))
  36.     #开启测试模式
  37.     model.eval()
  38.     while True:
  39.         data = input("请输入测试数据(输入‘q’退出):")
  40.         if data == 'q':
  41.             print("测试结束")
  42.             break
  43.         input_ids, attention_mask, token_type_ids = collate_fn(data)
  44.         input_ids, attention_mask, token_type_ids = input_ids.to(DEVICE), attention_mask.to(DEVICE), \
  45.             token_type_ids.to(DEVICE)
  46.         with torch.no_grad():
  47.             out = model(input_ids, attention_mask, token_type_ids)
  48.             out = out.argmax(dim=1)
  49.             print("模型判定:",names[out],"\n")
  50. if __name__ == '__main__':
  51.     test()
复制代码
可以正确的判定出,是哪一种范例的评价。 


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

万万哇

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表