马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
学习视频所在
项目所在
数据集的下载
- # 将数据集下载到本地
- from datasets import load_dataset
- # 在代码开头添加(抑制所有警告)
- import os
- os.environ["HF_HUB_DISABLE_SYMLINKS_WARNING"] = "1"
- # 指定数据集名称和本地缓存路径
- dataset_name = "lansinuote/ChnSentiCorp"
- cache_dir = "data/lansinuote/ChnSentiCorp"
- # 下载并加载数据集
- # 下载并加载数据集(添加信任远程代码参数)
- dataset = load_dataset(
- dataset_name,
- cache_dir=cache_dir,
- trust_remote_code=True # 关键修复参数
- )
- print(f"数据集已下载到:{cache_dir}")
- print("\n第一条数据样例:")
- print(dataset["train"][0])
复制代码
- from datasets import Dataset
- # 取出测试集
- test_set = Dataset.from_file("./data/lansinuote/ChnSentiCorp/chn_senti_corp-test.arrow")
- print(test_set)
- # 查看数据
- for data in test_set:
- print(data)
- # 取出训练集
- train_set = Dataset.from_file(".//data/lansinuote/ChnSentiCorp/chn_senti_corp-train.arrow")
- print(train_set)
- # 查看数据
- for data in train_set:
- print(data)
- # 取出验证集
- validation_set = Dataset.from_file("./data/lansinuote/ChnSentiCorp/chn_senti_corp-validation.arrow")
- print(validation_set)
- # 查看数据
- for data in validation_set:
- print(data)
复制代码 模子微调的根本概念与流程
- 微调指在预训练模子的底子上,通过进一步的训练来顺应特定的卑鄙使命。BERT模子通过预训练来学习语言的通用模式,然后通过微调来顺应特定使命,如感情分析、定名实体辨认等。微调过程中,通常冻结BERT的预训练层,只训练与卑鄙使命相干的层。
加载数据集
- 感情分析使命的数据通常包罗文本及其对应的感情标签。利用HuggingFace的datasets库可以轻松地加载和处置惩罚数据集。
- from datasets import load_dataset
- #加载数据集
- dataset =load_dataset('csv',data_files="data/chnsenticorp.csv")
- #查看数据集信息
- print(dataset)
复制代码 数据集格式
- Hugging Face 的 datasets 库支持多种数据集格式,如 CSV、JSON、TFRecord 等。在本案例中,利用CSV格式,CSV文件应包罗两列:一列是文本数据,另一列是感情标签。
数据集信息
- 加载数据集后,可以查察数据集的根本信息,如数据集巨细、字段名称等。
制作Dataset
- 加载数据集后,须要对其举行处置惩罚以顺应模子的输入格式。这包罗数据洗濯、格式转换等操纵。
- from torch.utils.data import Dataset, DataLoader
- from datasets import Dataset as HFDataset # 重命名以避免冲突
- class MyDataset(Dataset):
- def __init__(self, split):
- # 根据 split 确定 .arrow 文件路径
- if split == "train":
- data_path = "./data/train/chn_senti_corp-train.arrow"
- elif split == "test":
- data_path = "./data/test/chn_senti_corp-test.arrow"
- elif split == "validation":
- data_path = "./data/validation/chn_senti_corp-validation.arrow"
- else:
- raise ValueError("无效的数据集类型,必须是 train/test/validation")
- # 加载 Hugging Face Dataset
- self.hf_dataset = HFDataset.from_file(data_path)
- def __len__(self):
- return len(self.hf_dataset)
- def __getitem__(self, idx):
- text = self.hf_dataset[idx]["text"]
- label = self.hf_dataset[idx]["label"]
- return text, label
- if __name__ == "__main__":
- # 创建 PyTorch Dataset
- dataset = MyDataset("train")
- # 使用 DataLoader 进行迭代
- dataloader = DataLoader(dataset, batch_size=1, shuffle=True)
- for data in dataloader:
- print(data)
复制代码 数据集字段
- 在制作Dataset时,需界说数据集的字段。在本案例中,界说了两个字段:text(文本)和labe1(感情标签)。每个字段都须要与模子的输入和输出匹配。
数据集信息
- 制作Dataset后,可以通过dataset.info等方法查察其巨细、字段名称等信息,以确保数据集的精确性和完备性。
vocab字典操纵
词汇表
- BERT模子利用词汇表(vocab)将文本转换为模子可以明白的输入格式。词汇表包罗全部模子已知的单词及其对应的索引。确保数据会合的全部文本都能找到对应的词汇索引是至关告急的。
- from transformers import BertTokenizer
- model_name="./model/google-bert/bert-base-chinese/models--google-bert--bert-base-chinese/snapshots/c30a6ed22ab4564dc1e3b2ecbf6e766b0611a33f"
- # 加载字典和分词工具
- # token=BertTokenizer.from_pretrained("bert-base-chinese") # 在线方式
- token=BertTokenizer.from_pretrained(model_name) # 使用本地方式(推荐)
- '''
- sents=["酒店太旧,大堂感觉像三星级水平,在郑州这样的酒店水平,绝对算不上四星水平,早餐走了两圈也没有可以吃的,太差",
- "已经贴完了,又给小区的妈妈买了一套,值得推荐",
- "屏幕大,本子薄。自带数字小键盘,比较少见,声音很好,usb接口也很多,性价比高",
- "酒店环境很好,就是有一点偏僻,交通不是很好,不太好打车,酒店应该想办法解决一下"]
- '''
- # 批量编码句子
- '''
- out=token.batch_encode_plus(
- batch_text_or_text_pairs=[sents[0],sents[1]],
- add_special_tokens=True,
- truncation=True, # 句子过长截断
- padding="max_length", # 一律补零到max_length长度
- max_length=30,
- return_tensors=None, # 默认返回list
- return_attention_mask=True, # 返回 attention_mask
- return_token_type_ids=False,
- return_special_tokens_mask=True, #特殊符号标识
- return_length=True, # 返回length,标识长度
- )
- print(out)
- '''
- # 获取字典
- # vocab=token.get_vocab()
- # print(vocab)
- # print("阳" in vocab)
- # 添加新词
- token.add_tokens(new_tokens=["阳光","大志"])
- # 重新获取字典
- vocab=token.get_vocab()
- print("大志" in vocab)
- # 添加新的特殊符号 本质键值对
- # token.add_special_tokens({"eos_token":"[EOS]"})
- # 编码新句子
- res=token.encode(
- text="阳光照在大地上[EOS]",
- text_pair=None,
- truncation=True,
- padding="longest",
- longest=10,
- add_special_tokens=True,
- return_tensors=None
- )
- print(res)
- # 解码为源字符串
- print(token.decode(res))
复制代码 文本转换
- 利用tokenizer将文天职割成词汇表中的单词,并转换为相应的索引l。此步调须要确保文本长度、特别字符处置惩罚等都与BERT模子的预训练设置相同等。
卑鄙使命模子筹划
- 在微调BERT模子之前,须要筹划一个顺应感情分析使命的卑鄙模子布局。通常包罗一个或多个全毗连层,用于将BERT输出的特性向量转换为分类效果。
- # 加载预训练模型
- from transformers import BertModel
- import torch
- # 定义训练设备
- DEVICE=torch.device('cuda' if torch.cuda.is_available() else 'cpu')
- model_dir="./model/google-bert/bert-base-chinese/models--google-bert--bert-base-chinese/snapshots/c30a6ed22ab4564dc1e3b2ecbf6e766b0611a33f"
- pretrained=BertModel.from_pretrained(model_dir).to(DEVICE)
- # 定义下游任务模型(将主干网络所提取的特征进行分类)
- class Model(torch.nn.Module):
- def __init__(self):
- super().__init__()
- # 上一步 最后输出全连接模型 Linear(in_features=768, out_features=768, bias=True)
- self.fc = torch.nn.Linear(768, 2)
- # 训练推理
- 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)
- # 下游任务参与训练
- output=self.fc(out.last_hidden_state[:0])
- output=output.softmax(dim=1)
- return output;
复制代码 模子训练与生存
数据加载
- 利用DataLoader实现批量数据加载。DataLoader主动处置惩罚数据的批处置惩罚和随机打乱,确保训l练的高效性和数据的多样性。
优化器
- Adamw是一种实用于BERT模子的优化器,联合了Adam和权重衰减的特点,可以大概有用地防止过拟合。
训练循环
- 训练循环包罗前向传播(forward pass)、丧失盘算(loss calculation)、反向传播(backward pass)、参数更新(parameter update)等步调。每个epoch 都会对整个数据集举行一次遍历,更新模子参数。通常训练过程中会跟踪丧失值的厘革,以判定模子的收敛环境。
- import torch
- from torch.optim import AdamW
- from MyData import MyDataset
- from torch.utils.data import DataLoader
- from Net import Model
- from transformers import BertTokenizer
- # 定义训练设备
- DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
- EPOCHS = 100
- BATCH_SIZE = 32
- # 加载分词器
- model_name = "./model/google-bert/bert-base-chinese/models--google-bert--bert-base-chinese/snapshots/c30a6ed22ab4564dc1e3b2ecbf6e766b0611a33f"
- token = BertTokenizer.from_pretrained(model_name)
- # 自定义数据编码处理函数
- def collate_fn(data):
- sente = [i[0] for i in data]
- label = [i[1] for i in data]
- # 编码处理
- data = token.batch_encode_plus(
- batch_text_or_text_pairs=sente,
- truncation=True,
- padding='max_length',
- max_length=300,
- return_tensors='pt',
- return_length=True
- )
- input_ids = data['input_ids']
- attention_mask = data['attention_mask']
- token_type_ids = data['token_type_ids']
- labels = torch.LongTensor(label)
- return input_ids, attention_mask, token_type_ids, labels
- # 创建数据集
- train_dataset = MyDataset("train")
- # 创建数据加载器
- train_loader = DataLoader(
- dataset=train_dataset,
- batch_size=BATCH_SIZE,
- shuffle=True,
- drop_last=True,
- collate_fn=collate_fn # 只传递函数名
- )
- if __name__ == '__main__':
- # start train
- print(DEVICE)
- model = Model().to(DEVICE)
- # 优化器
- optimizer = AdamW(model.parameters(), lr=5e-4)
- # loss function
- loss_func=torch.nn.CrossEntropyLoss()
- # train model
- model.train()
- for epoch in range(EPOCHS):
- for i,(input_ids, attention_mask, token_type_ids, labels) in enumerate(train_loader):
- # 将数据放到DEVICE上
- 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)
- # print("Output shape:", out.shape)
- # 计算损失
- loss = loss_func(out, labels)
- # 优化模型 清空权重 反向传播 更新梯度
- optimizer.zero_grad()
- loss.backward()
- optimizer.step()
- # 每5个查看一下
- if i%20==0:
- out=out.argmax(dim=1)
- # 准确率
- acc=(out==labels).sum()/len(labels)
- print(epoch,i,loss.item(),acc)
- # 保存模型参数
- torch.save(model.state_dict(),f"./params/{epoch}bert.pt")
- print(epoch)
复制代码 终极效果评估与测试
- 在模子训练完成后,须要评估其在测试集上的性能。通常利用精确率、准确率、召回率和F1分数等指标来衡量模子的效果。
- 精确率是衡量分类模子团体性能的根本指标,盘算公式为精确分类的样本数量除以总样本数量。
- 准确率、召回率是分类模子的另两个告急指标,分别反映模子在正例推测上的准确性和召回本领。
- F1分数是准确率和召回率的调和匀称数,通常用于不平衡数据集的评估。
- import torch
- from Net import Model
- from transformers import BertTokenizer
- from MyData import MyDataset
- from torch.utils.data import DataLoader
- DEVICE = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
- # 加载分词器
- model_name = "./model/google-bert/bert-base-chinese/models--google-bert--bert-base-chinese/snapshots/c30a6ed22ab4564dc1e3b2ecbf6e766b0611a33f"
- token = BertTokenizer.from_pretrained(model_name)
- # 自定义数据编码处理函数
- def collate_fn(data):
- sente = [i[0] for i in data]
- label = [i[1] for i in data]
- # 编码处理
- data = token.batch_encode_plus(
- batch_text_or_text_pairs=sente,
- truncation=True,
- padding='max_length',
- max_length=300,
- return_tensors='pt',
- return_length=True
- )
- input_ids = data['input_ids']
- attention_mask = data['attention_mask']
- token_type_ids = data['token_type_ids']
- labels = torch.LongTensor(label)
- return input_ids, attention_mask, token_type_ids, labels
- # 创建数据集
- train_dataset = MyDataset("train")
- # 创建数据加载器
- train_loader = DataLoader(
- dataset=train_dataset,
- batch_size=32,
- shuffle=True,
- drop_last=True,
- collate_fn=collate_fn # 只传递函数名
- )
- if __name__ == "__main__":
- acc=0
- total=0
- model=Model().to(DEVICE)
- model.load_state_dict(torch.load("./params/1bert.pt"))
- model.eval() # 开启模型测试模式
- for i, (input_ids, attention_mask, token_type_ids, labels) in enumerate(train_loader):
- # 将数据放到DEVICE上
- 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)
- out=out.argmax(dim=1)
- acc+=(out==labels).sum().item()
- total+=len(labels)
- print(acc/total)
复制代码 模子加载和测试
- import torch
- from transformers import BertTokenizer
- from emotionAnalysis.Net import Model
- DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
- print(DEVICE)
- values=["负向评价","正向评价"]
- model=Model().to(DEVICE)
- # 加载分词器
- model_name = "./model/google-bert/bert-base-chinese/models--google-bert--bert-base-chinese/snapshots/c30a6ed22ab4564dc1e3b2ecbf6e766b0611a33f"
- token = BertTokenizer.from_pretrained(model_name)
- # 自定义数据编码处理函数
- def collate_fn(data):
- sente = [data]
- # 编码处理
- data = token.batch_encode_plus(
- batch_text_or_text_pairs=sente,
- truncation=True,
- padding='max_length',
- max_length=300,
- return_tensors='pt',
- return_length=True
- )
- input_ids = data['input_ids']
- attention_mask = data['attention_mask']
- token_type_ids = data['token_type_ids']
- return input_ids, attention_mask, token_type_ids
- def test():
- model.load_state_dict(torch.load("./params/1bert.pt"))
- model.eval()
- while True:
- data=input("请输入测试数据(输入‘q’退出):")
- if data=="q":
- print("测试结束")
- break
- input_ids, attention_mask, token_type_ids=collate_fn(data)
- input_ids, attention_mask, token_type_ids=input_ids.to(DEVICE), attention_mask.to(DEVICE), token_type_ids.to(DEVICE)
- with torch.no_grad():
- out=model(input_ids=input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids)
- out=out.argmax(dim=1)
- print("模型判定:",values[out],"\n")
- if __name__=="__main__":
- test()
复制代码- cuda
- 请输入测试数据(输入‘q’退出):酒店服务不错,环境也还比较好!特别是好像是48楼那个旋转餐厅满有特色,至少我觉得住这个酒店还满满意!
- 模型判定: 正向评价
- 请输入测试数据(输入‘q’退出):东西很差
- 模型判定: 负向评价
- 请输入测试数据(输入‘q’退出):东西很好,我要再买一个
- 模型判定: 正向评价
- 请输入测试数据(输入‘q’退出):我真的会谢谢你
- 模型判定: 正向评价
- 请输入测试数据(输入‘q’退出):真的很栓Q
- 模型判定: 负向评价
复制代码 |