实战中,BERT如何处理篇章级长文本?


自2018年以来,bert以及改造版本对多项NLP任务进行“屠榜”,引起了工业界、学术界的轩然大波。目前,很多算法团队蠢蠢欲动,希望引入SOTA模型,对现有业务进行提升。

不过有点令人遗憾的是,bert支持的最长序列长度为512。处理评论,标题等短文本基本上够用了,但对于较长的文本,比如新闻正文,会经常出现超出字符限制的情况。因此怎么处理好长文本不失为使用BERT的一个小trick。

1.截断法

截断法是非常常用办法,大致分为三种,head截断,tail截断,head+tail 截断。

  1. head截断即从文本开头直到限制的字数。
  2. tail截断是从结尾开始往前截断。
  3. head+tail 截断,开头和结尾各保留一部分,比例参数是一个可以调节超参数。

最长序列字数是512,其中还包括一些特殊token,在文本分类中,要包含开头的[CLS]和结尾的[SEP],因此实际只能最多装510个字。如果一个长文本的重要信息是在开头,可能head截断效果是比tail截断要好。同理,tail截断对信息点在结尾的长文本效果较好。具体哪种截断效果好,不同数据集不一样,需要多试。使用head+tail 截断,一般而言是好于单一的截断方式。

截断法丢失序列信息,显得非常暴力,一般使用在文本不是特别长的场景。如果是篇章级,文本长度好几千,如果直接使用截断法,必然会丢失大量信息。因此面对这种场景,首先想到的是“拆”。

2.Pooling法

将一个整段的文本拆分为多个segment,每一个segment的长度小于510。segment的拆分可以暴力地通过510的大小进行chunk,或者通过断句的方式,将相邻的句子放入一个segment。每一个segment都通过BERT,对得到的[CLS]进行Pooling。可以是用Max-Pooling、Mean-Pooling。亦或将 Max-Pooling、Mean-Pooling进行concat,然后再通过一个FC。如果考虑性能、只能使用一个Pooling的话,就使用Max-Pooling,因为捕获的特征很稀疏、Max-Pooling会保留突出的特征,Mean-Pooling会将特征打平。这一点和TextCNN后接Max-Pooing是一个道理。

Pooling法将所有序列都放入模型之中。考虑到了全局的信息,对文本很长且截断敏感的任务有较好的效果。但有一些缺点

  1. 性能较差,原来截断法需要encode一次,Pooling法需要encode多次,篇章越长,速度越慢。
  2. segment之间的联系丢失,可能会出badcase。


3.压缩法

压缩法的宗旨是选取“精华”,去除“糟粕”。断句之后整个篇章分割成segment,通过规则或者训练一个小模型,将无意义的segment进行剔除。

举个例子,最近笔者做了一个长篇章文本分类的任务,数据是自媒体自己创作发布的文章。一些作者,为了凑字数,或者进行引流会写一些冗余的话术,比如在结尾会说道:“不知道各位看官,对小编的创作是否感兴趣,如果感兴趣的话,希望点个赞”等。通过统计,该任务与主题相关的句子,不到总字数的60%,40%的时间都是在浪费在这些"糟粕"上,同时这些冗余文本也会带来一些噪声,不利于模型的学习。

因此在某一些场景,可以尝试对原始文本进行过滤,降低有效文本的大小。关键点是如何筛选出有效句子,然而筛选方法因任务而定,没有统一的方法。笔者曾经使用一个非常暴力压缩篇章的trick:让正文的句子和标题做字符相似度,只选取字符相似度最大的TOP-K句子来代表这个篇章。在F1的降低的可接受的范围内,让线上的QPS提升了数倍,节省的都是白花花的钱。

如果压缩之后,大部分的句子还是超过510,继续使用截断法或者Pooling法。


4.总结

本文只是笔者对使用bert进行篇章级长文本处理的一些经验和心得。具体使用什么方法,还要看数据和问题,不能一概而论。如果是工业级的实战,还要考虑性能和经济性。要是做出来的模型效果好,但因性能差上不了线,岂不是闹心。最后祝大家能在修炼的道路上越走越远。^_^

参考:实战中,BERT如何处理篇章级长文本?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值