赞
踩
先安装fasttext
pip install fasttext
二分类:
文本被分类两个类别中, 往往这两个类别是对立面, 比如: 判断一句评论是好评还是差评.
单标签多分类:
文本被分入到多个类别中, 且每条文本只能属于某一个类别(即被打上某一个标签), 比如: 输入一个人名, 判断它是来自哪个国家的人名.
多标签多分类:
文本被分人到多个类别中, 但每条文本可以属于多个类别(即被打上多个标签), 比如: 输入一段描述, 判断可能是和哪些兴趣爱好有关, 一段描述中可能即讨论了美食, 又太讨论了游戏爱好.
fasttext_data文件中
下载完数据文件并上传到服务器后,可以进入相应目录进行查看数据操作
# 导入fasttext
import fasttext
# help(fasttext)
# 使用fasttext的train_supervised方法进行文本分类模型的训练
model = fasttext.train_supervised(input="../data/fasttext_data/cooking.train")
运行结果
1.检查一下路径名是否正确还有就是不能有中文
2.路径开头使用…/ 而不要使用./(部分版本会出这个问题)
model.test("data/cooking/cooking.valid")
# 这些因素对我们最终的分类目标没有益处, 反是增加了模型提取分类规律的难度,
# 因此我们选择将它们去除或转化
# 处理前的部分数据
__label__fish Arctic char available in North-America
__label__pasta __label__salt __label__boiling When cooking pasta in salted water how much of the salt is absorbed?
__label__coffee Emergency Coffee via Chocolate Covered Coffee Beans?
__label__cake Non-beet alternatives to standard red food dye
__label__cheese __label__lentils Could cheese "halt" the tenderness of cooking lentils?
__label__asian-cuisine __label__chili-peppers __label__kimchi __label__korean-cuisine What kind of peppers are used in Gochugaru ()?
__label__consistency Pavlova Roll failure
__label__eggs __label__bread What qualities should I be looking for when making the best French Toast?
__label__meat __label__flour __label__stews __label__braising Coating meat in flour before browning, bad idea?
__label__food-safety Raw roast beef on the edge of safe?
__label__pork __label__food-identification How do I determine the cut of a pork steak prior to purchasing it?
def add_train():
model = fasttext.train_supervised(input="../data/fasttext_data/cooking.train", epoch=25)
result = model.test("../data/fasttext_data/cooking.valid")
return result
def main():
# print( model_test_by_ft() )
add_train()
return 0
model = fasttext.train_supervised(input="../data/fasttext_data/cooking.train", lr=1.0, epoch=25)
model = fasttext.train_supervised(input="../data/fasttext_data/cooking.train", lr=1.0, epoch=25, wordNgrams=2)
N-Gram特征的创建:设定滑动窗口长度(字节片段长度N),对恶意代码内容按字节特征大小进行滑动,每一个字节片段称为gram;统计gram出现的频度,设定阈值进行归一化
model = fasttext.train_supervised(input="../data/fasttext_data/cooking.train", lr=1.0, epoch=25, wordNgrams=2, loss='hs')
# autotuneValidationFile参数需要指定验证数据集所在路径, 它将在验证集上使用随机搜索方法寻找可能最优的超参数.
# 使用autotuneDuration参数可以控制随机搜索的时间, 默认是300s, 根据不同的需求, 我们可以延长或缩短时间.
# 验证集路径'cooking.valid', 随机搜索600秒
model = fasttext.train_supervised(input='../data/fasttext_data/cooking.train', autotuneValidationFile='data/cooking/cooking.pre.valid', autotuneDuration=600)
def save_model(model, path): model.save_model(path) def read_model_by_path(path): model = fasttext.load_model(path) return model def main(): # print( model_test_by_ft() ) # add_train() model = fasttext.train_supervised\ (input='../data/fasttext_data/cooking.train', autotuneValidationFile='../data/fasttext_data/cooking.valid', autotuneDuration=600) save_model(model, "../data/model/model_cooking.bin") read_model_by_path(path="../data/model/model_cooking.bin") return 0
用向量表示文本中的词汇(或字符)是现代机器学习中最流行的做法, 这些向量能够很好的捕捉语言之间的关系, 从而提升基于词向量的各种NLP任务的效果.
wget https://dl.fbaipublicfiles.com/fasttext/vectors-crawl/cc.zh.300.bin.gz
gunzip cc.zh.300.bin.gz
model = fasttext.load_model("./data/cc.zh.300.bin")
model.get_word_vector("音乐")
model.get_nearest_neighbors("音乐")
一般情况下预训练模型都是大型模型,具备复杂的网络结构,众多的参数量,以及在足够大的数据集下进行训练而产生的模型. 在NLP领域,预训练模型往往是语言模型,因为语言模型的训练是无监督的,可以获得大规模语料,同时语言模型又是许多典型NLP任务的基础
根据给定的预训练模型,改变它的部分参数或者为其新增部分输出结构后,通过在小部分数据集上训练,来使整个模型更好的适应特定任务
实现微调过程的代码文件。这些脚本文件中,应包括对预训练模型的调用,对微调参数的选定以及对微调结构的更改等,同时,因为微调是一个训练过程,它同样需要一些超参数的设定,以及损失函数和优化器的选取等, 因此微调脚本往往也包含了整个迁移学习的过程.
1.直接使用预训练模型,进行相同任务的处理,不需要调整参数或模型结构,这些模型开箱即用。但是这种情况一般只适用于普适任务
2.更加主流的迁移学习方式是发挥预训练模型特征抽象的能力,然后再通过微调的方式,通过训练更新小部分参数以此来适应不同的任务。
GLUE由纽约大学, 华盛顿大学, Google联合推出, 涵盖不同NLP任务类型, 截止至2020年1月其中包括11个子任务数据集, 成为衡量NLP研究发展的衡量标准
GLUE官网
BERT
GPT
GPT-2
Transformer-XL
XLNet
XLM
RoBERTa
DistilBERT
ALBERT
T5
XLM-RoBERTa
Huggingface总部位于纽约,是一家专注于自然语言处理、人工智能和分布式系统的创业公司。他们所提供的聊天机器人技术一直颇受欢迎,但更出名的是他们在NLP开源社区上的贡献。Huggingface一直致力于自然语言处理NLP技术的平民化(democratize),希望每个人都能用上最先进(SOTA, state-of-the-art)的NLP技术,而非困窘于训练资源的匮乏。同时Hugging Face专注于NLP技术,拥有大型的开源社区。尤其是在github上开源的自然语言处理,预训练模型库 Transformers,已被下载超过一百万次,github上超过24000个star
管道(Pipline)方式:高度集成的极简使用方式,只需要几行代码即可实现一个NLP任务。
自动模型(AutoMode)方式:可载入并使用BERTology系列模型。
具体模型(SpecificModel)方式:在使用时,需要明确指定具体的模型,并按照每个BERTology系列模型中的特定参数进行调用,该方式相对复杂,但具有较高的灵活度。
# 注意在执行clone之前,要查看当前是在那个目录下,比如$HOME/nlpdev/目录下
# 克隆huggingface的transfomers文件
git clone https://github.com/huggingface/transformers.git
# 进行transformers文件夹
cd transformers
# 切换transformers到指定版本
git checkout v4.19.0
# 安装transformers包
pip install .
顺便安装一下数据集库
pip install datasets
def dm01_test_classification(): # 1 使用中文预训练模型chinese_sentiment # 模型下载地址 git clone https://huggingface.co/techthiyanes/chinese_sentiment # 2 实例化pipeline对象 # my_model = pipeline(task='sentiment-analysis', model='../data/chinese_sentiment.bin', # encoding='gbk') my_model = pipeline(task='sentiment-analysis', model='./bert-base-chinese') # 3 文本送给模型 进行文本分类 output = my_model('我爱北京天安门,天安门上太阳升。') print('output--->', output) def main(): dm01_test_classification() return 0 if __name__ == '__main__': main()
# 特征抽取任务
def dm02_test_feature_extraction():
# 1 下载中文预训练模型 git clone https://huggingface.co/bert-base-chinese
# 2 实例化pipeline对象 返回模型对象
my_model = pipeline(task='feature-extraction', model='./bert-base-chinese')
# 3 给模型送数据 提取语句特征
output = my_model('人生该如何起头')
print('output--->', type(output), np.array(output).shape)
# 输出结果
# output---> <class 'list'> (1, 9, 768)
# 7个字变成9个字原因: [CLS] 人 生 该 如 何 起 头 [SEP]
# 完型填空任务
def dm03_test_fill_mask():
# 1 下载预训练模型 全词模型git clone https://huggingface.co/hfl/chinese-bert-wwm
# 2 实例化pipeline对象 返回一个模型
my_model = pipeline(task='fill-mask', model='chinese-bert-wwm')
# 3 给模型送数据 做预测
input = '我想明天去[MASK]家吃饭。'
output = my_model(input)
# 4 输出预测结果
print('output--->', output)
# 阅读理解任务(抽取式问答)
def dm04_test_question_answering():
# 问答语句
context = '我叫张三,我是一个程序员,我的喜好是打篮球。'
questions = ['我是谁?', '我是做什么的?', '我的爱好是什么?']
# 1 下载模型 git clone https://huggingface.co/luhua/chinese_pretrain_mrc_roberta_wwm_ext_large
# 2 实例化化pipeline 返回模型
model = pipeline('question-answering', model='chinese_pretrain_mrc_roberta_wwm_ext_large')
# 3 给模型送数据 的预测结果
print(model(context=context, question=questions))
# 文本摘要任务 def dm05_test_summarization(): # 1 下载模型 git clone https://huggingface.co/sshleifer/distilbart-cnn-12-6 # 2 实例化pipline 返回模型 my_model = pipeline(task = 'summarization', model="distilbart-cnn-12-6") # 3 准备文本 送给模型 text = "BERT is a transformers model pretrained on a large corpus of English data " \ "in a self-supervised fashion. This means it was pretrained on the raw texts " \ "only, with no humans labelling them in any way (which is why it can use lots " \ "of publicly available data) with an automatic process to generate inputs and " \ "labels from those texts. More precisely, it was pretrained with two objectives:Masked " \ "language modeling (MLM): taking a sentence, the model randomly masks 15% of the " \ "words in the input then run the entire masked sentence through the model and has " \ "to predict the masked words. This is different from traditional recurrent neural " \ "networks (RNNs) that usually see the words one after the other, or from autoregressive " \ "models like GPT which internally mask the future tokens. It allows the model to learn " \ "a bidirectional representation of the sentence.Next sentence prediction (NSP):" \ " the models" \ " concatenates two masked sentences as inputs during pretraining. Sometimes " \ "they correspond to " \ "sentences that were next to each other in the original text, sometimes not." \ " The model then " \ "has to predict if the two sentences were following each other or not." output = my_model(text) # 4 打印摘要结果 print('output--->', output)
实体词识别(NER)任务是NLP中的基础任务。它用于识别文本中的人名(PER)、地名(LOC)、组织(ORG)以及其他实体(MISC)等。例如:(王 B-PER) (小 I-PER) (明 I-PER) (在 O) (办 B-LOC) (公 I-LOC) (室 I-LOC)。其中O表示一个非实体,B表示一个实体的开始,I表示一个实体块的内部。
实体词识别本质上是一个分类任务(又叫序列标注任务),实体词识别是句法分析的基础,而句法分析优势NLP任务的核心。`
# NER任务
def dm06_test_ner():
# 1 下载模型 git clone https://huggingface.co/uer/roberta-base-finetuned-cluener2020-chinese
# 2 实例化pipeline 返回模型
model = pipeline('ner', model='roberta-base-finetuned-cluener2020-chinese')
# 3 给模型送数据 打印NER结果
print(model('我爱北京天安门,天安门上太阳升。'))
由于和前面大同小异
以分类、NER为列子
AutoTokenizer、AutoModelForSequenceClassification函数可以自动从官网下载预训练模型,也可以加载本地的预训练模型
AutoModelForSequenceClassification类管理着分类任务,会根据参数的输入选用不同的模型。
AutoTokenizer的encode()函数使用return_tensors=’pt‘参数和不使用pt参数对文本编码的结果不同
AutoTokenizer的encode()函数使用padding='max_length'可以按照最大程度进行补齐,俗称打padding
调用模型的forward函数输入return_dict=False参数,返回结果也不同
# 导入工具包 import torch from transformers import AutoConfig, AutoModel, AutoTokenizer from transformers import AutoModelForSequenceClassification, AutoModelForMaskedLM, AutoModelForQuestionAnswering # AutoModelForSeq2SeqLM:文本摘要 # AutoModelForTokenClassification:ner from transformers import AutoModelForSeq2SeqLM, AutoModelForTokenClassification # 情感分类任务 def dm01_test_classification(): # 1 加载tokenizer my_tokenizer = AutoTokenizer.from_pretrained('./chinese_sentiment') # 2 加载模型 my_model = AutoModelForSequenceClassification.from_pretrained('./chinese_sentiment') # 3 文本转张量 message = '人生该如何起头' # 3-1 return_tensors='pt' 返回是二维tensor msg_tensor1 = my_tokenizer.encode(text=message, return_tensors='pt', padding=True, truncation=True, max_length=20) print('msg_tensor1--->', msg_tensor1) # 3-2 不用return_tensors='pt'是一维列表 msg_list2 = my_tokenizer.encode(text=message, padding=True, truncation=True, max_length=20) print('msg_list2--->', msg_list2) msg_tensor2 = torch.tensor([msg_list2]) print('msg_tensor2--->', msg_tensor2) # 4 数据送给模型 # 4-1 my_model.eval() output1 = my_model(msg_tensor2) print('情感分类模型头输出outpout1--->', output1) # 4-2 output2 = my_model(msg_tensor2, return_dict=False) print('情感分类模型头输出outpout2--->', output2)
# NER任务 def dm06_test_ner(): # 1 加载tokenizer 加载模型 加载配置文件 # https://huggingface.co/uer/roberta-base-finetuned-cluener2020-chinese my_tokenizer = AutoTokenizer.from_pretrained('roberta-base-finetuned-cluener2020-chinese') my_model = AutoModelForTokenClassification.from_pretrained('roberta-base-finetuned-cluener2020-chinese') config = AutoConfig.from_pretrained('roberta-base-finetuned-cluener2020-chinese') # 2 数据张量化 inputs = my_tokenizer.encode_plus('我爱北京天安门,天安门上太阳升', return_tensors='pt') print('inputs--->', inputs.input_ids.shape, inputs.input_ids) # torch.Size([1, 17]) # 3 送入模型 预测ner概率 每个字预测的标签概率 my_model.eval() logits = my_model(inputs.input_ids).logits print('logits--->', logits.shape) # torch.Size([1, 17, 32]) # 4 对预测数据 进行显示 input_tokens = my_tokenizer.convert_ids_to_tokens(inputs.input_ids[0]) print('input_tokens--->', input_tokens) outputs = [] for token, value in zip(input_tokens, logits[0]): if token in my_tokenizer.all_special_tokens: continue # 获得每个字预测概率最大的标签索引 idx = torch.argmax(value).item() # 打印索引对应标签 outputs.append((token, config.id2label[idx])) print(outputs)
类型一: 直接加载预训练模型进行输入文本的特征表示, 后接自定义网络进行微调输出结果
类型二: 使用指定任务类型的微调脚本微调预训练模型, 后接带有输出头的预定义网络输出结果
说明: 所有类型的实战演示, 都将针对中文文本进行
# 导入工具包
import torch
from datasets import load_dataset
from transformers import BertTokenizer, BertModel
from transformers import AdamW
import time
# 加载字典和分词工具 实例化分词工具
my_tokenizer = BertTokenizer.from_pretrained('bert-base-chinese')
# 加载预训练模型 实例化预训练模型
my_model_pretrained = BertModel.from_pretrained('bert-base-chinese')
数据文件有三个train.csv,test.csv,validation.csv,数据样式都是一样的
zhujiang_garden下载
代码查看一下
def check_dataset_by_csv(): # 实例化数据源对象my_dataset_train print('\n加载训练集') my_dataset_train = load_dataset('csv', data_files='../data/' 'zhujiang_garden/train.csv', split='train') print('dataset_train--->', my_dataset_train) print(my_dataset_train[0:3]) # 实例化数据源对象my_dataset_test print('\n加载测试集') my_dataset_test = load_dataset('csv', data_files='../data/' 'zhujiang_garden/test.csv', split='train') print('my_dataset_test--->', my_dataset_test) print(my_dataset_test[0:3]) print('\n加载验证集') # 实例化数据源对象my_dataset_train my_dataset_validation = load_dataset('csv', data_files='../data/' 'zhujiang_garden/validation.csv', split="train") print('my_dataset_validation--->', my_dataset_validation) print(my_dataset_validation[0:3]) def main(): check_dataset_by_csv() return 0 if __name__ == '__main__': main()
# 数据集处理自定义函数 def collate_fn1(data): # data传过来的数据是list eg: 批次数8,8个字典 # [{'text':'xxxx','label':0} , {'text':'xxxx','label':1}, ...] sents = [i['text'] for i in data] labels = [i['label'] for i in data] # 编码text2id 对多句话进行编码用batch_encode_plus函数 data = my_tokenizer.batch_encode_plus(batch_text_or_text_pairs=sents, truncation=True, padding='max_length', max_length=500, return_tensors='pt', return_length=True) # input_ids:编码之后的数字 # attention_mask:是补零的位置是0,其他位置是1 input_ids = data['input_ids'] attention_mask = data['attention_mask'] token_type_ids = data['token_type_ids'] labels = torch.LongTensor(labels) # 返回text2id信息 掩码信息 句子分段信息 标签y return input_ids, attention_mask, token_type_ids, labels # 测试数据 def dm01_test_dataset(): # 实例化数据源 通过训练文件 dataset_train = load_dataset('csv', data_files='./mydata1/train.csv', split="train") print('dataset_train--->', dataset_train) # 实例化数据迭代器 mydataloader mydataloader = torch.utils.data.DataLoader(dataset_train, batch_size=8, collate_fn=collate_fn1, shuffle=True, drop_last=True) print('mydataloader--->', len(mydataloader)) # 调整数据迭代器对象数据返回格式 for i, (input_ids, attention_mask, token_type_ids, labels) in enumerate(mydataloader): print(len(mydataloader)) print(input_ids.shape, attention_mask.shape, token_type_ids.shape, labels) # 打印句子text2id后的信息 print('input_ids', input_ids) # 打印句子attention掩码信息 print('attention_mask', attention_mask) # 打印句子分段信息 print('token_type_ids', token_type_ids) # 打印目标y信息 print('labels', labels) break
# 定义下游任务模型 class MyModel(torch.nn.Module): def __init__(self): super().__init__() # 定义全连接层 self.fc = torch.nn.Linear(768, 2) def forward(self, input_ids, attention_mask, token_type_ids): # 预训练模型不训练 只进行特征抽取 [8,500] ---> [8,768] with torch.no_grad(): out = my_model_pretrained(input_ids=input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids) # 下游任务模型训练 数据经过全连接层 [8,768] --> [8,2] out = self.fc(out.last_hidden_state[:, 0]) # 数据进行softmax归一化 分类概率值 out = out.softmax(dim=1) return out
# 模型训练 def train_model(): # 实例化下游任务模型my_model my_model = MyModel() # 实例化优化器my_optimizer my_optimizer = AdamW(my_model.parameters(), lr=5e-4) # 实例化损失函数my_criterion my_criterion = torch.nn.CrossEntropyLoss() # 实例化数据源对象my_dataset_train my_dataset_train = load_dataset('csv', data_files='../data/' 'zhujiang_garden/test.csv', split="train") print('dataset_train--->', my_dataset_train) # 不训练预训练模型 只让预训练模型计算数据特征 不需要计算梯度 for param in my_model_pretrained.parameters(): param.requires_grad_(False) # 设置训练参数 epochs = 3 # 设置模型为训练模型 my_model.train() # 外层for循环 控制轮数 for eporch_idx in range(epochs): # 每次轮次开始计算时间 starttime = (int)(time.time()) # 实例化数据迭代器对象my_dataloader my_dataloader = torch.utils.data.DataLoader(my_dataset_train, batch_size=8, collate_fn=collate_fn1, shuffle=True, drop_last=True) # 内层for循环 控制迭代次数 for i, (input_ids, attention_mask, token_type_ids, labels) in enumerate(my_dataloader, start=1): # 给模型喂数据 [8,500] --> [8,2] my_out = my_model(input_ids=input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids) # 计算损失 my_loss = my_criterion(my_out, labels) # 梯度清零 my_optimizer.zero_grad() # 反向传播 my_loss.backward() # 梯度更新 my_optimizer.step() # 每5次迭代 算一下准确率 if i % 5 == 0: out = my_out.argmax(dim=1) # [8,2] --> (8,) accuracy = (out == labels).sum().item() / len(labels) print('轮次:%d 迭代数:%d 损失:%.6f 准确率%.3f 时间%d' \ %(eporch_idx, i, my_loss.item(), accuracy, (int)(time.time())-starttime)) # 每个轮次保存模型 torch.save(my_model.state_dict(), './my_model_%d.bin' % (eporch_idx + 1))
# 模型测试 def evaluate_model(): # 实例化数据源对象my_dataset_test print('\n加载测试集') my_dataset_test = load_dataset('csv', data_files='../data/' 'zhujiang_garden/test.csv', split='train') print('my_dataset_test--->', my_dataset_test) # print(my_dataset_test[0:3]) # 实例化下游任务模型my_model path = './my_model_3.bin' my_model = MyModel() my_model.load_state_dict(torch.load(path)) print('my_model-->', my_model) # 设置下游任务模型为评估模式 my_model.eval() # 设置评估参数 correct = 0 total = 0 # 实例化化dataloader my_loader_test = torch.utils.data.DataLoader(my_dataset_test, batch_size=8, collate_fn=collate_fn1, shuffle=True, drop_last=True) # 给模型送数据 测试预测结果 for i, (input_ids, attention_mask, token_type_ids, labels) in enumerate(my_loader_test): # 预训练模型进行特征抽取 with torch.no_grad(): my_out = my_model(input_ids=input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids) # 贪心算法求预测结果 out = my_out.argmax(dim = 1) # 计算准确率 correct += (out == labels).sum().item() total += len(labels) # 每5次迭代打印一次准确率 if i % 5 == 0: print(correct / total, end=" ") print(my_tokenizer.decode(input_ids[0], skip_special_tokens=True), end=" ") print('预测值 真实值:', out[0].item(), labels[0].item())
大多数模型可以进行多种任务,基本上除了个别地方不一致,大多数是一致的,下面的代码只搞不一致的
def collate_fn2(data): sents = [i['text'] for i in data] # 文本数值化 data = my_tokenizer.batch_encode_plus(batch_text_or_text_pairs=sents, truncation=True, padding='max_length', max_length=32, return_tensors='pt', return_length=True) # input_ids 编码之后的数字 # attention_mask 是补零的位置是0,其他位置是1 input_ids = data['input_ids'] attention_mask = data['attention_mask'] token_type_ids = data['token_type_ids'] # 把第16个词固定替换为mask labels = input_ids[:, 16].reshape(-1).clone() # 取出数据8句话 在第16个位置clone出来 做标签 input_ids[:, 16] = my_tokenizer.get_vocab()[my_tokenizer.mask_token] labels = torch.LongTensor(labels) # tmpa = input_ids[:, 16] # print('tmpa--->', tmpa, tmpa.shape) # torch.Size([8] # print('labels-->', labels.shape, labels) # torch.Size([8] return input_ids, attention_mask, token_type_ids, labels
# 定义下游任务模型 class MyModel_add(torch.nn.Module): def __init__(self): super().__init__() # 定义全连接层 self.decoder = torch.nn.Linear(768, my_tokenizer.vocab_size, bias=False) # 设置全连接层偏置为零 self.decoder.bias = torch.nn.Parameter(torch.zeros(my_tokenizer.vocab_size)) def forward(self, input_ids, attention_mask, token_type_ids): # 预训练模型不进行训练 with torch.no_grad(): out = my_model_pretrained(input_ids=input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids) # 下游任务进行训练 形状[8,768] ---> [8, 21128] out = self.decoder(out.last_hidden_state[:, 16]) # 返回 return out
def train_model_add(): # 实例化数据源对象my_dataset_train dataset_train_tmp = load_dataset('csv', data_files='../data/' 'zhujiang_garden/train.csv', split="train") my_dataset_train = dataset_train_tmp.filter(lambda x: len(x['text']) > 32) print('my_dataset_train--->', my_dataset_train) # 实例化下游任务模型my_model my_model = MyModel_add() # 实例化优化器my_optimizer my_optimizer = AdamW(my_model.parameters(), lr=5e-4) # 实例化损失函数my_criterion my_criterion = torch.nn.CrossEntropyLoss() # 不训练预训练模型 只让预训练模型计算数据特征 不需要计算梯度 for param in my_model_pretrained.parameters(): param.requires_grad_(False) # 设置训练参数 epochs = 3 # 设置模型为训练模型 my_model.train() # 外层for循环 控制轮数 for eporch_idx in range(epochs): # 实例化数据迭代器对象my_dataloader my_dataloader = torch.utils.data.DataLoader(my_dataset_train, batch_size=8, collate_fn=collate_fn2, shuffle=True, drop_last=True) starttime = (int)(time.time()) # 内层for循环 控制迭代次数 for i, (input_ids, attention_mask, token_type_ids, labels) in enumerate(my_dataloader, start=1): # 给模型喂数据 [8,32] --> [8,21128] my_out = my_model(input_ids=input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids) # 计算损失 my_loss = my_criterion(my_out, labels) # 梯度清零 my_optimizer.zero_grad() # 反向传播 my_loss.backward() # 梯度更新 my_optimizer.step() # 每5次迭代 算一下准确率 if i % 20 == 0: out = my_out.argmax(dim=1) # [8,21128] --> (8,) accuracy = (out == labels).sum().item() / len(labels) print('轮次:%d 迭代数:%d 损失:%.6f 准确率%.3f 时间%d' \ %(eporch_idx, i, my_loss.item(), accuracy, (int)(time.time())-starttime)) # 每个轮次保存模型 torch.save(my_model.state_dict(), './my_model_mask_%d.bin' % (eporch_idx + 1))
# 模型测试:填空 def evaluate_model_add(): # 实例化数据源对象my_dataset_test print('\n加载测试集') my_dataset_tmp = load_dataset('csv', data_files='../data/' 'zhujiang_garden/test.csv', split='train') my_dataset_test = my_dataset_tmp.filter(lambda x: len(x['text']) > 32) print('my_dataset_test--->', my_dataset_test) # print(my_dataset_test[0:3]) # 实例化下游任务模型my_model path = './my_model_mask_3.bin' my_model = MyModel() my_model.load_state_dict(torch.load(path)) print('my_model-->', my_model) # 设置下游任务模型为评估模式 my_model.eval() # 设置评估参数 correct = 0 total = 0 # 实例化化dataloader my_loader_test = torch.utils.data.DataLoader(my_dataset_test, batch_size=8, collate_fn=collate_fn2, shuffle=True, drop_last=True) # 给模型送数据 测试预测结果 for i, (input_ids, attention_mask, token_type_ids, labels) in enumerate(my_loader_test): with torch.no_grad(): my_out = my_model(input_ids=input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids) out = my_out.argmax(dim=1) correct += (out == labels).sum().item() total += len(labels) if i % 25 == 0: print(i+1, my_tokenizer.decode(input_ids[0])) print('预测值:', my_tokenizer.decode(out[0]), '\t真实值:', my_tokenizer.decode(labels[0])) print(correct / total)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。