文本生成专题2:常见的摘要生成方法

按照第一篇的计划,这篇文章梳理一下常见的摘要生成方法。大部分方法并不复杂,更多的内容其实包含在seq2seq框架、语言模型、self/cross attention这些模块里。 [TOC] 抽取式摘要 所谓抽取式摘要,有点像之前写过的关键词抽取,就是把原文里重要的部分抽出来作为摘要。 前Transformer时代的方法 有好多基于统计的抽取式摘要生成方法,例如jieba里都集成的TextRank。这方面资料很多,大家搜搜就有。 Transformers-based方法 比较典型的工作是BERTSum,其结构如下图。相比原始BERT,几个主要的变化是 在每个句子前面增加[CLS]token,后续用他们对应的隐向量作为句子表征; 把BERT原有的token type改变成了0/1相间的形式; 在得到句子表征后,又增加了一个称为Summarization Layers的Transformer/LSTM模块,用户在句子表征间做交互。 最后对于每句话输出一个应该包含进摘要的概率,最终结果由得分top3句子产生。 来看一下BERTSum的表现,如下图,总体还是不错的。可以发现加上所谓的Summarization Layers模块并没有很明显的提升,预训练语言模型大部分时候确实很强,光魔改结构往往收效不大。这篇文章的结构我感觉很工整,句子前加[CLS]的操作给人一种细腻的感觉。 生成式摘要 生成式摘要的大体框架很久都没有变过了,大概就是下面这张图。左边是一个encoder,用来编码原文,右边是个decoder,用来生成摘要。 前Transformer时代的方法 在RNN之后,Transformer出来之前,主要的改进是加入各种各样的attention,原文间,摘要间,原文和摘要间等等。大家可以看出来上面那张图已经是有attention的了。 我个人认为前Transformers时代最特别的一个问题是OOV。有不少工作是针对这个问题展开的,其中比较有名的是Google的Pointer Generator。对比和上图的区别可以发现,对于next token的预测,概率分布里出现了"2-0"这个从原文copy出来的词(也是不属于词典的词,是没有copy mechanism之前不可能被生成的词)。真的是要感谢subword tokenizer的广泛使用,让大家省去了很多类似的dirty work。 目前主流的方法 目前的encoder-decoder transformer早已把各种attention玩到登封造极的程度,原文、生成结果间相互的联系已经大大加强。这几年的提升很多都是来自于非结构方面,例如BART用一种新颖的预训练方法来提高,GPT用超大语言模型来提高等。摘要生成逐渐成为了一个跟随语言模型水涨船高的领域(调参调结构当然也有用,但至少大的提升我认为是这样)。 近期刷榜方法 如果大家有关心今年的ACL,会发现摘要相关的论文很多,前段时间还看到丕子老师发微博感叹。不仅数量多,今年在CNN/Dailymail数据集上还有个不小的涨幅,在本文的最后一起来看下是什么神奇的方法。 近几年的刷榜方法我认为可以总结为更加充分地挖掘数据集提供的信号,同时在模型上结合生成模型和判别模型。 我们先从一篇直白的论文Abstractive Summarization with Combination of Pre-trained Sequence-to-Sequence and Saliency Models讲起。这篇论文把原文和摘要中都出现的token认为是重要token,用这个作为监督信号,训练了一个重要性模型(saliency models)。然后尝试了多种组合方式来在解码器上使用重要性模型产生的辅助信号。 这里解释一下里面出现的几种方式: SE,Selective Encoding:用重要性得分来控制编码器输出 SA,Selective Attention:用重要性得分来控制解码器cross attention SEG, Sentence Extraction then Generation:相当于精简原文输入 CIT, Conditional Summarization Model with Important Tokens:把重要的Token选出来跟原文一起输入编码器 来看一下各种方式的表现,只是单独增加一个siliency model训练任务(MT)就提高了1个点的R1,CIT表现也不错,提升接近两个点。 有了上面这篇文章作为基础,我们来看下目前的SOTA,BRIO: Bringing Order to Abstractive Summarization,他们组其实工作是一脉相承的,感兴趣可以看下他们之前的论文GSum: A General Framework for Guided Neural Abstractive Summarization和SimCLS: A Simple Framework for Contrastive Learning of Abstractive Summarization。...

July 3, 2022 · 1 min · Yuanhao

文本生成专题1:基础知识

大家好,好久不见,疫情封控在家两个月写文章都不利索了😂。 在这段时间我反思了一下之前写的东西,基本是最近用了什么、看到什么就写什么,感觉系统性比较差。后面我打算少写一些零散话题,多总结一些更有体系的内容。第一个小专题我想总结一下我最近关注比较多的领域,文本生成。文本生成领域很广泛,我主要会聚焦在文本摘要(Text Summarization)和数据驱动生成(Data2Text)。 这篇文章是专题第一篇,将介绍以下的内容: [TOC] 除了第二部分外都比较像科普文,没有相关技术背景的朋友也可以看懂。 问题定义和数据集 摘要 摘要这个问题比较好理解,就是把长的文章,例如学术论文、新闻等等缩写成更短的文本,并且保留重要的信息。 摘要领域常见的典型数据集CNN/DailyMail, arXiv, Pubmed, XSUM等。其中CNN/DailyMail的原始文本是大约几百个词的新闻,摘要(ground truth)是人写的,大概五六十个词。中间两个都是来自学术论文的数据集,原始文本比新闻长不少。学术论文通常都需要作者提供摘要,一般一百来个词,天然适合拿来做摘要的数据集。X-SUM是里面摘要长度最短的数据集,基本是一句话的长度。还有一些数据集,大家可以参考papwerswithcode。 数据驱动生成 数据驱动生成则是给定一些结构化的数据,例如餐馆信息、实体间的关系等,生成一段自然语言。 这个领域典型的数据集有WebNLG和E2E。WebNLG的每条样本会提供一系列用三元组描述的实体及关系,以及一段陈述三元组表达事实的自然语言文本作为标签。 E2E数据集则提供了成对的餐馆结构化信息和自然语言描述。自然语言描述相比于WebNLG数据集更简短一些。更多数据集大家参考这个页面。 常用的评价指标 除了数据集,要理解一个技术的发展水平,另一个很重要的方面是理解评价指标。评价机器生成的文本,最常用的指标是ROUGE和BLEU。 ROUGE 摘要里最常用的指标是ROUGE,它的全称是Recall-Oriented Understudy for Gisting Evaluation,是在2004年的论文ROUGE: A Package for Automatic Evaluation of Summaries里提出的。从名字可以看出来它比较关注recall。它有很多形式,在论文里比较常看到的有ROUGE-N(N=1,2,3…)和ROUGE-L两种。 对于ROUGE-N,计算方式就是生成结果和参考文本中都出现的ngram占参考文本ngram的比例。ROUGE-L比较麻烦,需要考虑最长公共子串,但相比于预设ngram大小的ROUGE-N有一定的优势。单句的ROUGE-L是最长子串长度除以参考句的长度,举一个论文里的例子 S1. police killed the gunman S2. police kill the gunman S3. the gunman kill police 假设S1是参考句,那S2和S3的ROUGE-2都是1/3(匹配上了the gunman),但S2的ROUGE-L是3/4比S3的2/4大,实际情况确实是S2更好一些。 可以看出ROUGE,特别是ROUGE-N是比较考察和参考文本用词的一致性的,理论上不是个语义上的评价,这也和后面会写到的一些trick有直接的关联。 ROUGE指标的python实现可以参考这个repo,看代码应该是是最清楚的。 BLEU 在Data2Text领域常用的指标是BLEU,全称是bilingual evaluation understudy,从名字也能看出来,最开始是在机器翻译的评价里被广泛使用。BLEU像是一个precision指标,基本是在算生成结果和参考文本都出现的词和参考文本长度的比值。主要考虑的问题是多次匹配,例如 candidate:ha ha ha reference: only saying ha is not good candidate只有一种词,且在标签中出现了,但若BLEU是100分,显然是不合理的。因为ha在reference中只出现一次,所以只能匹配一次,所以BLEU是1/3。 另一个要解决的问题是防止candidate过短而导致的高分。因为precision的分母是自己ngram的数目,只输出有把握的词是可以提高分数的。这里引入了一个叫brevity penalty的参数。这个参数的计算公式如下:...

May 25, 2022 · 2 min · Yuanhao

面向Meta全公司工程师的AI优化平台解析

原作者:Igor Markov, Norm Zhou 人工智能是使现代软件系统和产品尽良好运行的一个重要部分,从改善用户体验到使计算基础设施更有效率都能看见AI的影子。无论是减少延迟,提高视频流的质量,还是精简界面以满足特定人的需求,今天的人工智能往往比人类精心构建的启发式策略更有效。但是,为了在我们的产品中更有效地利用人工智能,我们需要解决几个挑战:系统必须适应没有机器学习背景的软件工程师;它必须提供机制,为许多不同的产品目标进行优化,这可能不同于封闭形式的机器学习损失函数;它必须区分数据中的因果关系;它必须有效地扩展,以训练、托管和监测大量的人工智能模型。 为了满足Meta公司的这些需求,我们建立了一个端到端的人工智能平台,名为Looper,具有易于使用的优化、个性化和反馈收集的API。Looper支持整个机器学习的生命周期,从模型训练、部署和推理一直到产品的评估和调整。与其围绕人工智能模型重建我们现有的产品,Looper使我们能够升级它们,使用人工智能进行个性化优化。Looper平台目前承载了700个AI模型,每秒产生400万个AI输出。 让智能策略为应用程序所用 Meta的不同服务每天有数十亿人在使用,每个人都有不同的兴趣和偏好。Looper使我们能够以前所未有的规模定制其中的许多 “开箱即用 “的服务,而不需要复杂的专业代码。 让使用产品的人在用户界面菜单上有几十个选择,会使产品失去吸引力,无论它提供多少价值。但不同的人对菜单的偏好是不同的。同样,适时地将可能被用户浏览的内容预取到移动设备上,可能会极大地改善我们产品的用户体验,但要做到这一点而不使设备的硬件资源不堪重负,需要准确地预测什么会是最感兴趣的。 为了以可扩展的方式支持实时智能策略,Looper提供了几个功能。 Looper的目标是为具有适度数据规模和模型复杂性的用例提供易用性和快速部署模型。 它支持各种模型类型,托管和训练众多模型和决策策略。 它通过使用监督学习或强化学习,支持广泛的机器学习任务(分类、估计、价值和序列预测、排序、planning)。结合模型管理基础设施,我们的自动化工具(AutoML)选择模型和超参数以平衡模型质量、大小、推理时间等。Looper涵盖了从数据源到产品影响的范围,通过因果实验进行评估和优化。 它是一个声明式的人工智能系统,这意味着产品工程师只需要声明他们想要的功能,系统就会根据声明来填充软件的实现。在内部,Looper依赖于我们的策略蓝图抽象,它将特征、标签、模型和决策策略的配置合二为一,并维护这种联合配置的多个版本。这支持更全面的优化,捕捉不同版本之间的兼容性,并实现智能策略的整个生命周期的免编码管理。蓝图能够使用强大的实验优化系统对黑盒产品指标进行垂直优化。 其他人工智能平台通常以批处理模式进行离线推理,而Looper则是实时操作。 许多人工智能系统使用统一的数据工作,如像素或文本,但不同的产品往往有非常不同的元数据,往往来自不同的来源。此外,元数据的模式变化很快,需要定期在新数据上重新训练人工智能模型。 A/B测试,以评估许多不同类型的模型和决策规则,包括那些由上下文bandit使用的模型,以模拟一个或多个目标的预测的不确定性;或强化学习,以优化长期、累积的目标。 与传统的端到端人工智能系统不同,Looper使Meta公司的工程师和其他人能够跟踪一个模型在软件栈中的实际使用情况,并对建模框架的所有方面进行实验–从指标选择到策略优化的所有过程。为了做到这一点,Looper将常见的端到端定义扩展到软件层,这样,模型架构、特征选择参数可以在模型质量和计算资源之间进行多目标权衡优化。为了优化长期的产品目标,工程师可以调整在做实时决策时对不同输入的重视程度。我们的平台使得使用应用于整个管道的AutoML技术来优化这些和其他参数成为可能。 用于部署智能策略的Looper平台 与用于视觉、语音和自然语言处理的重量级人工智能模型不同的是,Looper使用的是可以重新训练并在共享基础设施上快速大量部署的模型,这些模型有利于离线推理和批量处理。我们的平台将用户互动和系统互动的元数据解释为监督学习的标签或强化学习的奖励。 Looper追求的是快速上线、稳健部署和低能耗的多种智能策略的维护,其中的积极影响是直接在应用方面进行测量和优化。应用程序代码与平台代码分离,Looper利用现有的水平AI平台,如PyTorch和Ax,为机器学习任务提供可互换的模型。 为了使智能策略获得成功,我们需要一种方法来评估它们,并在结果不够好时加以改进。这种评估是基于产品指标进行的。在某些情况下,每个决策都可以被检查,因此,好的和差的决策可以作为智能策略学习的例子(通过监督学习)。然而,有些产品指标追踪的是长期目标(如每日活跃用户),无法追踪到具体的决策。这两种情况都可以由Looper来处理,而使用实时数据则尤为重要。访问Meta的监控基础设施有助于发现不可预见的副作用。在我们的平台上,产品开发者定义决策空间,允许平台自动选择模型类型和超参数设置。在不影响用户的情况下,对模型进行训练和评估,并对其进行改进,直至可以部署。在产品使用前,新训练的模型会被关起来(部署在影子流量上)–这种模型在记录的特征和观测值的抽样子集上进行评估,并计算出离线质量指标(例如回归任务的MSE)。这有助于避免在部署较新的模型时降低模型质量。 智能策略的应用和影响 我们的垂直机器学习平台承载了来自水平平台的中等规模的模型,以便改善软件系统的各个方面。这些模型的部署只需很少的工程努力,并且不需要特定模型的基础设施来维护。Looper目前被Meta公司的90多个产品团队使用,这些团队部署了690个模型,每秒进行400万次预测。 应用案例可分为五类,按频率递减排列: 个性化体验是根据用户的参与历史而定制的。例如,一个产品可能只向那些可能使用它的人突出显示与购物有关的内容(但这种内容所有用户都可以通过菜单访问)。 排名对项目进行排序,以提高用户的效用,例如,为浏览者提供个性化的候选项目。 根据预测的使用可能性,预取/预计算数据/资源(4.1节)。 通知/提示可以只发送给认为有帮助的用户。 值估计预测回归任务,例如,数据查询的延迟或内存使用。 下图按资源类别对活跃的Looper用例的资源消耗(Y轴上的服务器数量)进行了比较。 各个产品团队的人工智能专业知识各不相同,从初学者到经验丰富的人工智能工程师都有。而使用Looper平台的团队中只有15%为人工智能工程师。对于没有生产人工智能经验的团队来说,一个易于使用的人工智能平台往往是采用的决定性因素,而人工智能的投资在证明有用后继续进行。我们的平台在高级服务背后处理关于软件升级、日志、监控等问题,并释放出巨大的生产力改进。对于有经验的人工智能工程师来说,智能策略平台通过自动化重复性的耗时工作来提高生产力:编写数据库查询,实施数据管道,设置监控和警报。与专精型的系统相比,它可以帮助产品开发人员推出更多的AI用例。无论之前是否有人工智能经验,成功的平台采用者在短短几天内就配置了最初的机器学习模型,迅速开始收集训练数据,然后在短短几个月内完善他们的模型并推出新产品。 让工程师和产品开发人员更容易实现规模化的人工智能 将产品决策的自我优化智能策略嵌入到软件系统中,从而提高用户体验,优化资源利用,并支持新的功能,这其中存在巨大的机会。我们的人工智能平台Looper解决了产品驱动的端到端机器学习系统的复杂性,促进了智能策略的大规模部署。它在数据可用性、简易配置、明智地使用可用资源、减少工程努力和确保产品影响方面提供了直接、切实的好处。平台采用者尤其被通过因果推理和资源开销测量对产品影响评估的广泛支持所吸引。 Looper使软件工程师更容易获得智能策略,并使产品团队能够以自我服务的方式建立、部署和改进人工智能驱动的能力,而无需人工智能专业知识。我们将继续开发这个平台,以便我们能够以新的方式利用人工智能来改善Meta的产品和服务。

April 24, 2022 · 1 min · Yuanhao

做NLP?Don't stop pretraining!

应该很多朋友知道,在训练下游任务之前先在任务的语料上做一下非监督的masked language model任务预训练可提高目标任务的性能。特别是当下游任务的标注数据少,相关语料多的情况下这个小技巧带来的提升更大。举个例子,假设你要做一个恶意评论分类器,但由于时间和成本关系,只标注了几万条评论,但系统里的评论已经有几百万条,这时候先在所有评论上做个MLM训练,再finetune恶意评论分类任务就是个比较好的选择。 这个问题多年前论文Don’t Stop Pretraining: Adapt Language Models to Domains and Tasks做了比较详细的探讨。 首先是个很好理解的现象,如下图所示,虽然现代化的Transformer语言模型都是由海量数据训练的,但难免跟我们目标任务的语料领域无法完全重叠 论文还做了定量的分析,它们选了几个领域,然后抽样了每个领域最高频的一万个token,看下重合度,发现确实不高。重合度最高的是新闻,那是因为Roberta训练的语料里其实就有新闻。 那既然如此,就在目标任务所在领域语料上继续做一把预训练(DAPT),然后再finetune目标任务。同样是上面几种领域的任务,发现经过DAPT之后都有明显提高,上面重合度最低的CS领域提升最明显。最后一列是个比较有意思的实验,它是为了排除单纯增加了训练数据带来的性能提升,选了一个非目标任务所在领域来进行预训练(数据同样变多,但领域和目标任务无关)。结果大多没提升,有些还下降了。这就说明在目标任务领域做预训练确实有效果! 这个论文后面还有不少内容,但我感觉对一般场景有些overkill,就不写了,有兴趣的朋友可以自己看。下面来给大家演示一下怎么用目前主流的transformers库来做MLM,相当简单,可以说是开箱即用。 首先你需要安装Transformers库,然后在transformers/examples/pytorch/language-modeling/目录下面找到run_mlm.py文件,把这个文件复制一份到你的工程目录。 为了做MLM训练,你需要准备好一些文本数据,将他们以一行一个样本的格式写在一个文本文件里,为了可以监控训练的进程,最好是像平常做其他机器学习任务一样准备一个训练集,一个验证集。但由于是MLM,验证集不需要太多。 准备好代码和数据之后就可以来运行这个脚本了,有三部分参数需要指定 模型参数 必须的模型参数只有一个,即model_name_or_path,即你要使用的基础模型。给这个参数是最方便的,tokenizer等组件会配套使用。你也可以参考代码来精细控制每个组件。 数据参数 train_file,即训练数据路径 validation_file,即验证数据路径 max_seq_length,最长的序列长度,不给的话会使用tokenizer的默认最大长度 mlm_probability遮蔽比例,默认是15%,之前陈丹琦组的论文说增大比例可以提高性能,但目前似乎还有争议 line_by_line,因为我们的数据是line by line的,所以这个要设置为True 训练参数。这部分参数有很多,可以参考这个文件。比较推荐设置的有以下几个 output_dir,这个必填,训练后模型保存的地址 do_train,这个必填 do_eval,如果有验证集必填 num_train_epochs,默认为3 fp16,如果你的显卡支持tensor core,那一定要把这个打开 weight_decay,MLM的时候可以给点衰减防止过拟合,常用0.01 per_device_train_batch_size,batch size 最后的成品可能像这样 python run_mlm.py \ --model_name_or_path roberta-base \ --train_file training_corpus.txt \ --validation_file validation_corpus.txt \ --per_device_train_batch_size 8 \ --per_device_eval_batch_size 8 \ --do_train \ --do_eval \ --fp16 \ --weight_decay 0.01 \ --line_by_line \ --output_dir ....

April 20, 2022 · 1 min · Yuanhao

还在用RoBERTa?快来看看DeBERTa吧!

如果你现在不知道DeBERTa,那相当于你在2018年不知道BERT ——多头注意力 DeBERTa模型是微软在2021年提出的,首发在ICLR 2021上,到现在其实已经迭代了三个版本。第一版发布的时候在SuperGLUE排行榜上就已经获得了超越人类的水平,如今也成为了Kaggle上非常重要的NLP Backbone(BERT感觉已经没什么人用了)。比较奇怪的是,似乎这个模型被大家讨论并不多,于是最近看了两篇相关论文DeBERTa: Decoding-enhanced BERT with Disentangled Attention和DeBERTaV3: Improving DeBERTa using ELECTRA-Style Pre-Training with Gradient-Disentangled Embedding Sharing学习了一下。 DeBERTa 1.0 1.0版本在BERT的基础上有三个主要的改进点: 更加解耦的self attention,上图中右边黄色部分; 考虑绝对位置的MLM任务,上图中Enhanced Mask Decoder; 预训练时引入对抗训练 我认为其中1应该是最重要的,然后是3,2最不重要,因为在后面的3.0版本已经不再使用MLM作为预训练任务了。 Disentangled Attention 第一个改进其实有点“复古”,这里的解耦是将位置信息和内容信息分别/交叉做attention。想当年BERT横空出世时大家都津津乐道地讨论为什么可以把word embedding,position embedding加起来做注意力,没想到没过几年却又被分开了。当然,DeBERTa的相对位置编码不同于BERT的绝对位置编码,似乎也不好直接比较。 论文里定义了一个相对位置embedding P,和一个相对距离函数$\delta(i,j)$,除了和标准transformers一样的内容QKV,计算了相对位置QK,分别为$Q_r=PW_{q,r}$,$K_r=PW_{k,r}$。注意力矩阵的计算变成了 $$A_{i,j}={H_i,P_{i|j}}\times{ H_j,P_{j|i}}^T=H_iH_j^T+H_iP_{j|i}^T+P_{i|j}H_j^T+P_{i|j}P_{j|i}$$ 第一项是常规的内容自注意力(content-to-content),第二第三项分别是content-to-position和position-to-content,第四项论文里认为不重要,直接省略了。具体看是下面这个公式 $$A_{i,j}=Q^c_i{K^c_j}^T+Q^c_i{K_{r,\delta(i,j)}}^T+K_j^c{Q_{r,\delta(j,i)}}^T$$ 这一部分其实看一下代码也比较清晰。 SiFT 对抗训练也是NLPer经常使用的技术了,在做比赛或者公司业务的时候我一般都会使用FGM对抗训练来提升模型的性能。DeBERTa预训练里面引入的对抗训练叫SiFT,比FGM复杂一些,他攻击的对象不是word embedding,而是embedding之后的layer norm。整个过程需要forward 3次,亲测比FGM慢一些。微软已经把代码放出,大家可以参考,在自己的任务里试一试。 DeBERTa 2.0 2012年2月放出的2.0版本在1.0版本的基础上又做了一些改进: 更换tokenizer,将词典扩大了。从1.0版的50k扩成了128k。这个扩大无疑大大增加了模型的capacity。 在第一个transformer block后加入卷积。这个技巧在token classification、span prediction任务里经常用到。 共享位置和内容的变换矩阵 把相对位置编码换成了log bucket,各个尺寸模型的bucket数都是256 这些变化里1和2是把模型变大,3和4是把模型变小。总的效果是V2版本模型比V1版本变大了。 2.0版几个变更对模型的影响,增大词典效果最显著 DeBERTa 3.0 2021年11月微软又放出了3.0版本。这次的版本在模型层面并没有修改,而是将预训练任务由掩码语言模型(MLM)换成了ELECTRA一样类似GAN的Replaced token detect任务。因为多了个生成器,DeBERTa 3.0的论文中也更多的是对不同的embedding sharing的探讨,下面这种图是对文中对比的三种方式的简介。 3.0论文探讨的集中参数更新方式 根据下图所示论文的结果,3.0的改进进一步提升了DeBERTa模型的性能(实际并不是所有任务都有提升)。DeBERTa-v3也确实成为了Kaggle上最常见的DeBERTa版本。 DeBERTa 3....

April 16, 2022 · 1 min · Yuanhao