S:Sparse Softmax(新设计的 Softmax 替代品); P:Pretraiend Language Model(预训练模型); A:Abstractive(抽象式,即生成式); C:Copy Mechanism(新设计的 Copy 机制); E:Extractive(抽取式) S:Special Words(将特殊词添加到预训练模型)。 很显然,这是笔者“煞费苦心”强行拼凑的.

数据集:

这次比赛官方共提供了 9484 个标注样本,以“(原文, 摘要)”这样的数据对形式出现,原训练数据还附带了其他的一些辅助标注信息,但为了模型的通用性,我们没有用这些辅助信息,所以我们的模型原则上适用于所有单条样本格式为“(原文, 摘要)”的监督式摘要任务。

下面是训练数据的一些统计信息:

1、总量:9484; 2、输入:平均字数 2568,字数标准差 1122,最大字数 13064,最小数字 866; 3、输出:平均字数 283,字数标准差 36,最大字数 474,最小数字 66; 4、指标:以词为单位的加权 Rouge。

因此,简单来说这大概就是一个“输入 3000 字、输出 300 字”的文本生成任务,其难度在于两千多的平均长度远远超出了我们平时处理的文本长度。

抽取模型

这一节我们将对抽取模型部分做一个简要介绍。抽取模型的思路是先通过规则将原始的生成式语料转化为序列标注式语料,然后用笔者常用的 DGCNN 模型来建模。

2.1 语料转换

首先,我们需要记住的是,抽取模型只是过程而不是结果,我们还要把抽取的结果送入到 Seq2Seq 模型优化。因此,抽取模型的原则是“求全”,即尽量把最终摘要所需要的信息覆盖到。为此,我们按照如下规则将原始训练语料转换为抽取式语料。

1、自行构建分句函数,使得句子的颗粒度更细; 2、人工摘要的每个句子,都在原文中匹配与之相似度最高的那个句子(可以重复匹配); 3、将所有匹配到的原文句子作为抽取句子标签; 4、删掉部分匹配出来的句子,使得与人工摘要的 Rouge 得分最高。

注意,我们在最终模型中删掉了第 4 点,而它本来是我们最初版模型的默认选择。事实上,加上第 4 点有利于提高抽取模型的指标,但是综合生成模型后最终得分反而下降了。

这不难理解,生成模型本来有删改功能,而且比抽取模型做得更好;如果抽取模型意外地把本应该抽取的关键句子删掉了的话,那么生成模型就很难把它恢复出来了,从而导致性能下降。也就是说,第 4 点不满足抽取模型的“求全”原则,我们应该把删改工作教程生成模型来做,不应该放到抽取模型中。

2.2 指标问题

上述转换流程涉及到一个“相似度”的选择,根据前面的介绍,本次比赛选择“以词为单位的加权 Rouge”作为评测指标,因此我们可以直接选择这个加权 Rouge 作为相似度指标。事实上,我们一开始确实是这样做的,但是后来在调试的时候发现,这样并不是一个好的选择,我们最终选择的是“以字为单位的加权 Rouge”。

这两者有什么区别呢?对于以词为单位来算评测指标的做法,我们也不难理解其目的,就是为了使得专有名词能够完全匹配上。比如本来是“中华人民共和国未成年人保护法”,你预测成了“中华人民共和国文物保护法”,如果以字为单位的话,最长公共子序列为“中华人民共和国xxx保护法”,至少还是算对了大部分,但是如果以词为单位的话,两者就是不同的词,因此算全错。因此,以词为单位有利于专有名词匹配得更精准

然而,以词为单位会带来一个严重的副作用,那就是降低了长词的权重。比如“根据 《 中华人民共和国未成年人保护法 》 的 有关 规定”中,核心词“中华人民共和国未成年人保护法”的权重仅为 1,剩下的“根据”、“《”、“》”、“的”等我们认为无关紧要的词权重分别都为 1,占了大部分,这样一来,模型宁愿去匹配“根据”、“《”、“》”、“的”等词,也不愿意去拟合核心词“中华人民共和国未成年人保护法”了。说白了,以词为单位的话,得分高的摘要未必是有什么关键信息的摘要。 

那怎么调和两者呢?事实上,最好的方案应该还是以词为单位,但是算指标的时候,按照字数跟每个词加权,比如“中华人民共和国未成年人保护法”,匹配不上就给 0 分,匹配对了就给 14 分(因为有 14 个字)而不是 1 分才好。不过,这需要自己来实现 Rouge 计算函数,有点麻烦,我们最终是直接选择以字为单位来算加权 Rouge,这也勉强够用,因为在转换语料的时候,我们知道摘要和原文都是在描述同一件案子,因此基本不会出现“中华人民共和国未成年人保护法”预测成“中华人民共和国文物保护法”的情况。

2.3 模型结构

回到模型方面,我们使用的是以句为单位的序列标注模型作为抽取模型,句向量部分用“BERT+平均池化”来生成,并固定不变,标注模型主体方面则用 DGCNN 模型构建。关于 DGCNN 模型,请参考基于 CNN 的阅读理解式问答模型:DGCNN、开源一版 DGCNN 阅读理解问答模型(Keras版)[2] 、基于DGCNN和概率图的轻量级信息抽取模型等。

图片

▲ SPACES的抽取模型示意图

值得指出的一个细节是,在训练抽取模型的时候,我们是以 0.3 为阈值做 EarlyStop 的,但最终以  0.2  为阈值构建生成模型的数据,依据还是前面说的抽取模型的原则是要“求全”。

2.4 输出数据

我们需要将原文作为输入,通过抽取模型输出抽取摘要,然后把抽取摘要作为生成模型的输入,来输出最终摘要。但是,这有一个问题,训练的数据我们都是见过的,但我们真正预测的是未见过的数据,如果直接训练一个抽取模型,然后用该模型抽取训练集的摘要,那么很明显由于都被训练过了,抽取出来的摘要分数肯定会偏高,而新样本的效果则会偏低,造成训练预测的不一致性。

这时候的解决方案就是交叉验证了。具体来说,我们将标注数据分为 n 份,其中 n-1 份训练抽取模型,然后用这个抽取模型预测剩下的那份数据的抽取摘要,如此重复 n 遍,就得到全部数据的抽取摘要,并且尽可能地减少了训练和预测阶段的不一致性。

生成模型

生成模型是我们投入主要时间的部分,也是我们的主要贡献点。生成模型就是一个Seq2Seq 模型,以抽取模型的输出结果作为输入、人工标注的摘要作为输出进行训练,我们可以理解为是对抽取结果做进一步的“润色”。

3.1 模型总览

如果用一张图概括我们的生成模型,那么大概如下:

图片

▲ SPACES的生成模型示意图

接下来我们会介绍模型的各个模块。

3.2 基础架构

Seq2Seq模型依然选择了经典的UniLM(参考从语言模型到 Seq2Seq:Transformer 如戏,全靠 Mask),并且考虑到“输入+输出”的总长度基本上都超过 512 了,所以选择华为的 NEZHA 模型作为基础模型架构,因为 NEZHA 使用了相对位置编码,不限长度。

当然,这是当时的选择,现在的话我们至少还有如下两个选择:

1、参考层次分解位置编码,让 BERT 可以处理超长文本中的直接延拓绝对位置编码的做法,使得 BERT 有能力直接处理更长序列(理论上可达 26 万),自然也可以用于“BERT+UniLM”中;

2、使用那个屠榜的 T5 模型,现在可以在中文上玩玩了 [3] 的多国语言版 T5 模型(mT5),它用的也是相对位置编码,不限长度,但要注意 T5 用的 tokenizer 会将全角逗号转为半角逗号,这会导致评测分数下降。

此外,在使用预训练模型方面,我们首创地将部分词语加入到了 NEZHA 模型中,改变了中文预训练模型以字为单位的通用选择,这使得模型的效果和速度都有一定的提升。这部分结果已经发布在之前的文章提速不掉点:基于词颗粒度的中文 WoBERT [4] 之中,读者可以移步参考。

3.3 BIO Copy

Copy机制在摘要生成模型中并不新鲜,甚至可以说已经成为了生成式摘要的标配了。常规的 Copy 机制一般就是 PointerNet [5] 的做法,但这种做法有两个不足之处:1)每次只能 Copy 一个 token,不能保证 Copy 一个连续片段(n-gram)出来;2)实现起来比较复杂,不够即插即用。为此,我们构思了一种新型的 Copy 机制,暂时称为 BIO Copy,它实现起来非常简单,而且具有 Copy 连续片段的能力。

其实前面的图示已经展示了这种 Copy 机制,它其实就是在 Decoder 部分多加一个序列预测任务,即原来 Decoder 建模的是每个 Token 的分布 ,现在多预测一个标签分布,变为:

图片

其中 ,含义如下:

B:表示该 token 复制而来; I:表示该 token 复制而来且跟前面 Token 组成连续片段; O:表示该 token 不是复制而来的。

那么,训练时 z 的标签哪里来呢?这里直接采用一种比较简单的方法:算摘要与原文的“最长公共子序列”,只要是出现在最长公共子序列的 token,都算是 Copy 过来的,根据 BIO 的具体含义设置不同的标签。比如前面图片中的例子,“我 真的 非常 热爱 我 的 祖国”与“我 爱 我 的 祖国”的最长公共子序列“我 我 的 祖国”,其中第一个“我”是单字,标签为 B,后面“我 的 祖国”是一个连续片段,标签为“B I I”,其他标签为 O,所以总的标签为“B O B I I”。

所以,在训练阶段,其实就是多了一个序列预测任务,并且标签都是已知的,实现起来很容易,也不增加什么计算成本。至于预测阶段,对于每一步,我们先预测标签 z_t,如果 z_t 是 O,那么不用改变,如果 z_t 是B,那么在 token 的分布中 mask 掉所有不在原文中的 token,如果 z_t 是 I,那么在 token 的分布中 mask 掉所有不能组成原文中对应的 n-gram 的 token。也就是说,解码的时候还是一步步解码,并不是一次性生成一个片段,但可以通过 mask 的方式,保证 BI 部分位置对应的 token 是原文中的一个片段。

需要指出的是,Copy 机制的引入未必能明显提高分数,印象中好像只提升了 0.5% 左右,但是 Copy 机制可以保证摘要与原始文本的忠实程度,避免出现专业性错误,这在实际使用中是相当必要的。

3.4 稀疏Softmax

在这次比赛中,我们还发现了一个 Softmax 及交叉熵代替品,我们称之为 Sparse Softmax,我们发现 Sparse Softmax 可以在相当多的分类问题(包括常规分类问题和文本生成等)中替换掉 Softmax,并且效果能得到一定的提升。

Sparse Softmax的思想源于 From Softmax to Sparsemax: A Sparse Model of Attention and Multi-Label Classification [6]、Sparse Sequence-to-Sequence Models [7] 等文章,里边作者提出了将 Softmax 稀疏化的做法来增强其解释性乃至提升效果。但笔者嫌里边的设计太麻烦,于是自己想了一个更简单的版本:

图片

其中  是将  从大到小排列后前 k 个元素的下标集合。说白了,我们提出的 Sparse Softmax 就是在计算概率的时候,只保留前 k 个,后面的直接置零,k 是人为选择的超参数,这次比赛中我们选择了 k=10。在算交叉熵的时候,则将原来的对全体类别  操作,改为只对最大的 k 个类别进行,其中 t 代表目标类别。

为什么稀疏化之后会有效呢?我们认为这是因为避免了 Softmax 的过度学习问题。假设已经成功分类,那么我们有 (目标类别的分数最大),此时我们可以推导原始交叉熵的一个不等式:

图片

假设当前交叉熵值为 ,那么解得:

图片

我们以  为例,这时候 ,那么 。也就是说,为了要 loss 降到 0.69,那么最大的 logit 和最小的 logit 的差就必须大于 ,当 n 比较大的时候,对于分类问题来说这是一个没有必要的过大的间隔,因为我们只希望目标类的 logit 比所有非目标类都要大一点就行,但是并不一定需要大  那么多,因此常规的交叉熵容易造成过度学习而导致过拟合,而截断之后就不会有这个问题。

在这次比赛中,Sparse Softmax 带来的提升可能(没有细测)有 2% 左右!通过,我们私下还补充做了很多实验,包括 NLP 和 CV 的,发现它在大多数任务上都有 1% 的提升,所以非常欢迎大家尝试!不过,我们也发现,Sparse Softmax 只适用于有预训练的场景,因为预训练模型已经训练得很充分了,因此 finetune 阶段要防止过拟合;但是如果你是从零训练一个模型,那么 Sparse Softmax 会造成性能下降,因为每次只有 k 个类别被学习到,反而会存在学习不充分的情况(欠拟合)。

3.5 其他细节

在训练生成模型的时候,我们加入了 EMA(权重滑动平均),这能使得训练过程更加稳定,甚至可能提升模型效果。事实上,EMA 基本是笔者打比赛的标配,它能让我们省一些调试训练策略的心。

其外,在谈到 BIO Copy 机制时,我们说到理论上只需要在 Decoder 处新增一个 BIO 预测,不过在实际训练的时候,我们同时在 Encoder 和 Decoder 处都加了,我们发现这样能提升模型的最终效果。直观来想的话,起作用的原因应该是同时加的话增强了 Encoder 和 Decoder 之间的同步性,能够引导 Decoder 更精准地 Attention 到 Encoder 的合理的位置。

至于其他要补充的,还在想,想到了再补充吧。

代码开源

SPACES 模型的源码已经发布在 Github 上:

SPACECS: https://github.com/bojone/SPACES

使用说明在 Github 上也有介绍,这里就不重复了,有问题可以提 issue 或者留言。开源是技术进步的动力,在非利益相关的情况下,笔者会尽量做到开源,也鼓励大家开源。