(杂谈)关于UIE的一点感想
- 0. 初识UIE
- 1. 真假UIE?
- 2. HAE与UIE
- 3. 结构化序列生成
- 4. UIE是“大一统”吗?
0. 初识UIE
前段时间百度推出的UIE模型在各个NLP相关的公众号刷屏,基本上都是以“大一统”的字眼进行介绍的,出于好奇,我也安装了paddle,体验了一把这个模型。根据官方的提示,果不其然地获取到了不错的结果,这也是prompt这一概念一年前提出到现在,我第一次接触到从应用角度来讲,令我感到惊喜的模型。但是惊喜之余,仔细揣摩了一番,又感觉这个“大一统”的模型似乎并没有特别新奇之处。
1. 真假UIE?
可能很多人跟我一样,首先从paddleNLP的git上接触到这个模型,先下载下来体验一番,再来深究它的原理。可是当我看完UIE的论文之后,再来看代码,看到模型结构的时候,令我感到非常意外:
class UIE(ErniePretrainedModel):def __init__(self, encoding_model):super(UIE, self).__init__()self.encoder = encoding_modelhidden_size = self.encoder.config["hidden_size"]self.linear_start = paddle.nn.Linear(hidden_size, 1)self.linear_end = paddle.nn.Linear(hidden_size, 1)self.sigmoid = nn.Sigmoid()def forward(self, input_ids, token_type_ids, pos_ids, att_mask):sequence_output, pooled_output = self.encoder(input_ids=input_ids,token_type_ids=token_type_ids,position_ids=pos_ids,attention_mask=att_mask)start_logits = self.linear_start(sequence_output)start_logits = paddle.squeeze(start_logits, -1)start_prob = self.sigmoid(start_logits)end_logits = self.linear_end(sequence_output)end_logits = paddle.squeeze(end_logits, -1)end_prob = self.sigmoid(end_logits)return start_prob, end_prob
不是说好的T5吗,不是生成式模型吗,怎么是二妮?
从模型结构可以很清楚的看到,这是一个抽取式模型,而非论文中所述的生成式,是以ERNIE编码器,接双指针解码,这个结构不是两年前香侬AI提出的MRC模型吗(MRC是我入行NLP之后读的第一篇论文,所以印象比较深刻),区别是在这个“UIE”中似乎只有start和end,少了交叉的部分,但是思想还是双指针的思想。
看到这里,可以说是出人意料,却又感到意料之中。出人意料的是,它跟UIE论文中的模型完全是两回事,完全是“货不对板”;意料之中的是,模型直接结构直接解答了我之前在测试其效果时遇到的几个疑问:
(1)为什么模型可以抽取over-lap的实体?
——因为解码是一个双指针的任务,而非序列标注。
(2)模型声称可以抽取事件和关系,但是在实际操作时抽取事件和关系的prompt是如此接近?
——这个我们先按下不表,等会儿再说。
那么真正的UIE在哪里呢?还得看论文里给出的链接:
https://github.com/universal-ie/UIE
是一个pytorch的版本,跟论文中所述的思路是一样的。
另外,paddle版本也有这个生成式的模型,只不过它叫duuie
,在git上也可以找得到。
所以,并不是论文与代码货不对板,而是我们在paddle的taskflow中看到的uie,与论文中的uie,是两个不同的东西,可以看做是一个快捷调用的应用。毕竟,推广一个工作最快的方式,还是开放给大家一个快捷有效的应用吧。
2. HAE与UIE
接下来我们来讨论一下paddle版本的UIE,也就是那个抽取式的模型。
20年的时候,看过一个叫做“history embedding”,也就是历史编码的工作,记得好像也是百度团队做的,后来我沿着这个思路也做了一点工作。
所谓历史编码,就是在编码器的输入侧,加入一个额外的嵌入层,也就是除了token-emb和seg-emb之外,又加了一个history-emb(为什么不提pos-emb,因为pos-emb是在attention的位置),然后有了这样一个embedding层,模型就可以感知到哪些位置已经作为历史论元出现过。
模型的输入文本,也是以QA的形式给入:[CLS]触发词xxx,这个xx事件的发生地点是哪里?[SEP]原文[SEP]。
看到这个结构,是不是与prompt非常相似呢?所以我一直认为,所谓的prompt,是早在去年夏天之前就已经存在的,只是没有被冠以这个名字罢了,而且prompt也没有吹的那么神乎其神。
由于时间过去比较久了,我现在只隐约记得当时一些工作内容,回顾如下:
- (1)keras版本
由于当时transformers模块还没有特别广泛的应用,我用的还是bert4keras,所以就根据hae改成了keras版本; - (2)有效性验证
在duee数据集上验证了hae的有效性,事件抽取的argument F1好像是有三、四个点的提升; - (3)问句形式验证
输入文本的前半部分,也就是问句的部分,其实不必是问句,尽管如果是问句的话可能更符合模型在预训练时的情景。当时尝试了很多问法,也尝试了只输入触发词和事件类型,作为prompt,发现对模型效果的影响并不大。所以我猜测在finetune的时候,模型是捕获了一些句法结构信息的,本质上是学习到了prompt触发词这个位置的词汇,与原文正文中的真实的触发词之间的关系,进而捕获到了原文中触发词相关的具体的论元的特征(不论是哪个论元history emb中的处罚词位置一定都是1),所以问句的形式是怎样的,其实并不关键; - (4)zero-shot验证
在duee验证之后,我又对模型的zero-shot能力进行了验证,尝试让模型去发现一些没有在schema中的事件类型和论元类型,结果居然成功了,例如,在训练集中并不包含雪灾这一事件类型,但给入相应地问句,输入自定义的论元,是可以成功地抽取出正确的论元的。类似的,还对其他的一些事件类型和论元类型进行了尝试,总结下来发现,如果是与训练接schema相似的事件类型或者论元,例如**者
,被**者
,**时间
,**等级
等都可以比较顺利的抽取出来,而如果与schema中已有的事件类型和论元类型相去甚远的话,就有些困难了; - (5)关系抽取验证
在验证了事件抽取的有效性之后,我想到了关系抽取。既然可以成功地根据触发词和论元类型构造prompt抽取事件,那么,是否也可以根据主语和关系类型抽取关系呢?我随即在duie数据集上进行了验证,结论是肯定的。该模型可以利用prompt抽取关系,只是效果上在当时比不上casrel等关系抽取模型。 - (6)序列标注与双指针
对于解码,当时也尝试了序列标注和双指针两种结构,从效果上来看,是区别不大的,序列标注由于可以再接一个CRF,效果有些微的提升,而且双指针的过度稀疏会造成训练缓慢的情况,加之当时所采用的数据集并没有遇到over-lap的情况,所以最后还是采用的序列标注的方式进行解码。
到这里我们可以发现,这不就是paddle版本UIE的思路吗。two-stage生成prompt,再利用prompt捕获实体之间的关系。
当时我大概记得,得到这个模型的效果的时候,我是非常意外的,但是一方面,当时我采用的bert-base模型只能处理到512的长度,并且问句占用了一定的长度,加之中文场景下的bert-base一个字符就占一个token,这就导致在实际应用场景下,模型的实用性是比较差的。而且pipline结构下,连续几个bert-base的编码器也是挺重的,所以后来也没有再沿着这个思路继续做下去。但是现在有了各种蒸馏的小模型,以及long-former等一众处理长序列的预训练模型,这些问题都已经不是问题,看看如今UIE发布的几个模型,从base到small,micro,nano,模型甚至可以应用到移动端。
总之,当时没有沿着这个思路做下去,现在回顾一下感觉非常可惜,怎奈当时刚入行的我,没有什么经验,对自己的直觉也不怎么自信。
3. 结构化序列生成
说回正牌的UIE本身,我第一眼看到UIE论文的时候,我一下子就联想到了另一篇论文,隐约记得是文本到事件的一个生成任务,生成的就是结构化的事件,于是再根据生成的这个结构化序列解码成事件。
所以在读论文的时候,我是带着一种排斥的心理在读的,明明别人已经做过的内容,怎么又做一遍还能发顶会,这都是去年就已经有的思想了。我隐约记得那篇文章我实验过,但是效果并不太好,所以后来就没有再关注,只是记得好像是去年NAACL还是EMNLP的论文,但是找了一圈也没找到,直到昨天才尴尬地发现,那篇文章也是ACL,而且作者就是UIE的作者。。。
TEXT2EVENT:https://arxiv.org/pdf/2106.09232.pdf
UIE: https://arxiv.org/pdf/2203.12277.pdf
除此之外,其实在过去两年的信息抽取领域,有很多工作其实都是在做prompt相关的生成,以事件抽取为例,比较有代表性的工作还有Ji Heng老师团队的gen-arg等。说明整个领域都在以这个方向行进,所以在prompt大火的今天,UIE的提出,似乎是一种必然。
讲到这里,我们可以发现,UIE这项工作并不是今年一下子提出来的,而是一个积累沉淀的过程,这一系列研究感觉都非常顺应多数人的正常思考逻辑,一脉相承。
4. UIE是“大一统”吗?
是也不是,我这样觉得。或许加上这样一个看点,可以更快地推广这个模型,让更多人接受吧。
首先对于关系抽取和事件抽取这两项任务,我认为其本质上并没有太大的差异,其差别在于触发词作为实体的特殊性,如果两个事情本身就是一致的,它们之间的统一,也谈不上是“大”一统吧。说起“大一统”,我认为UIE的思想并不如OneIE更加大一统,在OneIE中,把所有实体和触发词都当做节点,实体之间的关系和事件论元,都看做是节点之间的边,从而引入了图结构,也正是图结构,赋予了OneIE很强的表现能力(但是也正是因为图解码的复杂性,导致OneIE的推理时间较长),时至今日OneIE在信息抽取领域仍然坚挺,被诸多论文作为对比的SOTA。
同时,我也认为如果哪一天,深度学习中出现了一个“大一统”的模型,其必然是一个图模型,就像我们不能割裂地来看待关系抽取和事件抽取,CNN和RNN,NLP和CV也不应该被对立地看待,包括transformer结构,其本质上都是图模型,只是图的连接方式有所区别,如RNN模型是节点之间顺序连接,CNN模型是在平面上邻域连接。尽管我目前对图模型的研究并不深入,但是直觉让我愿意始终相信这一点。
但是从任务形式上看,我们又不能否认,prompt+text的结构统一了任务的形式,让各个原本我们认为不同的任务,得以一同训练。
可是话说回来,我们为什么一定要追求一个所谓的大一统的模型呢,强如transformer,也难以在任何任务上完全取代CNN和RNN的结构,这难道不是由于任务本身的差异性决定的吗。我们寻求共性,但不应该为了寻求共性而寻求共性,忽视客观存在的差异,诚然一个大一统的模型,可以收获更多的关注和掌声,但认为一切学术研究,终究都要落在应用,应该更加务实。
即便我不认为UIE在思想和结构上不具有非常强的创新性,但是我仍然认为这是一项很了不起的工作,尤其是做了大量的预训练实验,这些工作都是非常有价值的。并且,UIE也实实在在地为广大NLP研究者提供了一个务实的、好用的、快捷的工具,这似乎是与paddleNLP长期以来的追求吧(在这一方面不得不说paddle的taskflow比transformers的pipeline要更实用一些)。
以上就是近期UIE模型带给我的一些思考,如果读者认为哪个地方我讲的不对,可以指出来,或者有一些其他的见解的话,欢迎在评论区讨论。
我个人还是比较喜欢写一些偏应用的博客,只是这次的一些发现,让我觉得实在比较有趣,就忍不住记录一下。如果你喜欢我的内容,记得点赞关注哦。