0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

从预训练语言模型看MLM预测任务

深度学习自然语言处理 来源:老刘说NLP 作者:老刘说NLP 2022-11-14 14:56 次阅读

Prompt Learning是当前NLP的一个重要话题,已经有许多文章进行论述。

从本质上来说,Prompt Learning 可以理解为一种下游任务的重定义方法,将几乎所有的下游任务均统一为预训练语言模型任务,从而避免了预训练模型和下游任务之间存在的 gap。

如此一来,几乎所有的下游 NLP 任务均可以使用,不需要训练数据,在小样本数据集的基础上也可以取得超越 Fine-Tuning 的效果,使得所有任务在使用方法上变得更加一致,而局限于字面意义上的理解还远远不够,我们可以通过一种简单、明了的方式进行讲述。

为了解决这一问题,本文主要从预训练语言模型看MLM预测任务、引入prompt_template的MLM预测任务、引入verblize类别映射的Prompt-MLM预测、基于zero-shot的prompt情感分类实践以及基于zero-shot的promptNER实体识别实践五个方面,进行代码介绍,供大家一起思考。

一、从预训练语言模型看MLM预测任务

MLM和NSP两个任务是目前BERT等预训练语言模型预训任务,其中MLM要求指定周围词来预测中心词,其模型机构十分简单,如下所示:

importtorch.nnasnn
fromtransformersimportBertModel,BertForMaskedLM
classBert_Model(nn.Module):
def__init__(self,bert_path,config_file):
super(Bert_Model,self).__init__()
self.bert=BertForMaskedLM.from_pretrained(bert_path,config=config_file)#加载预训练模型权重
defforward(self,input_ids,attention_mask,token_type_ids):
outputs=self.bert(input_ids,attention_mask,token_type_ids)#maskedLM输出的是mask的值对应的ids的概率,输出会是词表大小,里面是概率
logit=outputs[0]#池化后的输出[bs,config.hidden_size]
returnlogit

下面一段代码,简单的使用了hugging face中的bert-base-uncased进行空缺词预测,先可以得到预训练模型对指定[MASK]位置上概率最大的词语【词语来自于预训练语言模型的词表】。

例如给定句子"natural language processing is a [MASK] technology.",要求预测出其中的[MASK]的词:

>>>fromtransformersimportpipeline
>>>unmasker=pipeline('fill-mask',model='bert-base-uncased')
>>>unmasker("naturallanguageprocessingisa[MASK]technology.")
[{'score':0.18927036225795746,'token':3274,'token_str':'computer','sequence':'naturallanguageprocessingisacomputertechnology.'},
{'score':0.14354903995990753,'token':4807,'token_str':'communication','sequence':'naturallanguageprocessingisacommunicationtechnology.'},
{'score':0.09429361671209335,'token':2047,'token_str':'new','sequence':'naturallanguageprocessingisanewtechnology.'},
{'score':0.05184786394238472,'token':2653,'token_str':'language','sequence':'naturallanguageprocessingisalanguagetechnology.'},
{'score':0.04084266722202301,'token':15078,'token_str':'computational','sequence':'naturallanguageprocessingisacomputationaltechnology.'}]

从结果中,可以显然的看到,[MASK]按照概率从大到小排序后得到的结果是,computer、communication、new、language以及computational,这直接反馈出了预训练语言模型能够有效刻画出NLP是一种计算机、交流以及语言技术。

二、引入prompt_template的MLM预测任务

因此,既然语言模型中的MLM预测结果能够较好地预测出指定的结果,那么其就必定包含了很重要的上下文知识,即上下文特征,那么,我们是否可以进一步地让它来执行文本分类任务?即使用[MASK]的预测方式来预测相应分类类别的词,然后再将词做下一步与具体类别的预测?

实际上,这种思想就是prompt的思想,将下游任务对齐为预训练语言模型的预训练任务,如NPS和MLM,至于怎么对齐,其中引入两个概念,一个是prompt_template,即提示模版,以告诉模型要生成与任务相关的词语。因此,将任务原文text和prompt_template进行拼接,就可以构造与预训练语言模型相同的预训练任务。

例如,

>>>fromtransformersimportpipeline
>>>unmasker=pipeline('fill-mask',model='bert-base-uncased')
>>>text="Ireallylikethefilmalot."
>>>prompt_template="Becauseitwas[MASK]."
>>>pred1=unmasker(text+prompt_template)
>>>pred1
[
{'score':0.14730973541736603,'token':2307,'token_str':'great','sequence':'ireallylikethefilmalot.becauseitwasgreat.'},
{'score':0.10884211212396622,'token':6429,'token_str':'amazing','sequence':'ireallylikethefilmalot.becauseitwasamazing.'},
{'score':0.09781625121831894,'token':2204,'token_str':'good','sequence':'ireallylikethefilmalot.becauseitwasgood.'},
{'score':0.04627735912799835,'token':4569,'token_str':'fun','sequence':'ireallylikethefilmalot.becauseitwasfun.'},
{'score':0.043138038367033005,'token':10392,'token_str':'fantastic','sequence':'ireallylikethefilmalot.becauseitwasfantastic.'}]

>>>text="thismoviemakesmeverydisgusting."
>>>prompt_template="Becauseitwas[MASK]."
>>>pred2=unmasker(text+prompt_template)
>>>pred2
[
{'score':0.05464331805706024,'token':9643,'token_str':'awful','sequence':'thismoviemakesmeverydisgusting.becauseitwasawful.'},
{'score':0.050322480499744415,'token':2204,'token_str':'good','sequence':'thismoviemakesmeverydisgusting.becauseitwasgood.'},
{'score':0.04008950665593147,'token':9202,'token_str':'horrible','sequence':'thismoviemakesmeverydisgusting.becauseitwashorrible.'},
{'score':0.03569378703832626,'token':3308,'token_str':'wrong','sequence':'thismoviemakesmeverydisgusting.becauseitwaswrong.'},
{'score':0.033358603715896606,'token':2613,'token_str':'real','sequence':'thismoviemakesmeverydisgusting.becauseitwasreal.'}]

上面,我们使用了表达正面和负面的两个句子,模型得到最高的均是与类型相关的词语,这也验证了这种方法的可行性。

三、引入verblize类别映射的Prompt-MLM预测

与构造prompt-template之外,另一个重要的点是verblize,做词语到类型的映射,因为MLM模型预测的词语很不确定,需要将词语与具体的类别进行对齐,比如将"great", "amazing", "good", "fun", "fantastic", "better"等词对齐到"positive"上,当模型预测结果出现这些词时,就可以将整个预测的类别设定为positive;

同理,将"awful", "horrible", "bad", "wrong", "ugly"等词映射为“negative”时,即可以将整个预测的类别设定为negative;

>>>verblize_dict={"pos":["great","amazing","good","fun","fantastic","better"],"neg":["awful","horrible","bad","wrong","ugly"]
...}
>>>hash_dict=dict()
>>>fork,vinverblize_dict.items():
...forv_inv:
...hash_dict[v_]=k
>>>hash_dict
{'great':'pos','amazing':'pos','good':'pos','fun':'pos','fantastic':'pos','better':'pos','awful':'neg','horrible':'neg','bad':'neg','wrong':'neg','ugly':'neg'}

因此,我们可以将这类方法直接加入到上面的预测结果当中进行修正,得到以下结果,

>>>[{"label":hash_dict[i["token_str"]],"score":i["score"]}foriinpred1]
[{'label':'pos','score':0.14730973541736603},{'label':'pos','score':0.10884211212396622},{'label':'pos','score':0.09781625121831894},{'label':'pos','score':0.04627735912799835},{'label':'pos','score':0.043138038367033005}]

>>>[{"label":hash_dict.get(i["token_str"],i["token_str"]),"score":i["score"]}foriinpred2]
[{'label':'neg','score':0.05464331805706024},{'label':'pos','score':0.050322480499744415},{'label':'neg','score':0.04008950665593147},{'label':'neg','score':0.03569378703832626},{'label':'real','score':0.033358603715896606}]

通过取top1,可直接得到类别分类结果,当然也可以综合多个预测结果,可以获top10中各个类别的比重,以得到最终结果:

{
"text":"Ireallylikethefilmalot.","label":"pos"
"text":"thismoviemakesmeverydisgusting.","label":"neg"
}

至此,我们可以大致就可以大致了解在zero-shot场景下,prompt的核心所在。而我们可以进一步的想到,如果我们有标注数据,又如何进行继续训练,如何更好的设计prompt-template以及做好这个词语映射词表,这也是prompt-learning的后续研究问题。

因此,我们可以进一步地形成一个完整的基于训练数据的prompt分类模型,其代码实现样例具体如下,从中我们可以大致在看出具体的算法思想,我们命名为prompt.py

fromtransformersimportAutoModelForMaskedLM,AutoTokenizer
importtorch

classPrompting(object):

def__init__(self,**kwargs):
model_path=kwargs['model']
tokenizer_path=kwargs['model']
if"tokenizer"inkwargs.keys():
tokenizer_path=kwargs['tokenizer']
self.model=AutoModelForMaskedLM.from_pretrained(model_path)
self.tokenizer=AutoTokenizer.from_pretrained(model_path)

defprompt_pred(self,text):
"""
输入带有[MASK]的序列,输出LM模型Vocab中的词语列表及其概率
"""
indexed_tokens=self.tokenizer(text,return_tensors="pt").input_ids
tokenized_text=self.tokenizer.convert_ids_to_tokens(indexed_tokens[0])
mask_pos=tokenized_text.index(self.tokenizer.mask_token)
self.model.eval()
withtorch.no_grad():
outputs=self.model(indexed_tokens)
predictions=outputs[0]
values,indices=torch.sort(predictions[0,mask_pos],descending=True)
result=list(zip(self.tokenizer.convert_ids_to_tokens(indices),values))
self.scores_dict={a:bfora,binresult}
returnresult

defcompute_tokens_prob(self,text,token_list1,token_list2):
"""
给定两个词表,token_list1表示表示正面情感positive的词,如good,great,token_list2表示表示负面情感positive的词,如good,great,bad,terrible.
在计算概率时候,统计每个类别词所占的比例,score1/(score1+score2)并归一化,作为最终类别概率。
"""
_=self.prompt_pred(text)
score1=[self.scores_dict[token1]iftoken1inself.scores_dict.keys()else0
fortoken1intoken_list1]
score1=sum(score1)
score2=[self.scores_dict[token2]iftoken2inself.scores_dict.keys()else0
fortoken2intoken_list2]
score2=sum(score2)
softmax_rt=torch.nn.functional.softmax(torch.Tensor([score1,score2]),dim=0)
returnsoftmax_rt

deffine_tune(self,sentences,labels,prompt="Sinceitwas[MASK].",goodToken="good",badToken="bad"):
"""
对已有标注数据进行Fine tune训练。
"""
good=tokenizer.convert_tokens_to_ids(goodToken)
bad=tokenizer.convert_tokens_to_ids(badToken)
fromtransformersimportAdamW
optimizer=AdamW(self.model.parameters(),lr=1e-3)
forsen,labelinzip(sentences,labels):
tokenized_text=self.tokenizer.tokenize(sen+prompt)
indexed_tokens=self.tokenizer.convert_tokens_to_ids(tokenized_text)
tokens_tensor=torch.tensor([indexed_tokens])
mask_pos=tokenized_text.index(self.tokenizer.mask_token)
outputs=self.model(tokens_tensor)
predictions=outputs[0]
pred=predictions[0,mask_pos][[good,bad]]
prob=torch.nn.functional.softmax(pred,dim=0)
lossFunc=torch.nn.CrossEntropyLoss()
loss=lossFunc(prob.unsqueeze(0),torch.tensor([label]))
loss.backward()
optimizer.step()

四、基于zero-shot的prompt情感分类实践

下面我们直接以imdb中的例子进行zero-shot的prompt分类实践,大家可以看看其中的大致逻辑:

1、加入

>>fromtransformersimportAutoModelForMaskedLM,AutoTokenizer
>>importtorch
>>model_path="bert-base-uncased"
>>tokenizer=AutoTokenizer.from_pretrained(model_path)
>>frompromptimportPrompting
>>prompting=Prompting(model=model_path)

2、使用prompt_pred直接进行情感预测

>>prompt="Becauseitwas[MASK]."
>>text="Ireallylikethefilmalot."
>>prompting.prompt_pred(text+prompt)[:10]
[('great',tensor(9.5558)),
('amazing',tensor(9.2532)),
('good',tensor(9.1464)),
('fun',tensor(8.3979)),
('fantastic',tensor(8.3277)),
('wonderful',tensor(8.2719)),
('beautiful',tensor(8.1584)),
('awesome',tensor(8.1071)),
('incredible',tensor(8.0140)),
('funny',tensor(7.8785))]
>>text="Ididnotlikethefilm."
>>prompting.prompt_pred(text+prompt)[:10]
[('bad',tensor(8.6784)),
('funny',tensor(8.1660)),
('good',tensor(7.9858)),
('awful',tensor(7.7454)),
('scary',tensor(7.3526)),
('boring',tensor(7.1553)),
('wrong',tensor(7.1402)),
('terrible',tensor(7.1296)),
('horrible',tensor(6.9923)),
('ridiculous',tensor(6.7731))]

2、加入neg/pos词语vervlize进行情感预测

>>text="notworthwatching"
>>prompting.compute_tokens_prob(text+prompt,token_list1=["great","amazin","good"],token_list2=["bad","awfull","terrible"])
tensor([0.1496,0.8504])

>>text="Istronglyrecommendthatmoview"
>>prompting.compute_tokens_prob(text+prompt,token_list1=["great","amazin","good"],token_list2=["bad","awfull","terrible"])
tensor([0.9321,0.0679])

>>text="Istronglyrecommendthatmoview"
>>prompting.compute_tokens_prob(text+prompt,token_list1=["good"],token_list2=["bad"])
tensor([0.9223,0.0777])

五、基于zero-shot的promptNER实体识别实践

进一步的,我们可以想到,既然分类任务可以进行分类任务,那么是否可以进一步用这种方法来做实体识别任务呢?

实际上是可行的,暴力的方式,通过获取候选span,然后询问其中实体所属的类型集合。

1、设定prompt-template

同样的,我们可以设定template,以一个人物为例,John是一个非常常见的名字,模型可以直接知道它是一个人,而不需要上下文

Sentence.Johnisatypeof[MASK]

2、使用prompt_pred直接进行预测我们直接进行处理,可以看看效果:

>>prompting.prompt_pred("JohnwenttoParistovisittheUniversity.Johnisatypeof[MASK].")[:5]
[('man',tensor(8.1382)),
('john',tensor(7.1325)),
('guy',tensor(6.9672)),
('writer',tensor(6.4336)),
('philosopher',tensor(6.3823))]
>>prompting.prompt_pred("SavaşwenttoParistovisittheuniversity.Savaşisatypeof[MASK].")[:5]
[('philosopher',tensor(7.6558)),
('poet',tensor(7.5621)),
('saint',tensor(7.0104)),
('man',tensor(6.8890)),
('pigeon',tensor(6.6780))]

2、加入类别词语vervlize进行情感预测
进一步的,我们加入类别词,进行预测,因为我们需要做的识别是人物person识别,因此我们可以将person类别相关的词作为token_list1,如["person","man"],其他类型的,作为其他词语,如token_list2为["location","city","place"]),而在其他类别时,也可以通过构造wordlist字典完成预测。

>>>prompting.compute_tokens_prob("Itisatypeof[MASK].",
token_list1=["person","man"],token_list2=["location","city","place"])
tensor([0.7603,0.2397])

>>>prompting.compute_tokens_prob("SavaşwenttoParistovisittheparliament.Savaşisatypeof[MASK].",
token_list1=["person","man"],token_list2=["location","city","place"])//确定概率为0.76,将大于0.76的作为判定为person的概率
tensor([9.9987e-01,1.2744e-04])

从上面的结果中,我们可以看到,利用分类方式来实现zero shot实体识别,是直接有效的,“Savaş”判定为person的概率为0.99,

prompting.compute_tokens_prob("SavaşwenttoLaristovisittheparliament.Larisisatypeof[MASK].",
token_list1=["person","man"],token_list2=["location","city","place"])
tensor([0.3263,0.6737])

而在这个例子中,将“Laris”这一地点判定为person的概率仅仅为0.3263,也证明其有效性。

总结

本文主要从预训练语言模型看MLM预测任务、引入prompt_template的MLM预测任务、引入verblize类别映射的Prompt-MLM预测、基于zero-shot的prompt情感分类实践以及基于zero-shot的promptNER实体识别实践五个方面,进行了代码介绍。

关于prompt-learning,我们可以看到,其核心就在于将下游任务统一建模为了预训练语言模型的训练任务,从而能够最大地挖掘出预训模型的潜力,而其中的prompt-template以及对应词的构造,这个十分有趣,大家可以多关注。

审核编辑 :李倩


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 语言模型
    +关注

    关注

    0

    文章

    502

    浏览量

    10244
  • nlp
    nlp
    +关注

    关注

    1

    文章

    487

    浏览量

    22006

原文标题:Prompt总结 | 从MLM预训任务到Prompt Learning原理解析与Zero-shot分类、NER简单实践

文章出处:【微信号:zenRRan,微信公众号:深度学习自然语言处理】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    直播预约 |数据智能系列讲座第4期:训练的基础模型下的持续学习

    神经网络,特别是训练的基础模型研究得到了广泛的应用,但其仍然主要依赖于在大量样本上的批量式训练。本报告将探讨实现模型的增量式
    的头像 发表于 10-18 08:09 154次阅读
    直播预约 |数据智能系列讲座第4期:<b class='flag-5'>预</b><b class='flag-5'>训练</b>的基础<b class='flag-5'>模型</b>下的持续学习

    【《大语言模型应用指南》阅读体验】+ 基础知识学习

    收集海量的文本数据作为训练材料。这些数据集不仅包括语法结构的学习,还包括对语言的深层次理解,如文化背景、语境含义和情感色彩等。 自监督学习:模型采用自监督学习策略,在大量无标签文本数据上学习
    发表于 08-02 11:03

    语言模型训练

    能力,逐渐成为NLP领域的研究热点。大语言模型训练是这一技术发展的关键步骤,它通过在海量无标签数据上进行训练,使
    的头像 发表于 07-11 10:11 380次阅读

    LLM训练的基本概念、基本原理和主要优势

    在人工智能和自然语言处理(NLP)领域,大型语言模型(Large Language Model,简称LLM)的兴起极大地推动了技术的进步和应用的发展。LLM通过在大规模文本数据上进行
    的头像 发表于 07-10 11:03 991次阅读

    训练模型的基本原理和应用

    训练模型(Pre-trained Model)是深度学习和机器学习领域中的一个重要概念,尤其是在自然语言处理(NLP)和计算机视觉(CV)等领域中得到了广泛应用。
    的头像 发表于 07-03 18:20 2303次阅读

    语言模型:原理与工程时间+小白初识大语言模型

    语言模型进行训练,此处训练为自然语言处理领域的
    发表于 05-12 23:57

    【大语言模型:原理与工程实践】大语言模型的应用

    操作。所谓零样本提示(Zero-Shot Prompt),指的是在提示词中不包含与指令任务相似的任何示例。 当大语言模型训练完成后,它便具备了分析情绪和识别命名实体等常见
    发表于 05-07 17:21

    【大语言模型:原理与工程实践】大语言模型的评测

    语言模型的评测是确保模型性能和应用适应性的关键环节。基座模型到微调模型,再到行业
    发表于 05-07 17:12

    【大语言模型:原理与工程实践】大语言模型训练

    语言模型的核心特点在于其庞大的参数量,这赋予了模型强大的学习容量,使其无需依赖微调即可适应各种下游任务,而更倾向于培养通用的处理能力。然而,随着学习容量的增加,对
    发表于 05-07 17:10

    【大语言模型:原理与工程实践】大语言模型的基础技术

    特定任务模型进行微调。这种方法的成功不仅是自然语言处理发展的一个转折点,还为许多现实世界的应用场带来了前所未有的性能提升。广为人知的GPT到BERT,
    发表于 05-05 12:17

    【大语言模型:原理与工程实践】核心技术综述

    的复杂模式和长距离依赖关系。 训练策略: 训练是LLMs训练过程的第一阶段,模型在大量的
    发表于 05-05 10:56

    【大语言模型:原理与工程实践】揭开大语言模型的面纱

    获得良好效果。 语言模型作为自然语言处理的核心,不断进化以捕捉人类语言的精髓。起初,这些模型依赖于统计方法,如n-gram
    发表于 05-04 23:55

    名单公布!【书籍评测活动NO.30】大规模语言模型理论到实践

    等多种形式和任务。这个阶段是语言模型向对话模型转变的关键,其核心难点在于如何构建训练数据,包括
    发表于 03-11 15:16

    语言模型推断中的批处理效应

    随着开源训练大型语言模型(Large Language Model, LLM )变得更加强大和开放,越来越多的开发者将大语言
    的头像 发表于 01-04 12:32 590次阅读
    大<b class='flag-5'>语言</b><b class='flag-5'>模型</b>推断中的批处理效应

    语言模型简介:基于大语言模型模型全家桶Amazon Bedrock

    本文基于亚马逊云科技推出的大语言模型与生成式AI的全家桶:Bedrock对大语言模型进行介绍。大语言模型
    的头像 发表于 12-04 15:51 743次阅读