迁移学习--fasttext概述
迁移学习
1、fasttext概述
作为NLP工程领域常用的工具包, fasttext有两大作用:进行文本分类、训练词向量
正如它的名字, 在保持较高精度的情况下, 快速的进行训练和预测是fasttext的最大优势。fasttext工具包中内含的fasttext模型具有十分简单的网络结构。使用fasttext模型训练词向量时使用层次softmax结构, 来提升超多类别下的模型性能。由于fasttext模型过于简单无法捕捉词序特征, 因此会进行n-gram特征提取以弥补模型缺陷提升精度。
2、fasttext模型架构
FastText 模型架构和 Word2Vec 中的 CBOW 模型很类似, 不同之处在于, FastText 预测标签, 而 CBOW 模型预测中间词。
FastText的模型分为三层架构:
- 输入层: 是对文档embedding之后的向量, 包含N-gram特征
- 隐藏层: 是对输入数据的求和平均
- 输出层: 是文档对应的label
(一)、层次softmax
为了提高效率, 在fastText中计算分类标签概率的时候, 不再使用传统的softmax来进行多分类的计算, 而是使用哈夫曼树, 使用层次化的softmax来进行概率的计算。
(1)、哈夫曼树
当利用n 个结点试图构建一棵树时, 如果构建的这棵树的带权路径长度最小, 称这棵树为“最优二叉树”, 有时也叫“赫夫曼树”或者“哈夫曼树”。
权值越大的节点距离根节点也较近。
(2)、构建哈夫曼树
假设有n个权值, 则构造出的哈夫曼树有n个叶子节点. n个权值分别设为 w1、w2、…、wn, 则哈夫曼树的构造规则为:
- 步骤1: 将w1、w2、…, wn看成是有n 棵树的森林(每棵树仅有一个节点);
- 步骤2: 在森林中选出两个根节点的权值最小的树合并, 作为一颗新树的左、右子树, 且新树的根节点权值为其左、右子树根节点权值之和;
- 步骤3: 从森林中删除选取的两棵树, 并将新树加入森林;
- 步骤4: 重复2-3步骤, 直到森林只有一颗树为止, 该树就是所求的哈夫曼树。
(3)、哈夫曼树编码
哈夫曼编码一般规定哈夫曼树中的左分支为 0, 右分支为 1, 从根节点到每个叶节点所经过的分支对应的 0 和 1 组成的序列便为该节点对应字符的编码。这样的编码称为哈夫曼编码。
(二)、负采样
(1)、策略
减少计算softmax的token数量。
噪声词获取策略:指定拿到噪声词的数量K,每个噪声词token被取为噪声词的概率为
P = f ( t i ) 0.75 ∑ ( f ( t j ) 0.75 ) P=\frac{f(t_i)^{0.75}}{\sum(f(t_j)^{0.75})} P=∑(f(tj)0.75)f(ti)0.75
(2)、优势
- 提高训练速度, 选择了部分数据进行计算损失, 损失计算更加简单
- 改进效果, 增加部分负样本, 能够模拟真实场景下的噪声情况, 能够让模型的稳健性更强,泛化能力更强
3、fasttext文本分类
- 模型训练
# 进行文本分类任务(有监督)
'''
input:输入的文本
lr:学习率
epoch:训练轮次
wordNgram:n-gram特征
dim:词向量维度
loss:计算损失的方式,默认是softmax,'hs';还可以选择'ova',代表one vs all,改变意味着我们在统一语料下同时训练多个二分类模型
'''
fasttext.train_supervised()
# 进行文本分类任务(无监督)
fasttext.train_unsupervised()
- 预测
model.predict('需要预测的内容')# 返回结果:
# 元组中的第一项代表标签, 第二项代表对应的概率
- 测试
model.test('验证集/测试集')# 返回结果:
# 元组中的每项分别代表, 验证集样本数量, 精度以及召回率
- 保存模型
model.save_model('模型存储位置')
- 重加载模型
fasttext.load_model('模型存储位置')
4、训练词向量
(一)、训练词向量的过程:
- 获取数据
- 训练词向量
- 模型超参数设定
- 模型效果检验
- 模型的保存与重加载
(二)、API
- 获得指定词汇的词向量
model.get_word_vector(word='指定词汇')
- 查找邻近词
model.get_nearest_neighbors(word='指定词汇')
5、词向量迁移
大型语料库上已经进行训练完成的词向量模型,我们可以直接使用这些模型,或者对模型进行改造。
- 下载词向量模型压缩的bin.gz文件
- 解压bin.gz文件到bin文件
- 加载bin文件获取词向量
- 利用邻近词进行效果检验
# 使用gunzip进行解压, 获取cc.zh.300.bin文件
gunzip cc.zh.300.bin.gz
# 加载模型
model = fasttext.load_model("cc.zh.300.bin")
# 使用模型获得'音乐'这个名词的词向量
model.get_word_vector("海鸥")
# 以'音乐'为例, 返回的邻近词基本上与音乐都有关系, 如乐曲, 音乐会, 声乐等
model.get_nearest_neighbors("海鸥")
6、迁移学习
(一)、概述
(1)、预训练模型
一般情况下预训练模型都是大型模型,具备复杂的网络结构,众多的参数量,以及在足够大的数据集下进行训练而产生的模型.。
在NLP领域,预训练模型往往是语言模型。因为语言模型的训练是无监督的,可以获得大规模语料,同时语言模型又是许多典型NLP任务的基础,如机器翻译,文本生成,阅读理解等,
常见的预训练模型有BERT, GPT, roBERTa, transformer-XL等
(2)、微调
根据给定的预训练模型,改变它的部分参数或者为其新增部分输出结构后,通过在小部分数据集上训练,来使整个模型更好的适应特定任务
(3)、两种迁移方式
-
直接使用预训练模型,进行相同任务的处理,不需要调整参数或模型结构,这些模型开箱即用。但是这种情况一般只适用于普适任务, 如:fasttest工具包中预训练的词向量模型。另外,很多预训练模型开发者为了达到开箱即用的效果,将模型结构分各个部分保存为不同的预训练模型,提供对应的加载方法来完成特定目标。
-
更主流的迁移学习方式是发挥预训练模型特征抽象的能力,然后再通过微调的方式,通过训练更新小部分参数以此来适应不同的任务。这种迁移方式需要提供小部分的标注数据来进行监督学习。
(二)、NLP中常见的预训练模型
(1)、常见的训练模型
BERT、GPT、GPT-2、Transformer-XL、XLNet、XLM、RoBERTa、DistilBERT、ALBERT、T5、XLM-RoBERTa
(2)、BERT及其变体
- bert-base-uncased: 编码器具有12个隐层, 输出768维张量, 12个自注意力头, 共110M参数量, 在小写的英文文本上进行训练而得到.
- bert-large-uncased: 编码器具有24个隐层, 输出1024维张量, 16个自注意力头, 共340M参数量, 在小写的英文文本上进行训练而得到.
- bert-base-cased: 编码器具有12个隐层, 输出768维张量, 12个自注意力头, 共110M参数量, 在不区分大小写的英文文本上进行训练而得到.
- bert-large-cased: 编码器具有24个隐层, 输出1024维张量, 16个自注意力头, 共340M参数量, 在不区分大小写的英文文本上进行训练而得到.
- bert-base-multilingual-uncased: 编码器具有12个隐层, 输出768维张量, 12个自注意力头, 共110M参数量, 在小写的102种语言文本上进行训练而得到.
- bert-large-multilingual-uncased: 编码器具有24个隐层, 输出1024维张量, 16个自注意力头, 共340M参数量, 在小写的102种语言文本上进行训练而得到.
- bert-base-chinese: 编码器具有12个隐层, 输出768维张量, 12个自注意力头, 共110M参数量, 在简体和繁体中文文本上进行训练而得到.
(3)、GPT
openai-gpt: 编码器具有12个隐层, 输出768维张量, 12个自注意力头, 共110M参数量, 由OpenAI在英文语料上进行训练而得到
(4)、GPT-2及其变体
- gpt2: 编码器具有12个隐层, 输出768维张量, 12个自注意力头, 共117M参数量, 在OpenAI GPT-2英文语料上进行训练而得到.
- gpt2-xl: 编码器具有48个隐层, 输出1600维张量, 25个自注意力头, 共1558M参数量, 在大型的OpenAI GPT-2英文语料上进行训练而得到.
(5)、Transformer-XL
transfo-xl-wt103: 编码器具有18个隐层, 输出1024维张量, 16个自注意力头, 共257M参数量, 在wikitext-103英文语料进行训练而得到
(6)、XLNet及其变体
- xlnet-base-cased: 编码器具有12个隐层, 输出768维张量, 12个自注意力头, 共110M参数量, 在英文语料上进行训练而得到.
- xlnet-large-cased: 编码器具有24个隐层, 输出1024维张量, 16个自注意力头, 共240参数量, 在英文语料上进行训练而得到.
(6)、XLM
xlm-mlm-en-2048: 编码器具有12个隐层, 输出2048维张量, 16个自注意力头, 在英文文本上进行训练而得到
(7)、RoBERTa及其变体
- roberta-base: 编码器具有12个隐层, 输出768维张量, 12个自注意力头, 共125M参数量, 在英文文本上进行训练而得到.
- roberta-large: 编码器具有24个隐层, 输出1024维张量, 16个自注意力头, 共355M参数量, 在英文文本上进行训练而得到.
(8)、DistilBERT及其变体
- distilbert-base-uncased: 基于bert-base-uncased的蒸馏(压缩)模型, 编码器具有6个隐层, 输出768维张量, 12个自注意力头, 共66M参数量.
- distilbert-base-multilingual-cased: 基于bert-base-multilingual-uncased的蒸馏(压缩)模型, 编码器具有6个隐层, 输出768维张量, 12个自注意力头, 共66M参数量.
(9)、ALBERT
- albert-base-v1: 编码器具有12个隐层, 输出768维张量, 12个自注意力头, 共125M参数量, 在英文文本上进行训练而得到.
- albert-base-v2: 编码器具有12个隐层, 输出768维张量, 12个自注意力头, 共125M参数量, 在英文文本上进行训练而得到, 相比v1使用了更多的数据量, 花费更长的训练时间.
(10)、T5及其变体
- t5-small: 编码器具有6个隐层, 输出512维张量, 8个自注意力头, 共60M参数量, 在C4语料上进行训练而得到.
- t5-base: 编码器具有12个隐层, 输出768维张量, 12个自注意力头, 共220M参数量, 在C4语料上进行训练而得到.
- t5-large: 编码器具有24个隐层, 输出1024维张量, 16个自注意力头, 共770M参数量, 在C4语料上进行训练而得到.
(11)、XLM-RoBERTa及其变体
- xlm-roberta-base: 编码器具有12个隐层, 输出768维张量, 8个自注意力头, 共125M参数量, 在2.5TB的100种语言文本上进行训练而得到.
- xlm-roberta-large: 编码器具有24个隐层, 输出1027维张量, 16个自注意力头, 共355M参数量, 在2.5TB的100种语言文本上进行训练而得到.
(三)、Transformers库使用
(1)、Transformer库三层应用结构
- 管道(Pipline)方式:高度集成的极简使用方式,只需要几行代码即可实现一个NLP任务。
- 自动模型(AutoMode)方式:可载入并使用BERTology系列模型。
- 具体模型(SpecificModel)方式:在使用时,需要明确指定具体的模型,并按照每个BERTology系列模型中的特定参数进行调用,该方式相对复杂,但具有较高的灵活度。
(2)、编码解码函数
<一>、编码
tokenizer.encode()
tokenizer.tokenize()
tokenizer.encode_plus()
tokenizer.batch_encode_plus()
tokenizer.convert_tokens_to_ids()
<1>、tokenizer.encode()
# 1、tokenizer.encode()
# 进行分词和token转换,encode=tokenize+convert_tokens_to_ids
# 单个句子 or 句子列表:分开编码,分开padding,一个句子对应一个向量
# 句子对(pair)和句子元组(tuple):组合编码,统一padding,句子之间用 102 隔开# 单个句子,默认只返回 input_ids
out = tokenizer.encode(text=sents[0],truncation=True,padding='max_length',max_length=20,return_tensors='pt'
)
print(out)
print(out.shape)
# exit()# pair对中的两个句子,合并编码,默认只返回 input_ids
out = tokenizer.encode(text=(sents[0], sents[1]),truncation=True,padding='max_length',max_length=20,return_tensors='pt',
)
print(out)
print(out.shape)
<2>、tokenizer.tokenize()
# 2、tokenizer.tokenize()
# 只做分词
out = tokenizer.tokenize(text=sents[:2],truncation=True,padding='max_length',max_length=20,return_tensors='pt'
)
print(out)
<3>、tokenizer.encode_plus()
# 3、tokenizer.encode_plus()
# 在encode的基础之上生成input_ids、token_type_ids、attention_mask
# 单个句子编码,默认返回 input_ids、token_type_ids、attention_mask
out = tokenizer.encode_plus(text=sents[0],truncation=True,padding='max_length',max_length=20,return_tensors='pt'
)
print(out)
# exit()# pair对,合并编码
# todo 注意 token_type_ids
out = tokenizer.encode_plus(text=(sents[0], sents[1]),truncation=True,padding='max_length',max_length=20,return_tensors='pt'
)
print(out)
<4>、tokenizer.batch_encode_plus()
# 4、tokenizer.batch_encode_plus()
# 在encode_plus的基础之上,能够批量梳理文本
# 批量编码
out = tokenizer.batch_encode_plus(batch_text_or_text_pairs=sents,truncation=True,padding='max_length',max_length=20,return_tensors='pt'
)
print(out['input_ids'].shape)
# exit()# 批量编码 成对句子
out = tokenizer.batch_encode_plus(# pair内编码为一句话,统一padding,列表内分别编码,分别paddingbatch_text_or_text_pairs=[(sents[0], sents[1]), (sents[2], sents[3])],truncation=True,padding='max_length',max_length=20,return_tensors='pt'
)
print(out['input_ids'].shape)
<5>、tokenizer.convert_tokens_to_ids()
# 5、tokenizer.convert_tokens_to_ids()
# convert_tokens_to_ids,将token转化成id,在分词之后。
# convert_ids_to_tokens,将id转化成token,通常用于模型预测出结果,查看时使用。
out = [tokenizer.convert_tokens_to_ids(i) for i in sents[0]]
print(out)
<二>、解码
tokenizer.decode()
tokenizer.convert_ids_to_tokens()
<1>、tokenizer.decode()
res1 = tokenizer.decode(out['input_ids'][0])
print(res1)
<2>、tokenizer.convert_ids_to_tokens()
res2 = [tokenizer.convert_ids_to_tokens(i.item()) for i in out['input_ids'][0]]
print(res2)
(3)、管道方式完成多种NLP任务
<一>、文本分类任务
文本分类是指模型可以根据文本中的内容来进行分类。句子级别的分类。
# 导入工具包
import torch
from transformers import pipeline
import numpy as np# 实现情感分析
def text_classcify():# 1 定义模型model = pipeline(task='sentiment-analysis', model='./model/chinese_sentiment')# 2 直接预测res = model('我爱北京天安门,天安门上太阳升。')print(res)
<二>、特征提取任务
特征抽取任务只返回文本处理后的特征,属于预训练模型的范畴。特征抽取任务的输出结果需要和其他模型一起工作。
# 实现特征提取,拿到词向量,用于下游任务
def feature_extraction():# 1 创建piplinemodel = pipeline(task='feature-extraction', model='./model/bert-base-chinese')# 2 模型预测res = model('去码头整点薯条')print(res)print(type(res))print(np.array(res).shape)
# 输出结果
# output---> <class 'list'> (1, 9, 768)
# 7个字变成9个字原因: [CLS] 去 码 头 整 点 薯 条 [SEP]
- 不带任务头输出:特征抽取任务属于不带任务头输出,本bert-base-chinese模型的9个字,每个字的特征维度是768
- 带头任务头输出:其他有指定任务类型的比如文本分类,完型填空属于带头任务输出,会根据具体任务类型不同输出不同的结果
<三>、完形填空任务
完型填空任务又被叫做“遮蔽语言建模任务”,它属于BERT模型训练过程中的子任务。分类任务。
# 完形填空任务
def fill_mask():model = pipeline(task='fill-mask', model='./model/chinese-bert-wwm')res = model('我想明天去[MASK]家吃饭。')print(res)# 输出结果
# output--->
# [{'score': 0.34331339597702026, 'token': 1961, 'token_str': '她', 'sequence': '我 想 明 天 去 她 家 吃 饭.'},
# {'score': 0.2533259987831116, 'token': 872, 'token_str': '你', 'sequence': '我 想 明 天 去 你 家 吃 饭.'},
# {'score': 0.1874391734600067, 'token': 800, 'token_str': '他', 'sequence': '我 想 明 天 去 他 家 吃 饭.'},
# {'score': 0.1273055076599121, 'token': 2769, 'token_str': '我', 'sequence': '我 想 明 天 去 我 家 吃 饭.'},
# {'score': 0.02162978984415531, 'token': 2644, 'token_str': '您', 'sequence': '我 想 明 天 去 您 家 吃 饭.'}]
<四>、阅读理解任务
阅读理解任务又称为“抽取式问答任务”,即输入一段文本和一个问题,让模型输出结果。
# 阅读理解
def qa():context = '我叫张三,我是一个程序员,我的喜好是打篮球。'questions = ['我是谁?', '我是做什么的?', '我的爱好是什么?']model = pipeline(task='question-answering', model='./model/chinese_pretrain_mrc_roberta_wwm_ext_large')res = model(context=context, question=questions)print(res)# 输出结果
'''
[{'score': 1.2071758523357623e-12, 'start': 2, 'end': 4, 'answer': '张三'},{'score': 2.60890374192968e-06, 'start': 9, 'end': 12, 'answer': '程序员'},{'score': 4.1686924134864967e-08, 'start': 18, 'end': 21, 'answer': '打篮球'}]
'''
<五>、文本摘要任务
摘要生成任务的输入一一段文本,输出是一段概况、简单的文字。
# 5 文本摘要
def summary():model = pipeline(task='summarization', model='./model/distilbart-cnn-12-6')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.'res = model(text)print(res)# 输出结果
output---> [{'summary_text': ' BERT is a transformers model pretrained on a large corpus of English data in a self-supervised fashion . It was pretrained with two objectives: Masked language modeling (MLM) and next sentence prediction (NSP) This allows the model to learn a bidirectional representation of the sentence .'}]
<六>、NER任务
**实体词识别(NER)**任务是NLP中的基础任务。它用于识别文本中的人名(PER)、地名(LOC)、组织(ORG)以及其他实体(MISC)等。例如:(王 B-PER) (小 I-PER) (明 I-PER) (在 O) (北 B-LOC) (京 I-LOC)。其中O表示一个非实体,B表示一个实体的开始,I表示一个实体块的内部。
实体词识别本质上是一个分类任务(又叫序列标注任务:token级别的分类任务),实体词识别是句法分析的基础,而句法分析优势NLP任务的核心。
- ner(命名实体识别、实体抽取):两阶段 分别是 边界识别 and 实体分类
- 常见的命名实体:人名、地名、机构名、时间、日期、货币、百分比
- 句子里边的关键信息,一般由命名实体承载,场景:意图识别、关键词抽取、知识图谱
- 信息抽取:实体抽取、关系抽取、事件抽取(属性抽取)
def ner():model = pipeline(task='ner', model='./model/roberta-base-finetuned-cluener2020-chinese')res = model('特朗普第二次担任了美国总统')print(res)
(4)、自动模型方式完成多种NLP任务
- 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 text_classify():# chinese_sentiment 是一个5分类# 1 加载切词器:分词+word2id(BPE)my_tokenizer = AutoTokenizer.from_pretrained('./model/chinese_sentiment')# 2 加载模型 # SequenceClassification 句子级别的分类# TokenClassification token级别的分类my_model = AutoModelForSequenceClassification.from_pretrained('./model/chinese_sentiment')# 3 准备数据样本句子# message = '人生该如何起头'# message = '我的人生很灰暗'# message = '我的人生很辉煌'message = '我不同意你的看法'# message = '我对你的看法表示中立'# message = '我很同意你的看法'# message = '你的看法太棒了,我非常同意'# message = ['艾海两只黄鹂鸣翠柳', '一行白鹭上青天']# 4 对句子进行编码 encodeoutput1 = my_tokenizer.encode(message,return_tensors='pt', # 可选 pt(torch tensor) tf(tensorflow) None(list)truncation=True, # 超过 max-len 就进行截断padding='max_length', # True 根据最长的句子进行补齐;’max_length‘ 根据设置的max_length进行补齐max_length=20 # 设置句子的最大长度)print(output1)print(output1.shape)# exit()# 不设置 pt,返回 listoutput2 = my_tokenizer.encode(message,# return_tensors='pt',truncation=True,padding=True,max_length=20)print(output2)# 5 使用模型进行预测my_model.eval() # 开启模型预测验证result = my_model(output1)print(result)result2 = my_model(output1, return_dict=False)print(result2)# 结果分析topv, topi = torch.topk(result.logits, k=1, dim=-1)print('star', topi.item())
<二>、特征提取任务
# 特征提取 拿到词向量 句向量
# todo token_type_ids attention_mask
def feature_extraction():# 1 加载分词器my_tokenizer = AutoTokenizer.from_pretrained('./model/bert-base-chinese')print(my_tokenizer)# 2 加载模型my_model = AutoModel.from_pretrained('./model/bert-base-chinese')# 3 准备样本message = ['你是谁', '人生该如何起头']# 4 样本编码output = my_tokenizer.batch_encode_plus(message, # message 句子列表,有多句话,所以用的 batch_encode_plusreturn_tensors='pt',truncation=True,padding='max_length', # 不够就补0max_length=20,)# output 一般有3个kv对,input_ids 就是token具体的编码结果 前后加 [CLS] [SEP]# 'input_ids': tensor([# [101, 872, 3221, 6443, 102, 0, 0, 0, 0, 0, 0, 0,# 0, 0, 0, 0, 0, 0, 0, 0# ],# [101, 782, 4495, 6421, 1963, 862, 6629, 1928, 102, 0, 0, 0,# 0, 0, 0, 0, 0, 0, 0, 0# ]# attention_mask 标识 padding 的位置 为 0,正常的有意义的 token 标识为 1# 'attention_mask': tensor([# [1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],# [1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]# ])# token_type_ids 在一条样本内部,第一个句子标识为 0,第二个句子表示为 1# 'token_type_ids': tensor([# [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], # 因为此处只有一个句子,所以只有0# [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]# ]),print(output)# 5 将数据送入到模型my_model.eval()res = my_model(**output)print(res)print(res.last_hidden_state.shape) # 词向量 ner token级别的分类print(res.pooler_output.shape) # 句向量 文本分类
<三>、完形填空任务
# 完形填空
def fill_mask():# 1 加载分词器my_tokenizer = AutoTokenizer.from_pretrained('./model/chinese-bert-wwm')print(my_tokenizer)# 2 加载模型my_model = AutoModelForMaskedLM.from_pretrained('./model/chinese-bert-wwm')# 3 准备样本message = '我想明天去[MASK]家吃饭'# 4 对样本进行编码output = my_tokenizer.encode_plus(message, return_tensors='pt')print(output)# 5 将数据送入模型my_model.eval()res = my_model(**output).logits # res.shape=(1,11,vocab_size)print(res.shape)# res[0][6]:[mask]对应的输出向量,长度vocab_size# torch.argmax(res[0][6]) 拿到最大值所在下表索引index = torch.argmax(res[0][6]).item()print(index)# 6 拿到 mask 对应的 tokentoken = my_tokenizer.convert_ids_to_tokens(index)print(token)
<四>、阅读理解任务
def qa():# 1 加载分词器my_tokenizer = AutoTokenizer.from_pretrained('./model/chinese_pretrain_mrc_roberta_wwm_ext_large')# 2 加载模型my_model = AutoModelForQuestionAnswering.from_pretrained('./model/chinese_pretrain_mrc_roberta_wwm_ext_large')# 3 准备语料context = '我叫张三 我是一个程序员 我的喜好是打篮球'questions = ['我是谁?', '我是做什么的?', '我的爱好是什么?']# 4 将数据送入模型my_model.eval()for question in questions:print(question)# pair对 进行统一合并编码inputs = my_tokenizer.encode_plus(question, context, return_tensors='pt')outputs = my_model(**inputs)print(outputs)# 拿到输出的开始的logit,结束的logit,通过argmax拿到indexstart_index = torch.argmax(outputs.start_logits, dim=-1).item()end_index = torch.argmax(outputs.end_logits, dim=-1).item()# 来到inputs中做切片, a 是id序列a = inputs['input_ids'][0][start_index: end_index + 1]# 对 a 进行解码res = my_tokenizer.convert_ids_to_tokens(a)print(res)
<五>、文本摘要任务
def summary():# 1 加载分词器my_tokenizer = AutoTokenizer.from_pretrained('./model/distilbart-cnn-12-6')# 2 加载模型my_model = AutoModelForSeq2SeqLM.from_pretrained('./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."text = 'I have a dream.'# 4 把文本进行张量表示inputs = my_tokenizer.encode_plus(text, return_tensors='pt')# 5 将数据送入模型,进行解码my_model.eval()outputs = my_model.generate(inputs['input_ids'])print(outputs)# skip_special_tokens=True 跳过特殊符号 BERT的特殊符号 CLS SEP PAD UNK MASK# clean_up_tokenization_spaces=False 是否清理空字符res = my_tokenizer.decode(outputs[0], skip_special_tokens=True, clean_up_tokenization_spaces=True)print(res)
<六>、NER任务
命名实体识别、实体抽取
def ner():# 1 加载分词器、模型、配置configmy_tokenizer = AutoTokenizer.from_pretrained('./model/roberta-base-finetuned-cluener2020-chinese')my_model = AutoModelForTokenClassification.from_pretrained('./model/roberta-base-finetuned-cluener2020-chinese')my_config = AutoConfig.from_pretrained('./model/roberta-base-finetuned-cluener2020-chinese')# 2 准备数据,并进行张量化text = '我爱北京天安门,天安门上太阳升'inputs = my_tokenizer.encode_plus(text, return_tensors='pt')print('inputs: ', inputs)# 3 将tensor送入到模型,拿到 id-token,因为 inputs 已经添加了特殊符号my_model.eval()# logits 是模型返回的主要张量,用来做token分类的outputs = my_model(**inputs).logits# 因为原来的 inputs 已经添加了特殊符号,而特殊符号也需要标签labeltokens = my_tokenizer.convert_ids_to_tokens(inputs['input_ids'][0])print('tokens:', tokens)# 4 预测结果# 初始化返回结果的列表output_listoutput_list = []# 循环遍历 具体的token,及其对应的标签tensor,这个tensor未经过argmax的# logit 是一个一维的tensorfor token, logit in zip(tokens, outputs[0]):# 跳过特殊符号if token in my_tokenizer.all_special_tokens:continueindex = torch.argmax(logit, dim=-1).item()# 根据id拿到具体的标签labellabel = my_config.id2label[index]# 封装 token及其标签 进 output_listoutput_list.append((token, label))print(output_list)
(四)、微调方式进行迁移学习
(1)、迁移学习的两种类型
-
直接加载预训练模型进行输入文本的特征表示, 后接自定义网络进行微调输出结果
-
使用指定任务类型的微调脚本微调预训练模型, 后接带有输出头的预定义网络输出结果
(2)、中文分类
<一>、导包
import torch
import torch.nn as nn
from torch.utils.data import Dataset, DataLoader
from datasets import load_dataset # 用来加载数据
from transformers import BertModel, BertTokenizer
from transformers import AdamW
import time
import shutup
<二>、加载分词器和模型
shutup.please() # 去掉无意义的警告# 定义设备
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')# 加载分词器
my_tokenizer = BertTokenizer.from_pretrained('./model/bert-base-chinese')# 加载模型, my_model对应的下游任务模型
bert_model = BertModel.from_pretrained('./model/bert-base-chinese')
<三>、加载数据
# 3 使用 load_dataset 加载数据
def file2dataset():'''load_dataset 3种情况情况1 data_files如果传入的是一个字典(不同的类型对应的不同的数据文件,这个类型就是split)情况2 如果直接传入数据文件路径,直接写死 split='train' 没有意义了情况3 不使用data_files,使用data_dir,那么直接返回一个 dataset dict,根据 key 去检索数据文件 dataset['train]'''my_files = {'train': './data/train.csv','test': './data/test.csv','valid': './data/validation.csv',}# 加载训练集, load_dataset 三个参数:数据文件格式、文件路径、类型train_dataset = load_dataset('csv', data_files=my_files, split='train')print(train_dataset[0])# 测试集test_dataset = load_dataset('csv', data_files=my_files, split='test')# 验证集valid_dataset = load_dataset('csv', data_files=my_files, split='valid')return train_dataset, test_dataset, valid_dataset
<四>、对同一批次的数据做标准化
# 4 自定义批处理函数, 对一个批次的数据做标准化
def collate_fn(data):# data=[{text:xxx, label:1}, {},{},,,]# 主要作用:对句子长度进行规范化,规范到统一的标准长度sents = [i['text'] for i in data]labels = [i['label'] for i in data]# print(sents)# print(labels)inputs = my_tokenizer.batch_encode_plus(sents,# 是否截断truncation=True,# paddingpadding='max_length',max_length=500,# 返回tensor,默认列表return_tensors='pt',# 返回长度return_length=True)input_ids = inputs['input_ids']token_type_ids = inputs['token_type_ids']attention_mask = inputs['attention_mask']labels = torch.LongTensor(labels)return input_ids, token_type_ids, attention_mask, labels
<五>、获得dataloader
# 5 测试数据集,获得dataloader
def get_dataloader():train_dataset = load_dataset('csv', data_files='./data/train.csv', split='train')my_dataloader = DataLoader(train_dataset,batch_size=8, # 一个 batch 有 8 条样本shuffle=True, # 将数据打乱collate_fn=collate_fn, # 批处理函数,统一句子长度drop_last=True, # 删除最后一个不足一个 batch 的数据)# 通过 next(iter()) 方法拿到一个batch的数据input_ids, token_type_ids, attention_mask, labels = next(iter(my_dataloader))# print(input_ids)# print(token_type_ids)# print(labels)return my_dataloader
<六>、自定义下游任务模型
# 6 自定义下游任务模型
class MyModel(nn.Module):def __init__(self):super().__init__()# 适配下游任务,一个线性层self.linear = nn.Linear(768, 2)def forward(self, input_ids, token_type_ids, attention_mask): # 参数均为编码的结果# 不对预训练模型的参数更新with torch.no_grad():# 输出两个值,词向量和句向量bert_output = bert_model(input_ids=input_ids,attention_mask=attention_mask,token_type_ids=token_type_ids)output = self.linear(bert_output.pooler_output) # 可以不做 softmax,后续有嵌套return output
<七>、模型训练
# 7 模型训练
def train_model():# 1 准备物料: 模型、损失函数、优化器、数据my_model = MyModel().to(device)# 把bert参数固定住for param in bert_model.parameters():param.requires_grad_(False)# CrossEntropyLoss 本身自带 softmaxmy_loss_fn = nn.CrossEntropyLoss(reduction='mean')my_adamw = AdamW(my_model.parameters(), lr=3e-4)# 拿到数据my_dataloader = get_dataloader()# 2 开始训练my_model.train()epochs = 3for epoch_idx in range(epochs):# 记录开始时间start_time = time.time()for i, (input_ids, token_type_ids, attention_mask, labels) in enumerate(my_dataloader, start=1):input_ids = input_ids.to(device)token_type_ids = token_type_ids.to(device)attention_mask = attention_mask.to(device)labels = labels.to(device)# 训练的4步:前向传播、计算损失、损失反向传播、参数更新、梯度清零output = my_model(input_ids, token_type_ids, attention_mask)loss = my_loss_fn(output, labels)loss.backward()my_adamw.step()my_adamw.zero_grad()# 每隔几步 打印日志if i % 2 == 0:# 根据 argmax 拿到预测值 idxtem = torch.argmax(output, dim=-1)# 计算准确率,预测正确的 / 总的数量acc = (tem == labels).sum().item() / len(labels)use_time = time.time() - start_timeprint('当前训练轮次%d,迭代步数%d,损失%.2f,准确率%.2f,时间%d' % (epoch_idx + 1,i,loss.item(),acc,use_time))# 每隔epoch保存一次模型torch.save(my_model.state_dict(), './save/classify_%d.bin' % (epoch_idx + 1))
<八>、模型评估
# 9 模型评估
def ceshi_model():# 1 准备物料 必要 模型 数据 也可以有损失test_dataset = load_dataset('csv', data_files='./data/test.csv', split='train')test_dataloader = DataLoader(test_dataset,batch_size=8,shuffle=True,collate_fn=collate_fn,drop_last=True,)my_model = MyModel()my_model.load_state_dict(torch.load('./save/classify_3.bin'))# 2 开始测试correct = 0 # 预测正确的样本数量total = 0 # 总的样本数量# 开启模型验证模式my_model.eval()# 只需要一个epoch即可for i, (input_ids, token_type_ids, attention_mask, labels) in enumerate(test_dataloader, start=1):# 数据放到 with torch.no_grad() 执行with torch.no_grad():output = my_model(input_ids, token_type_ids, attention_mask)temp = torch.argmax(output, dim=-1)# 把当前batch的预测正确的、总的数量分别加到correct、totalcorrect += (temp == labels).sum().item()total += len(labels)# 打印日志if i % 2 == 0:print('平均acc:', correct / total)text = my_tokenizer.decode(input_ids[0], skip_special_tokens=True)print('当前batch第一个原始文本:', text)print('模型的预测结果', temp[0])print('真是结果是:', labels[0])print('模型总的acc:', correct / total)
相关文章:

迁移学习--fasttext概述
迁移学习 1、fasttext概述 作为NLP工程领域常用的工具包, fasttext有两大作用:进行文本分类、训练词向量 正如它的名字, 在保持较高精度的情况下, 快速的进行训练和预测是fasttext的最大优势。fasttext工具包中内含的fasttext模型具有十分简单的网络结构。使用fa…...

【数字信号处理】数字信号处理试题及答案,离散序列,Z变换,傅里叶变换
关注作者了解更多 我的其他CSDN专栏 过程控制系统 工程测试技术 虚拟仪器技术 可编程控制器 工业现场总线 数字图像处理 智能控制 传感器技术 嵌入式系统 复变函数与积分变换 单片机原理 线性代数 大学物理 热工与工程流体力学 数字信号处理 光电融合集成电路…...

CNN、RNN、LSTM和Transformer之间的区别和联系
文章目录 CNN、RNN、LSTM和Transformer之间的区别和联系前言CNN(卷积神经网络)RNN(循环神经网络)LSTM(长短期记忆网络)Transformer四者之间的联系与区别Yolo算法简介Yolo和CNN的关系YOLO各版本 CNN、RNN、L…...

springboot448教学辅助系统(论文+源码)_kaic
摘 要 互联网发展至今,无论是其理论还是技术都已经成熟,而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播,搭配信息管理工具可以很好地为人们提供服务。针对信息管理混乱,出错率高,信息安全性差&#x…...

用QT制作的倒计时软件
一、pro代码 RC_ICONS countdown.ico 二、mainwindow.cpp代码 #include "mainwindow.h" #include "ui_mainwindow.h"#include <QDateTime> #include <QMessageBox> #include <QSettings>MainWindow::MainWindow(QWidget *parent): QM…...

基于 mzt-biz-log 实现接口调用日志记录
🎯导读:mzt-biz-log 是一个用于记录操作日志的通用组件,旨在追踪系统中“谁”在“何时”对“何事”执行了“何种操作”。该组件通过简单的注解配置,如 LogRecord,即可实现接口调用的日志记录,支持成功与失败…...

docker容器的安装以及用法
1、了解docker 1.1、docker是什么 Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apache2.0 协议开源。 Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现…...

Java中的Consumer接口应该如何使用(通俗易懂图解)
应用场景: 第一次程序员A写好了个基础的遍历方法: public class Demo1 {public static void main(String[] args) {//假设main方法为程序员B写的,此时需要去调用A写好的一个遍历方法//1.如果此时B突然发现想将字符串以小写的形式打印出来,则…...

D102【python 接口自动化学习】- pytest进阶之fixture用法
day102 pytest的usefixtures方法 学习日期:20241219 学习目标:pytest基础用法 -- pytest的usefixtures方法 学习笔记: fixture调用方法 实际应用 总结 pytest.mark.usefixtures(func),pytest的usefixtures方法,无…...

从零玩转CanMV-K230(4)-小核Linux驱动开发参考
前言 K230 芯片是一款基于 RISC-V 架构的端侧 AIoT 芯片,包含两个核心: CPU 1: RISC-V 处理器,1.6GHz,32KB I-cache, 32KB D-cache, 256KB L2 Cache,128bit RVV 1.0扩展 CPU 0: RISC-V 处理器,0.8GHz&am…...

上汽大通汽车CAN数据解析开发服务及技术商用领域详细解析
上汽大通G90是一款集豪华、科技与舒适于一身的中大型MPV,号称“国产埃尔法”。在国内市场,作为“卷王”的G90主要面向中大型MPV市场,满足家庭出行、商务接待和客运租赁等多元化场景需求,在国内市场上取得了不错的销售成绩。在海外…...

基于SCUI的后台管理系统
一、SCUI Admin 官方地址:https://python-abc.xyz/scui-doc/ 高性能中后台前端解决方案,基于 Vue3、elementPlus 持续性的提供独家组件和丰富的业务模板帮助你快速搭建企业级中后台前端任务。 预览地址:https://python-abc.xyz/scui-doc/de…...

使用频谱分析仪:RBW,Res BW,分辨率带宽;Sweep,扫描;noise floor,底噪,如何降低底噪?
RBW与Sweep的定义及其特性阐述: Res BW,即Resolution Bandwidth(分辨率带宽),是衡量仪器分辨信号细节能力的重要参数。当RBW的数值越小,意味着像素点的尺寸更为精细,从而能够观察到更为细微的信…...

项目管理工具Maven(一)
Maven的概念 什么是Maven 翻译为“专家”,“内行”Maven是跨平台的项目管理工具。主要服务于基于Java平台的项目构建,依赖管理和项目信息管理。什么是理想的项目构建? 高度自动化,跨平台,可重用的组件,标准…...

阿里云ESC服务器一次性全部迁移到另一个ESC
摘要: 在云计算时代,服务器迁移是企业优化资源配置、提升业务灵活性的常见需求。本文将详细介绍如何将阿里云ECS(Elastic Compute Service)服务器一次性迁移到另一个ECS实例。整个迁移过程分为四个关键步骤: 创建自定义…...

搭建分布式Kafka集群
title: 搭建分布式Kafka集群 date: 2024-12-1 14:00:00 categories: - 服务器 tags: - Kafka - 大数据搭建分布式Kafka集群 在主节点上安装Kafka; Kafka使用Zookeeper服务器来存储元数据信息 本次实验环境:Centos 7-2009、Hadoop-3.1.4、JDK 8、Zookeep…...

【后端面试总结】深入解析进程和线程的区别
在操作系统和并发编程中,进程和线程是两个核心概念。它们各自承担着不同的职责,并在多任务处理中发挥着关键作用。本文将从定义、特性、应用场景以及优缺点等多个方面对进程和线程进行详细对比,帮助读者深入理解它们之间的区别。 一、进程和…...

java版电子招投标采购|投标|评标|竞标|邀标|评审招投标系统源码
招投标管理系统是一款适用于招标代理、政府采购、企业采购和工程交易等领域的企业级应用平台。该平台以项目为主线,从项目立项到项目归档,实现了全流程的高效沟通和协作。通过该平台,用户可以实时共享项目数据信息,实现规范化管理…...

SSM 赋能 Vue 助力:新锐台球厅管理系统的设计与实现的辉煌之路
2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统,它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等,非常适…...

C++ 并发专题 - C++线程同步的几种方法
一:概述 线程同步是多线程编程中的一个重要概念,它用于控制多个线程之间对共享资源的访问,避免竞态条件(race condition)和数据不一致的问题。线程同步确保在多线程环境中,多个线程访问共享数据时能够按照某…...

使用Python脚本进行编写批量根据源IP进行查询的语句用于态势感知攻击行为的搜索
使用Python脚本进行编写批量根据源IP进行查询的语句 以下根据ip-list集里面的IP地址(可以自行扩充),然后采用srcaddress "{ip}" or 的形式进行打印并存储在路径为:桌面的IOC结果.txt --------------------------代码如…...

Python中的zip/unzip:像拉拉链一样组合数据的艺术
今天让我们一起探讨Python中一个优雅而强大的内置功能: zip 和 unzip 。听名字就知道,它就像我们衣服上的拉链一样,能把两边的数据完美地咬合在一起。 从一个有趣的例子开始 想象你正在开发一个班级管理系统。每个学生都有名字、成绩和评语…...

数电课设·简易数字钟(Quartus Ⅱ)
忽如一夜春风来,千树万树梨花开 —— 《白雪歌诵武判官归京》 岑参 【唐】 目录 简易数字钟 要点剖析: 逐步分析: 端口说明: 代码展示: 分部解释: 代码编译结果: 提醒 : …...

大模型中RAG模型的检索过程是如何实现的?(附最佳实践资料)
RAG模型的检索过程主要涉及以下几个步骤: 向量化(Embedding):首先,需要将外部知识库中的文档转换为计算机能够理解的向量形式。这一步骤通常使用预训练的嵌入模型(如BERT、GPT等)将文本转换为高…...

python:用 sklearn.metrics 评价 K-Means 聚类模型
sklearn 的 metrics 模块提供的聚类模型评价指标如下: ARI 评价法(兰德系数): adjusted_rand_score AMI 评价法(相互信息): adjusted_mutual_info_score V-measure 评分 : completeness_score FMI 评价法 : fowlkes_m…...

Spring依赖注入不同类型的数据
目录 前言 回顾 注入集合 List与set集合 Map集合 前言 前面学习依赖注入时注入的都是对象,这里记录注入的值为集合的情况 回顾 在注入的时候,如果要注入的属性的值为字符串或基本数据类型,用value即可;如果要注入一个对象的…...

Linux大杂烩!!!
Linux 命令大全 https://www.runoob.com/linux/linux-command-manual.html Linux下打印ASCII字符 ASCII码对照表及转换器 [rootuntifa_80 ~]# printf "\x30\n" 0 [rootuntifa_80 ~]# echo -e "\u0030" 0tar、gzip 打包解压命令 参考文章:ta…...

12.19问答解析
概述 某中小型企业有四个部门,分别是市场部、行政部、研发部和工程部,请合理规划IP地址和VLAN,实现企业内部能够互联互通,同时要求市场部、行政部和工程部能够访问外网环境(要求使用OSPF协议),研发部不能访问外网环境…...

C语言——实现杨氏矩阵
什么是杨氏矩阵? 概念: 有一个数字矩阵,矩阵的每行从左到右是递增的,矩阵从上到下是递增的 eg: 1 2 3 4 5 6 7 8 9 题目: 请编写程序在这样的矩阵中查找某个数字是否存在。 要求:时间复…...

授权模型PAM
PAM(Privileged Access Management)是一种授权模型,用于管理和控制特权用户的访问权限。PAM的目标是确保特权用户只能在需要时获得所需的特权,并且他们的活动得到适当的监控和审计。 PAM的核心思想是将特权访问权限视为一种受限的…...