先安装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---> (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)