Key Phrase Extraction

做了一段时间的新闻NLP,越来越感受到抓重点对长文本理解的重要性。类别、话题、关键词句这种离散标签对下游的推荐、搜索业务以及产品的形态都有很重大的影响。最近读了两篇关键短语抽取(Key Phrase Extraction,KPE)相关的论文,感觉挺有意思,跟大家分享一下。 问题定义和数据集 首先,对于一篇文章来说什么是其中的关键短语就没有一个统一的标准,标注的时候也比较主观,而且标注难度很大。常见的类别体系可能包含几百个类别,话题体系包含成千上万个话题,而对于关键短语来说,连个确定的候选集都没有。 目前主流的KPE任务benchmark数据集有好几个,这里列两个比较有名的 KP20k:2017年论文Deep Keyphrase Generation贡献的数据集,由科学论文组成。文本包括标题和摘要。发过论文的都知道,作者需要给文章提供几个关键词,确实是很好的数据来源。 KPTimes:2019年论文****KPTimes: A Large-Scale Dataset for Keyphrase Generation on News Documents****贡献的数据集,文章都是新闻,下面是一个例子。 KPTimes数据样例 这两个数据集规模应该都挺大了,KPTimes的论文里有一张主流数据集规格对照表,一目了然,大家可以参考。从统计上看KP20k和KPTimes篇均5个KP的确实比较实用,但它们的问题是测试集里很大比例的标签并没有在文本中出现,对于模型来说难度可能太大了 主流数据集对比 监督方法 KP20k数据集其实是那篇论文的副产品,那篇论文的主要贡献其实是一个叫CopyRNN的方法,看名字大概就知道是个seq2seq+copy机制的生成式方法。这里引入copy机制也是有比较明确的动机的,因为在RNN时代生成式方法会受限于字典,decoder输出层没有的词是无法被预测出来的。 RNN+copy机制可以在KP20k上获得0.255的F1@10 到了2020年,BERT等Transformers模型已经成了NLP领域的标配,那自然也会想到用来做KPE。Joint Keyphrase Chunking and Salience Ranking with BERT 就是里面简单且有效的一个方法。题目里的Salience是个显著的意思,这篇文章的方法也非常直接,就是把最可能是KP的文本段落(n-gram)用排序的方法找出来。那怎么得到一个n-gram的表示呢,这篇文章的办法就是在Transformer上面再套一个一维CNN,n和卷积核的大小相对应。 论文里用了两个任务来训练这个网络,一个任务是二分类,即n-gram是否是KP;另一个是排序任务,这个任务是对于文档中的每个unique n-gram,获得最大的预测值(文中称为max pooling),然后用hinge loss来使得KP的概率值大于非KP。 JointKPE的成绩大大提高 感兴趣的朋友们可以参考他们的代码实现。 非监督方法 一开始我是想找一些靠谱的非监督方法的,毕竟像KP20k这样优质的的训练数据集一般只有英语。然后就在paperswithcode上看到了目前的榜一,UCPhrase。这个方法比较有意思,它的流程如下面这张图所示 分为几个核心步骤: 找到所谓的Core Phrase。这其实是通过一些规则找到文本中反复出现的片段,并且把它们当做KP,以及后续网络训练的Silver Labels。 用Transformers语言模型生成特征。这里的特征不是大家常用的embedding,而是attention map。 训练一个图像分类器,对于一个attention map进行是否KP的二分类。 一个attention map样例,从中可以发现:1. attention map把句子分成了比较明显的几块 2.attention map可以可以作为图像输入来进行KP分类 这个论文的结果如下,在KP20k上的F1@10是19.7,和2017年的RNN+copy差了6个百分点,但和同样使用Transformers的监督方法相比差了16个百分点。 非监督方法比起监督方法来确实逊色不少 这个工作的代码也开源了:https://github.com/xgeric/UCPhrase-exp。 写在最后 提到KPE,可能大家第一个想到的方法是SpanBert那样的span prediction方法,亦或是序列标注里常用的BIO分类法,但JointBert论文里对比下来还是这种接一个CNN的方法更好。相比于单纯序列标注或片段预测,这个方法确实可以更直接地利用附近的邻域信息,在Kaggle中其实也常有在序列标注前先加一层CNN或RNN来强化邻域信息的做法。 UCPhrase的方法让人眼前一亮,有一种学术美,但与JointBert 16个百分点的性能差异又实际上让它的实用价值大打折扣。所以在业务明确的前提下,搞漂亮方法确实不如扎扎实实搞点标注数据啊。

March 26, 2022 · 1 min · Yuanhao

多模态对比学习预训练模型CLIP

我经常在面试的时候问候选人如何构建一个文本配图系统,有不少人都会想到OpenAI的 CLIP (Contrastive Language–Image Pre-training) 模型。确实,CLIP的思路应该是解决这个问题的一个好框架,正好之前的几篇文章又都是关于其中的关键技术,于是这篇文章重温一下CLIP。 方法 自然语言信号 At the core of our approach is the idea of learning perception from supervision contained in natural language. 正如作者所说,这是CLIP的核心,但并不是一个新的方法。很多过去的研究都使用自然语言信号来训练图片编码器,但大家使用的方法各不一样。 用自然语言信号有几个好处,一个是数据收集容易了,有相关性的图文在互联网上很多,不需要标注,第二个是与之前那种类别空间相比,自然语言信号更容易迁移,后面还会具体讲到。 更大的数据集 CLIP构建了一个400 million 图片-文本对组成的数据集。比之前类似工作所使用的数据集大了二十几倍。而且这些数据集都是互联网上现成的,只是做了一些过滤来保证质量。 it is trained on a wide variety of images with a wide variety of natural language supervision that’s abundantly available on the internet 更大的模型 文本编码器使用的是12层8个头512个隐层神经元的Transformers模型,但没有使用预训练模型。我猜测这是因为要跟图像编码器交互,所以预训练可能帮助不大,如果使用预训练模型还需要特殊的策略来让图像和文本编码器的embedding空间匹配起来。 图像编码器尝试了resnet家族和ViT家族。最佳结果是来自于ViT,并且ViT相比于Resnet有更高的训练效率。图像编码器同样也没有使用Imagenet上的预训练权重来初始化。ViT我们在之前有两篇文章介绍,感兴趣的同学可以参考。 更高效的训练目标 过去的SOTA CV模型,如Noisy Student EfficientNet-L2,只训练Imagenet就需要耗费大量的训练时长(33个TPU年),如何能够在超大规模、自然语言信号的数据集上训练出一个好模型是个挑战。这部分也是CLIP最核心的地方。 This data is used to create the following proxy training task for CLIP: given an image, predict which out of a set of 32,768 randomly sampled text snippets, was actually paired with it in our dataset....

December 13, 2021 · 2 min · Yuanhao

面向电商场景的语言模型E-BERT

最近跟不少做电商NLP的朋友们聊天,有不少收获。我之前从来没想过【搜索】在电商里的地位是如此重要,可能GMV的50%以上都是从搜索来的。巨大的经济价值也极大地推动了技术的发展,他们的工作做得很细致,毕竟一个百分点的点击率后购买率提升也许对应的就是几百亿的成交额。 其实之前做的汽车领域NLP工作跟电商有很多相似的地方,场景先验都非常重要。直接使用开放域语料预训练的语言模型效果并不好。我们也尝试过一些方法,例如用本领域语料训练语言模型,结合一些词库词典等等。今天介绍最近看到的一篇针对电商场景调优BERT的论文《E-BERT: Adapting BERT to E-commerce with Adaptive Hybrid Masking and Neighbor Product Reconstruction》,其中的一些方法应该对细分领域NLP都有一些启发。 方法 论文的创新方法主要有两个:Adaptive Hybrid Masking(AHM,自适应混合掩码)和Neighbor Product Reconstruction(NPR,相似商品重构)。 E-BERT总览 {: .align-caption style=“text-align:center;font-size:smaller”} AHM 第一个方法AHM其实是对已有掩码方式的改进。原始版本的BERT采用的是随机mask,这个大家应该都比较清楚。这种mask方式针对的是token,而众所周知token是由单词通过wordpiece tokenizer分割而来。所以这种方式遮盖住的可能是单词的一个部分,学习这种类似看三个字母猜剩下四个字母的任务不是很符合大家的直觉。随后就诞生了更加符合人类认知的Whole Word Masking,这个方法就是说要遮就遮整个词。这里用一个网上的例子帮大家理解 Input Text: the man jumped up , put his basket on phil ##am ##mon ' s head Original Masked Input: [MASK] man [MASK] up , put his [MASK] on phil [MASK] ##mon ' s head Whole Word Masked Input: the man [MASK] up , put his basket on [MASK] [MASK] [MASK] ' s head philammon是一个词,他会被tokenizer分解成三个token,这时就体现了普通mask和WWM的区别。...

September 16, 2020 · 1 min · Yuanhao

受控文本生成2

昨天的文章介绍了在输出空间对文本生成进行控制的两篇论文,今天介绍一篇在隐空间控制的论文。 隐空间方法也分为两个流派,一种认为在隐空间里可以把内容和特性的向量表示分开(disentangled),然后通过修改特性向量来实现对特性的控制;另一种则无须这种假设。下面分别介绍一篇相关论文。 Style Transfer from Non-Parallel Text by Cross-Alignment disentangled representation的代表作之一,发表在2017年的NIPS上,如今引用已经接近300多。 Style Transformer: Unpaired Text Style Transfer without Disentangled Latent Representation 复旦大学NLP组发表于2019年的文章,已经被引用20次,文章标题中明确写了他们的方法without Disentangled Latent Representation。 在文章的introduction部分列举了一些Disentangled表示的问题,我觉得比较重要的两条是: 难以评价Disentangled表示的质量,纯粹的Disentangled表示也很难获得; 分离不是必要的,有文章已经论证了靠解码器就可以overwrite风格。 这篇文章总的来说是对抗生成网络的思路。模型分两大块,一块是典型的encoder-decoder结构的transformers,用来作为风格迁移器,另一块是判别器,用来解决由于没有平行语料带来的训练问题。 判别器训练 文中提出了两种判别器,从结果上看多分类判别器对BLEU指标更友好,而条件判别器对迁移后的风格更友好。 多分类判别器 这种方法比较好理解,即采用K+1类的多类分类器作为判别器,输入只有句子。后K类对应K种风格,第0类对应$f_\theta(\rm{x},\rm{\hat{s}})$,即假样本。在训练时判别器时,将原始语料和用原风格重建后的句子都标为对应的风格,假样本标为第0类。在训练风格转换器的时候,我们希望转换器能尽量提高$f_\theta(\rm{x},\rm{\hat{s}})$被判别为$\rm{\hat{s}}$类的概率,即能骗过判别器,使判别器不认为生成的是个假样本。 条件判别器 输入包括句子和风格,判别器需要判断句子是否含有风格(二分类)。训练判别器时将原始语料和重建句子$f_\theta(\rm{x},\rm{s})$标注为正样本,将变换后的句子$f_\theta(\rm{x},\rm{\hat{s}})$标注为负样本。 判别器训练算法 {: .align-caption style=“text-align:center;font-size:smaller”} 风格迁移器训练 风格迁移器有三个重要的任务,一个是自重建(Self Reconstruction),一个是循环重建(Cycle Reconstruction),以及风格控制(Style Controlling)。 自重建就是输入句子$\rm{x}$以及其原本风格的控制变量$\rm{s}$,让他生成自己。这个任务是可以使用监督学习来完成的,loss计算公式如下 $$ L_{\rm{self}}=-p_\theta(\rm y=\rm x|\rm x,\rm s) $$ 循环重建是先输入$\rm{x}$和一个其他的风格控制变量$\rm{\hat{s}}$,生成$\rm\hat y$,再用$\rm\hat y$和$\rm s$生成一个$\rm y$。此时$\rm y$应该和$\rm{x}$无论内容及风格都一致,并且可以使用监督学习来计算loss: $$ L_{\rm{cycle}}=-p_\theta(\rm y=\rm x|f_\theta(\rm x,\rm\hat s), \rm s) $$ 前面两个任务虽然解决了没有平行语料带来的训练问题,但思考一下就会发现这两个任务并不会起效果。模型可以完全只学习返回原句子就可以“蒙混过关”。解决的办法就是检验一下循环的中间结果$f_\theta(\rm x,\rm\hat s)$,这个中间结果应该尽可能含有$\rm\hat s$风格。因此引入了第三个风格控制任务,这个任务根据判别器的不同也分成两种情况:...

July 23, 2020 · 1 min · Yuanhao

受控文本生成1

关于文本生成的话题聊得比较少,印象中我们之前只有一期多轮问句改写涉及到了文本生成,受控文本生成就更少了。 受控文本生成是在保证内容的前提下对文本的特性,例如情绪、文风等,进行控制。典型的任务有文本风格迁移。图片和声音的风格迁移都已经商用落地了,例如之前很火的几个应用例如Prisma和FaceApp,相比起来文本风格迁移的发展要慢一些。 名噪一时的Prisma是图像风格迁移的代表性应用 {: .align-caption style=“text-align:center;font-size:smaller”} 文本风格迁移很像翻译任务(语言也可以认为是文本特性的一种),但相比于机器翻译,风格迁移任务几乎没有平行语料,所以要困难一些。如果你对这个方向有兴趣,强烈推荐北大付振新同学整理的这个Repo。 受控文本生成因为是文本生成的高级版,通过学习相关技术可以很好地加深对文本生成的理解。受控文本生成从技法上来讲主要有两类,第一类在隐空间做文章,第二类在生成器的输出空间上做文章。 相比于在隐空间施加控制,我感觉在输出空间施加控制在方法上更简单一些。今天先从这个流派开始。我认为在输出空间进行控制又可以细分出两种形式,一种是在概率空间,一种是在离散空间,下面分别用一篇文章来举例。 Delete, Retrieve, Generate: A Simple Approach to Sentiment and Style Transfer 来自斯坦福NLP组,发表在2018年的NAACL,目前引用150,可以说是这个方向的经典论文了。 这篇其实包含了四种方法,但我感觉最有代表性的是在token空间进行的方法(即后面的template based方法),可解释性强,效率也高。 DRG的四种迁移方法 {: .align-caption style=“text-align:center;font-size:smaller”} 这篇文章的思路很简单,因为它基于一个假设:通常文本特征迁移可以通过改变一些标志词或短语(attribute markers)来完成。 在做风格迁移时,首先要找到这些attribute markers。找的方法也很简单,就是考虑某个n-gram在不同风格语料中出现的概率。如果有显著(salience, s)差异,那它就很可能是个attribute marker,显著性的计算公式如下,$u$是某个term,$v$是某种风格,$\mathcal{D}_v$是某种风格的所有语料,$\lambda$是个平滑系数。公式简单,大家一看便懂,计算出数值后根据阈值最终确定所有的attribute marker。 $$ s(u,v)=\frac{\text{count}(u, \mathcal{D}v)+\lambda}{(\sum{v’\in \mathcal{V},v’\neq v}\text{count}(u, \mathcal{D}_{v’}))+\lambda} $$ 围绕这些attribute marker(后文简称AM),后续将进行如文字标题所写的三种核心操作:delete, retrieve和generate。 Delete Delete的目的是要删除句子中的AM,留下内容。用$a(x, v^{\text{src}})$表示源句子x中所有的AM,删除AM后的x表示为$c(x, v^{\text{src}})$,即不含AM的句子内容。 Retrieve 这一步是要在源句子中插入目标特性的AM。论文的策略是先使用$c(x, v^{\text{src}})$在目标特性句子集合中检索一个内容最接近的句子$x^{\text{tgt}}$。内容接近程度的评价可以使用任意的距离函数来完成。 Generate 这是最后一步,即获得最终的结果。文章里有四种策略 Retrieve Only 直接返回第二步的结果。这么做生成的句子在语言角度应该是正确的且带有目标特性,但可能在内容上和源句有出入。 Template Based 直接把$a(x, v^{\text{src}})$替换成$a(x^{\text{tgt}}, v^{\text{tgt}})$。这么做简单粗暴,可能产生不通顺的句子。 Delete Only 把$c(x, v^{\text{src}})$交给一个RNN进行编码,再拼上特性$v^{\text{tgt}}$的embedding,最后交由一个解码器解码。 Delete And Retrieve 和上一种相似,但不是拼上特性$v^{\text{tgt}}$的嵌入,而是用另一个RNN编码得到的$a(x^{\text{tgt}}, v^{\text{tgt}})$的表示向量。 前两种方法是不需要训练的,后两种则需要训练。对于Delete Only,使用重建句子任务(即训练一个自编码器)来训练。对于Delete And Retrieve则复杂一些,为了防止特征迁移的能力退化成句子拼接(c+a)的能力,作者在这里训练一个降噪自编码器,具体地说就是随机替换a里的AM。...

July 22, 2020 · 1 min · Yuanhao

Tweet Sentiment Extraction比赛总结

这是前段时间结束的Kaggle比赛,之前在文档问答的文章中我也有提到过,最终我们队获得了第七名,这篇文章分享一下我的参赛收获和感受。 首先感谢队友,特别是曹老师,如果没有曹老师我肯定中途就弃赛了。至于弃赛的原因,在感受部分会详细介绍。我的代码已经传到Github上了,感兴趣的朋友可以看一看,里面包含了我所有的commits,可以完整看到我方案的演进。 Repo: https://github.com/thuwyh/Tweet-Sentiment-Extraction 赛题回顾 比赛叫做Tweet Sentiment Extraction,对于给定的tweet和情感极性,需要选手从文本中找出支撑情感的部分。例如下面这条数据 "My ridiculous dog is amazing." [sentiment: positive] 模型应该返回amazing这个词。比赛的评价指标是word-level Jaccard score,它的含义看下面的实现就一目了然了。 def jaccard(str1, str2): a = set(str1.lower().split()) b = set(str2.lower().split()) c = a.intersection(b) return float(len(c)) / (len(a) + len(b) - len(c)) Baseline及一些改进 在比赛的初期讨论区和kernel分享区基本就定下了解题思路的基调,即用机器阅读理解(MRC)的方法来做span prediction。具体的说,就是把数据提供的情感词作为question,把tweet作为context,把预测对象作为answer。 模型也很简单,在RoBERTa后面接一个questionAnswering head预测start和end位置就可以了。这道题一个比较神奇的地方就是RoBERTa的效果比普通的BERT要好一些。 在这个框架下,大家也都做了一些改进,例如: 在语言模型输出后面加dropout; concat语言模型的多层输出结果; 引入FGM等对抗训练方法 以上都是一些比较常规的操作,也比较容易实现,类似FGM是比较稳定能提分的。还有一些稍微复杂一点的trick,例如: 在词级别进行数据增强,例如同义词替换,随机删词 在token级别的增强 label smoothing 蒸馏 因为是span prediction任务,数据增强如果做成随机动态的,需要考虑到改词后对label的影响,这是实现的一个小难点。英文的同义词替换可以使用wordnet来做,相比中文的一些同义词库来讲质量是比较高的。 label smoothing和蒸馏是很相关的两个技术,因为他们都需要用到KL散度作为损失函数。我也是趁这个比赛补了一补相关的知识,感觉还蛮有趣的,感兴趣的朋友可以参考这篇文章。做QA任务通常是对位置用CrossEntropyLoss,但是如果label不是一个确定的位置而是平滑过或者是teacher model预测得到的分布,就需要使用KLDivLoss。 这里在做标签平滑的时候遇到了一个小问题,蛮值得思考的。最开始是Google在Imagenet上用这个技巧,对于这个分类问题标签的种类是确定的K=1000类,所以在Inception论文里直接用一个系数来控制平滑的强度,即 $$ q’(k) = (1-\epsilon)\delta_{k,y}+\frac{\epsilon}{K} $$ 但是如果用同样方法在这些长短不一的句子上做平滑,其实是不合适的。每个位置的平滑概率反比于句子的长度,也就是K,所以我认为更好的确定平滑强度的方法是先确定一个单位平滑强度,再根据句子总长来确定原标签的权重。 针对数据特点的方法 这次的数据总体质量很差,噪声(其实是错误)很多,给参赛者带来了很多困扰。主要的噪声模式有两种,一种是把整个句子都标注成了支撑情感的selected_text,第二种是数据中有大量“断头词”出现在标签中。下图给出了一些例子。 对于第一种整句都是标签的情况,早期很多参赛者就发现了对于neutral类型的情感,绝大部分selected_text都和text一样;但对于其他情感,我们在人工审阅数据之后没有发现什么规律。我只好设计了一个辅助的分类任务让模型自己学习,实测下来有些微的提升,但并不明显。 对于“断头词”的情况,我们在比赛的末期终于发现了其规律。这种情况应该是由于标注环境不一致导致的。例如Twitter数据里有很多@用户的情况,这份比赛数据集会把相关的文本删除,但由于删除脚本的问题会导致文本中多出一个空格。我们猜测标注者看到的数据应该是没有多余空格的,类似于是使用' '.join(text.split())处理过的。这就会导致标出来的span相对于原text的位置产生了位移。且位移的大小就等于多余空格的数量。...

July 8, 2020 · 1 min · Yuanhao

跨语种语言模型

在著名的科幻电影《银河系漫游指南》里有一种叫巴别鱼的神奇生物。将它塞进耳朵里你就能听懂任何语言。多语种语言模型做得事情和巴别鱼很像,人们希望这个模型能用来处理所有的语言。举个例子,大家常用的中文bert有很强的中文处理能力以及一定的英文处理能力,但基本也就只能处理这两种语言;而目前的SOTA多语种模型XLM-RoBERTa能够处理104种语言。 巴别鱼,体型很小,黄色,外形像水蛭,很可能是宇宙中最奇异的事物。它靠接收脑电波的能量为生,并且不是从其携带者身上接收,而是从周围的人身上。它从这些脑电波能量中吸收所有未被人察觉的精神频率,转化成营养。然后它向携带者的思想中排泄一种由被察觉到的精神频率和大脑语言中枢提供的神经信号混合而成的心灵感应矩阵。所有这些过程的实际效果就是,如果你把一条巴别鱼塞进耳朵,你就能立刻理解以任何形式的语言对你说的任何事情。 数据集 训练跨语种语言模型会用到两种语料。一种是单语种(monolingual)语料,另一种是平行(parallel)语料。所谓平行语料就是源语言与译文“对齐”的语料。所谓对齐也有好几种级别,最常见的是句子级对齐,也有按词进行对齐的文本。可想而知,平行语料的获取相比于单语种语料要困难许多。如何充分借助单语种语料来提升模型能力是XLM研究的一个重点。 跨语种语言模型的评价一般有两个大方向,一个是其语义理解能力,另一个是文本生成能力。语义理解能力通常借助XNLI数据集,它提供了15种语言的平行文本,每种语言7500对的NLI语料。文本生成通常用翻译任务来评估,感兴趣的朋友可以自己查阅相关资料。 模型 下表列出了常见的单语种和多语种预训练语言模型。接下来我们将分析其中的mBERT、XLM和XLM-R三个模型。 Multilingual Bert(mBERT) 模型来自于这论文《BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding》,你没有看错,就是发表于2018年大名鼎鼎的BERT论文。 2018年11谷歌就放出了支持104种语言的多语种版本预训练模型,规格是BERT base。这个模型的较新版本是uncased版,即没有对输入文本进行规范化。使用WordPiece算法进行tokenization,词典大小是110k。其他的训练方法和普通的BERT一样,采用的是MLM和NSP两个loss,语料是Wikipedia。 XLM 模型来自于论文《Cross-lingual lan- guage model pretraining》,来自于FAIR,发表在NIPS2019。 XLM使用BPE算法进行tokenization,并且词典大小比mBERT更大,达到200k。论文指出Shared sub-word vocabulary对模型性能有很大的影响,在训练BPE算法的过程中他们使用了特殊的采样方式来避免低资源语种被进行字符集切分。 模型训练使用了三种不同的目标函数,在单语种语料上使用非监督的CLM和MLM。MLM就是masked language modeling,大家比较熟悉,在此就不再赘述了。CLM全称是Causal Language Modeling,简单的说就是用前面的词预测当前词,更详细的介绍大家可以参考我们之前UniLM和MASS的文章。在平行语料上使用的目标称为Translation Language Modeling (TLM)。其训练方式如下图所示,是将平行句子拼接后随机mask,希望让模型能借助另一种语言的信息来还原出被遮蔽的词。从图中可以看出模型用language embedding替换了BERT里的type embedding,并且在做TLM任务时position embedding在两个语言间是对应的。 我们来看一下XLM在XNLI上的表现。这张表很有意思,首先对这个数据集有3种处理方式:translate-train,translate-test和直接测试,即zeroshot。第一种是把英语的MNLI数据集机器翻译成XNLI内的15种语言用于训练,在XNLI测试集上测试;第二种是把XNLI测试集的15种语言翻译成英文。本文的对照组就是上面的mBERT。 可以看到效果最好的是翻译训练集,平均精度达到了76.7%,zero-shot次之,最差的是翻译测试集。在相同的实验设定下XLM稳定优于mBERT,甚至在zero-shot下的XLM也比finetune过的mBERT强。另外MLM+TLM也稳定优于只用MLM的方式。 XLM-RoBERTa 模型来自于论文《Unsupervised Cross-lingual Representation Learning at Scale》,和上文一样来自FAIR,已经被ACL 2020接收。 XLM-R使用了比XLM更大的词典,达到了250k。它也没有辜负RoBERTa的血统,使用了比Wikipedia大得多的cc100数据集。XLM-R只使用单语种语料,训练目标也只有MLM一个。 Tokenizer换成了sentence piece算法,在构建时也进行了采样,并且调整了系数使得各语言更加平衡。模型层面去掉了language embedding,变得更加简洁。我感觉用“重剑无锋”来形容XLM-R再合适不过了。 这篇论文总结了几个影响多语种模型的重要因素,可能会对大家有所启发: 当处理的语种变多的时候模型的能力会下降(嗯,符合常识)。增大模型可以一定程度对抗这种效应。 模型能力主要受词典大小、训练集大小、语种的采样频率影响 增大词典规模可以提高模型性能 sentence piece可以提高模型的通用性 下面这种图可以让大家对这些结论有更直观的印象 最后来看一下XLM-RoBERTa的实力。下表是在XNLI数据集上的结果对比,设定和XLM论文中差不多,其中Devlin et al.指的是mBERT,Lample and Conneau指的是XLM。可以看出XLM-R相比于XLM又前进了一大步。 顺便再提一嘴,论文作者还在GLUE数据集上对比了XLM-R和XLNET、RoBERTa等单语种语言模型,XLM-R超过了BERT-large,略低于XLNET和RoBERTa。也就是说XLM-R不仅获得了多语种能力,而且没有牺牲英文上的水平。 总结一下,从2018年的mBERT到2020年的XLM-R,跨语种预训练语言模型获得了长足的发展,地球语言范围内的巴别鱼指日可待。最近在Kaggle上正在进行一场跨语种文本分类的比赛,如果有想体验XLM最新进展的朋友可以去试试身手。 今天的文章就到这里,下期再见👋

May 11, 2020 · 1 min · Yuanhao

十分钟读懂beam search-2

在上一篇文章中我们介绍了基础版的beam search,这篇文章是对它的一个扩展,可以在模型不改的情况下获得更好的生成结果。今天的介绍围绕的也是一篇蛮新的论文,《The Curious Case of Neural Text Degeneration》,根据这篇论文的版面内容,它应该已经被ICLR 2020接收了。 Beam Search的问题 先解释以下什么要对Beam Search进行改进。因为Beam Search虽然比贪心有所改进,但还是会生成出空洞、重复、前后矛盾的文本。如果你有文本生成经验,一定对这些现象并不陌生。在语言模型还不像如今的BERT、GPT这么厉害的时候,这种现象更加明显。 没有经验也没关系,我们来看一个论文里面的例子。输入模型的引文(context) “The study, published in the Proceedings of the They were cattle called Bolivian Cavalleros; they live in a National Academy of Sciences of the United States of remote desert uninterrupted by town, and they speak huge, America (PNAS), was conducted by researchers from the beautiful, paradisiacal Bolivian linguistic thing. They say, Universidad Nacional Autónoma de México (UNAM) and...

March 23, 2020 · 4 min · Yuanhao

十分钟读懂beam search-1

最近研究了一下用基于BERT的encoder-decoder结构做文本生成任务,碰巧管老师昨天的文章也介绍了以生成任务见长的GPT模型,于是决定用两篇文章大家介绍一下在文本生成任务中常用的解码策略Beam Search(集束搜索)。 解码及贪心搜索 生成式任务相比普通的分类、tagging等NLP任务会复杂不少。在生成的时候,模型的输出是一个时间步一个时间步依次获得的,而且前面时间步的结果还会影响后面时间步的结果。也就是说,每一个时间步,模型给出的都是基于历史生成结果的条件概率。为了生成完整的句子,需要一个称为解码的额外动作来融合模型多个时间步的输出,而且使得最终得到的序列的每一步条件概率连乘起来最大。 在文本生成任务中,每一个时间步可能的输出种类称为字典大小(vocabulary size,我们用$v$表示),进行T步随机的生成可能获得的结果总共有$v^T$种。拿中文文本生成来说,$v$的值大约是5000-6000,即常用汉字的个数。在如此大的基数下,遍历整个生成空间是不现实的。 最容易想到的策略是贪心搜索,即每一个时间步都取出一个条件概率最大的输出,再将从开始到当前步的结果作为输入去获得下一个时间步的输出,直到模型给出生成结束的标志。例如下图,每一个时间步都取出了条件概率最大一个结果,生成了序列[A,B,C]。 很明显,这样做将原来指数级别的求解空间直接压缩到了与长度线性相关的大小。由于丢弃了绝大多数的可能解,这种关注当下的策略无法保证最终得到的序列概率是最优的。 Beam Search 而beam search是对贪心策略一个改进。思路也很简单,就是稍微放宽一些考察的范围。在每一个时间步,不再只保留当前分数最高的1个输出,而是保留num_beams个。当num_beams=1时集束搜索就退化成了贪心搜索。 下图是一个实际的例子,每个时间步有ABCDE共5种可能的输出,即$v=5$,图中的num_beams=2,也就是说每个时间步都会保留到当前步为止条件概率最优的2个序列。 在第一个时间步,A和C是最优的两个,因此得到了两个结果[A],[C],其他三个就被抛弃了; 第二步会基于这两个结果继续进行生成,在A这个分支可以得到5个候选人,[AA],[AB],[AC],[AD],[AE],C也同理得到5个,此时会对这10个进行统一排名,再保留最优的两个,即图中的[AB]和[CE]; 第三步同理,也会从新的10个候选人里再保留最好的两个,最后得到了[ABD],[CED]两个结果。 可以发现,beam search在每一步需要考察的候选人数量是贪心搜索的num_beams倍,因此是一种牺牲时间换性能的方法。 以上就是Beam Search的基本概念,下面我们解析一种高效率实现方式。 Beam Search代码解析 Beam Search的原理虽然简单,但实际实现的时候却有很多细节要考虑。下面要解析这个实现出自于NLP界著名Python包Transformers,我为了说明方便做了一些改动。 一个正确且高效的算法需要处理的问题大概有两个: 充分利用硬件,可以处理批量数据,且尽量使用并行计算少用循环 处理好长短不同的生成结果 下面是基础版的beam search函数定义。其中context是编码器编码获得的向量,batch_size是每批数据中包含的样本量,bos_token_id是句子开头标志的token id,pad_token_id是用于填充的token id,eos_token_id是句子结束标志的token id。这里给参数填上的默认值和我们后面讲解时使用的例子是一致的。 def beam_search_generate(context, batch_size=3, max_length=20, min_length=2, num_beams=2, bos_token_id=101, pad_token_id=0, eos_token_id=102, ): pass 在函数中主要执行以下三个步骤: 准备初始输入 在当前生成的序列长度未达到max_length时扩展生成序列 准备最终输出的序列 下面我们分别解析。 准备初始输入 # 建立beam容器,每个样本一个 generated_hyps = [ BeamHypotheses(num_beams, max_length, length_penalty, early_stopping=early_stopping) for _ in range(batch_size) ] # 每个beam容器的得分,共batch_size*num_beams个 beam_scores = torch.zeros((batch_size, num_beams), dtype=torch.float, device=encoder_input_ids....

March 20, 2020 · 4 min · Yuanhao