文本摘要方法

所谓摘要,就是对给定的单个或者多个文档进行梗概,即在保证能够反映原文档的重要内容的情况下,尽可能地保持简明扼要。质量良好的文摘能够在信息检索过程中发挥重要的作用,比如利用文摘代替原文档参与索引,可以有效缩短检索的时间,同时也能减少检索结果中的冗余信息,提高用户体验。随着信息爆炸时代的到来,自动文摘逐渐成为自然语言处理领域的一项重要的研究课题

一. 技术路线

1.1 TF-IDF

《Term Weighting Approaches in Automatic Text Retrieval》

导言:一种统计方法,用以评估一个词对于一个文件集或一个语料库中的其中一份文件的重要程度。其是由两个算法相乘而来,即词频(TF)乘以 逆文档频率指数(IDF)。其中词频表示一个词的常见程度,逆文档频率表示一个词的稀有程度。其基本原理是,字词的重要性随着其在文件中出现的次数成正比增加,但同时会随着其在语料库中出现的频率成反比下降

1.1.1 原理

TF-IDF的主要思想是:如果某个词或短语在一篇文章中出现的频率高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类。其计算公式如下:

TF-IDF=TF×IDF

其中,TF表示词频(Term Frequency)IDF表示逆向文件频率(Inverse Document Frequency)TF表示词在文档d中出现的频率,而IDF的主要思想是:如果包含词t的文档越少,IDF越大,则说明词条t具有很好的类别区分能力。

词频(TF)指的是某一个给定的词语在该文件中出现的频率。这个数字是对词数(term count)的归一化,以防止它偏向长的文件。对于在某一特定文件里的词语来说,它的重要性可表示为:

TF_{i,j}=\frac{n_{i,j}}{\sum_kn_{k,j}}

其中分子是该词在文件中的出现次数,而分母则是在文件中所有字词的出现次数之和

逆向文件频率(IDF)指的是一个词语普遍重要性的度量。某一特定词语的IDF,可以由总文件数目除以包含该词语之文件的数目,再将得到的商取以10为底的对数得到:

DF_i=lg\frac{|D|}{|j:t_i\in d_j|}

某一特定文件内的高词语频率,以及该词语在整个文件集合中的低文件频率,可以产生出高权重的TF-IDF。因此,TF-IDF倾向于过滤掉常见的词语,保留重要的词语。其计算公式如下:

TF-IDF_{i,j}=TF_{i,j}×IDF_i

1.1.2 理论依据及不足

TF-IDF算法基于假设:对区别文档最有意义的词语应该是那些在文档中出现频率高,而在整个文档集合的其他文档中出现频率少的词语,因此引入TF词频作为测度,就可以体现同类文本的特点;另外考虑到单词区别不同类别的能力,TF-IDF法认为一个单词出现的文本频数越小,它区别不同类别文本的能力就越大,因此引入了逆文本频度IDF的概念,以TF和IDF的乘积作为特征空间坐标系的取值测度,完成对TF权重的调整,其目的在于突出重要单词,抑制次要单词。本质上IDF是一种试图抑制噪音的加权,且单纯认为文本频数小的单词就越重要,文本频数大的单词就越无用,显然并不完全正确。IDF的简单结构并不能有效地反映单词的重要程度和特征词的分布情况,使其无法很好地完成对权值调整的功能,所以TF-IDF法的精度并不是很高。此外,在TF-IDF算法中并没有体现出单词的位置信息,特征词在不同的位置对文章内容的反映程度不同,其权重的计算方法也应不同。

1.1.3 代码实现

使用TF_IDF模型实现文本摘要任务,具体思想如下

  1. 输入原文(长文本),可支持任意长度的文本。

  2. 输入文本经过文本清洗(删除html标签、冗余字符、url、异常字符等),再进行分句,得到一系列句子的集合;

  3. 然后对原文中的每个句子进行权重的计算。

  4. 最后将句子按照重要程度进行排序,筛选出超过阈值的重要句子,然后按照原文的序号进行排序。最后组合成完整的摘要文本并输出;

# sklearn的TF-IDF实现
from sklearn.feature_extraction.text import TfidfTransformer, CountVectorizer  
corpus=["I come to China to travel", 
    "This is a car polupar in China",          
    "I love tea and Apple ",   
    "The work is to write some papers in science"] 
vectorizer=CountVectorizer()
transformer = TfidfTransformer()
tfidf = transformer.fit_transform(vectorizer.fit_transform(corpus))  
print tfidf

1.2 TextRank

《TextRank: Bringing Order into Texts》

导言:最经典的基于图的无监督关键词/句提取算法,是文本任务版本的PageRank。TextRank算法仿照PageRank,将句子作为节点,使用句子间相似度,构造无向有权边。使用边上的权值迭代更新节点值,最后选取N个得分最高的节点,作为摘要。

1.1.1 原理

最经典的TextRank通过将文本建模成无向全连接图结构,在图上利用PageRank迭代计算每个节点的重要性分数,从而能够提取关键节点。对于关键词提取而言,图上的每个节点即为文档的词,边则代表词和词之间的共现关系,即在长度为N的滑动窗口内部的所有词认为是存在共现关系的,这些词也就相互之间有边连接。这里构造的图是无边权的,计算节点V_i的PageRank分数的方法如下式,d的存在目的是为了使模型有一定的概率跳到图上其它随机点上,避免孤立点计算出现死循环,一般取d=0.85,初始节点分数均为1。注意下式是迭代计算的,一般设为20次:

S\left(V_{i}\right)=(1-d)+d * \sum_{j \in \operatorname{In}\left(V_{i}\right)} \frac{1}{\left|\operatorname{Out}\left(V_{j}\right)\right|} S\left(V_{j}\right)

对于关键句提取而言,图上的节点代表文档中的句子,边权则用下式计算,其中S_i,S_j为两个句子,w_k代表句子中的词,也即节点边权定义为和两个句子词重叠率成正比,之所以还要除以句子长度的对数之和,是考虑到越长的句子越可能出现重叠的词

\operatorname{Similarity}\left(S_{i}, S_{j}\right)=\frac{\left|\left\{w_{k} \mid w_{k} \in S_{i} \& w_{k} \in S_{j}\right\}\right|}{\log \left(\left|S_{i}\right|\right)+\log \left(\left|S_{j}\right|\right)}

关键句提取中TextRank方法建立的图为带边权的图,因而以下式计算PageRank分数,这里w_{ij}即为节点V_i,V_j之间的边权大小,d的规定同上:

W S\left(V_{i}\right)=(1-d)+d * \sum_{V_{j} \in In\left(V_{i}\right)} \frac{w_{j i}}{\sum_{V_{k} \in Out \left(V_{j}\right)} w_{j k}} W S\left(V_{j}\right)

故,基于上述方法可知,TextRank方法是无监督的不需要训练

1.1.2 代码实现

这里使用sklearn实现,使用TextRank抽取文档中的关键句,实现无监督提取文本摘要

from sklearn.feature_extraction.text import TfidfVectorizer, TfidfTransformer
def get_abstract(content, size=3):
    """
    利用textrank提取摘要
    :param content:
    :param size:
    :return:
    """
    docs = list(cut_sentence(content))
    tfidf_model = TfidfVectorizer(tokenizer=jieba.cut, stop_words=load_stopwords())
    tfidf_matrix = tfidf_model.fit_transform(docs)
    normalized_matrix = TfidfTransformer().fit_transform(tfidf_matrix)
    similarity = nx.from_scipy_sparse_matrix(normalized_matrix * normalized_matrix.T)
    scores = nx.pagerank(similarity)
    tops = sorted(scores.items(), key=lambda x: x[1], reverse=True)
    size = min(size, len(docs))
    indices = list(map(lambda x: x[0], tops))[:size]
    return list(map(lambda idx: docs[idx], indices))

1.3 Roberta

A Robustly Optimized BERT Pretraining Approach

导言:基于全词掩码策略的中文预训练BERT模型,在多项中文NLP任务中均取得优异性能

Roberta本质上是一个调到最优的bert模型。chinese-roberta-wwm-ext针对中文任务的特点,对roberta的训练策略进行了进一步的优化

1.3.1 原理

整体改进

  • Roberta全称为Robusty Optimized BERT Approach,其基础模型结构和Bert一致,都是使用了Transformer的Encoder结构。Roberta的改进主要在以下几点:

    • 使用了更多的训练语料,在BERT采用的数据BOOKCORPUS+English WIKIPEDIA(共16G)基础上,增加CC-NEWS(76GB)、OPENWEBTEXT(38GB)、STORIES(31GB),一共用了160GB语料进行预训练

    • 训练时采用动态MASK策略,预训练的每一个step都随机挑选15%的token进行mask操作,而不是像BERT那样,一个epoch内选取固定的15%token进行mask

    • 去除BERT中的next sentence prediction(NSP)预训练任务,因为实验证明NSP任务可能对效果有负提升,因为其包含两个句子的拼接,可能会对单个句子截断从而影响句子的语义表达,此外NSP中含有大量负样本,即两个句子的关联度不高,也会影响mask的预测

    • 训练时采用更大的batch size,更大的batch size可以提升性能,但同时也会造成更大的显存开销

    • Byte-level BPE编码,原始BERT采用字符级别的BPE编码,英文vocab size为30k,容易出现UNK问题,影响模型效果。RoBERTa采用了Byte级别的BPE词汇表,vocab size为50k。vocab size的增加使得模型参数量有所增加,BERT-base增加了15M,BERT-large增加了20M。但也提升了一定的效果。

  • 除此之外,中文chinese-roberta-wwm-ext模型又对roberta的优化策略做了如下改进,使其更适合中文NLP任务:

    • 采用全词掩码策略。Google在2019年发布了BERT的升级版,其中包含whole-word-mask(wwm),即全词掩码。在全词Mask中,如果一个完整的词的部分WordPiece子词被mask,则同属该词的其他部分也会被mask。由于中文BERT模型是以字为粒度进行切分,没有考虑到传统NLP中的中文分词(CWS),因此chinese-roberta-wwm-ext将全词Mask的方法应用在了中文中,使用了中文维基百科(包括简体和繁体)进行训练,并且使用了哈工大LTP作为分词工具,即对组成同一个词的汉字全部进行Mask

输入:原始文本是一个句子,如“使用语言模型来预测下一个词的probability”,经过分词和随机mask后,会得到预处理文本“使 用 语 言 [MASK] [MASK] 来 [MASK] [MASK] 下 一 个 词 的 [MASK] [MASK] [MASK]”,这里采用了全词掩码策略

输出:对[MASK]位置的词进行预测,输出概率值

预训练过程:集成了RoBERTa和BERT-wwm的优点,对两者进行了一个自然的结合。 和之前本目录中的模型之间的区别如下:

  • 预训练阶段采用wwm策略进行mask(但没有使用dynamic masking)

  • 简单取消Next Sentence Prediction(NSP)loss

  • 不再采用先maxlen=128然后再maxlen=512的训练模式,直接训练max_len=512

  • 训练步数适当延长

1.3.2 代码实现
# Roberta模型的训练过程
def Roberta_train(train_file, test_file, model_save_path,out_file):
    trainer = Trainer(data_file=train_file)
    best_rouge_2 = 0.
    best_rouge_l = 0.
    train_epoches = 20
    best_save_model_path = model_save_path
    for epoch in tqdm(range(train_epoches)):
        trainer.train(epoch)
        _,results = trainer.test(model_path = None, test_file = test_file, with_metric = True, 
                                 out_file = 'saved_models/test_test_output_{}.json'.format(epoch))
        if results['rouge-2'] > best_rouge_2 or results['rouge-l'] > best_rouge_l:
            best_rouge_2 = max(results['rouge-2'], best_rouge_2)
            best_rouge_l = max(results['rouge-l'], best_rouge_l)
            best_save_model_path = model_save_path.replace('.bin','0530_{:.4f}_{:.4f}.bin'.format(results['rouge-2'], results['rouge-l']))
            trainer.save(best_save_model_path)
    trainer.test(model_path = best_save_model_path, test_file = test_file, out_file = out_file)

1.4 mT5 model

Exploring the Limits of Transfer Learning with a Unified Text-to-Text Transformer

导言:一个统一框架,靠着大力出奇迹,将所有 NLP 任务都转化成 Text-to-Text(文本到文本)任务

1.4.1 原理

mT5是T5的多语言变体,已在包含101中语言的新的基于Common Crawl的数据集中进行了预训练。mT5的模型架构和训练过程与T5紧密相似,其改进点在于:使用GeGLU非线性(Shazeer,2020年)激活函数,在更大模型中缩放dmodel而不是改变dff, 对无标签数据进行预训练而没有dropout等措施。

本项目直接加载降级处理后的mT5模型(hugging Face库中对应的版本为:csebuetnlp/mT5_multilingual_XLSum),输入文本通过tokenizer进行分词得到对应的token id (支持最大长度为512),然后调用generate函数,将编码的输入文本进行解码,目前项目在解码过程中的超参数设置如下:支持最大长度max_length=70, 解码所用的beam search所保留的beam值为4。然后将得到的generate token ids经过tokenizer解码生成具体预测的文本。

  • 训练多语言模型的最重要的一点是如何从每种语言中采样数据。但是,这种选择是零和博弈:如果对低资源语言的采样过于频繁,则该模型可能会过拟合;如果对高资源语言的训练不够充分,则模型的通用性会受限。

  • 因此,研究团队采用Devlin和Arivazhagan等人使用的方法,并根据概率p(L)∝|L|^α,对资源较少的语言进行采样。其中p(L)是在预训练期间从给定语言中采样的概率,|L|是该语言中样本的数量,α是个超参数,谷歌经过实验发现α取0.3的效果最好。

1.4.2 代码实现
def summarize(text, max_length):
    '''
      text: 要生成摘要的文本
      max_length: 摘要的最大长度
    '''
    preprocess_text = text.strip().replace('\n','')                       # 去掉多余的空格和换行符
    t5_prepared_text = 'summarize: ' + preprocess_text                    # 准备前缀+文本
    print("Preprocessed and prepared text: \n", t5_prepared_text)         # 分词
    tokenized_text = tokenizer.encode(t5_prepared_text, return_tensors="pt").to(device)
    summary_ids = model.generate(tokenized_text,                          # 进行文本摘要
                                 num_beams=4,
                                 no_repeat_ngram_size=2,
                                 min_length=30,
                                 max_length=max_length,
                                 early_stopping=True)
    output = tokenizer.decode(summary_ids[0], skip_special_tokens=True)   # 将id转换为输出 summary_ids.shape = [1, 50]
    return output

二. 评价指标

2.1 ROUGE-N

2.1.1 指标解释

ROUGE英文全称Recall-Oriented Understudy for Gisting Evaluation,专注于召回率而非精度。N指的是N-gram,它会查看有多少个参考译句中的n元词组出现在了输出之中

ROUGE-N=\frac{\sum \limits_{S\in \{ReferenceSummaries\}}\sum \limits_{gram\in S}Count_{match}(gram_N)}{\sum\limits_{S\in \{ReferenceSummaries\}}\sum\limits_{gram\in S}Count(gram_N)}

公式的分母是统计在参考译文中N-gram的个数,而分子是统计参考译文与机器译文共有的N-gram个数。

2.2 bertscore

2.2.1 指标解释

对两个生成句和参考句(word piece进行tokenize)分别用bert提取特征,然后对2个句子的每一个词分别计算内积,可以得到一个相似性矩阵。基于这个矩阵,我们可以分别对参考句和生成句做一个最大相似性得分的累加然后归一化,得到bertscore的precision,recall和F1:

R_{BERT}=\frac{1}{|x|} \sum_{x_i\in x} \max_{\hat x_j\in \hat x}x_i^T\hat x_j\\ P_{BERT}=\frac{1}{|\hat x|} \sum_{\hat x_i\in \hat x} \max_{x_j\in x}x_i^T\hat x_j\\ F_{BERT}=2\frac{P_{BERT}\cdot R_{BERT}}{P_{BERT}+R_{BERT}}

2.3 Perplexity

2.3.1 指标解释

给测试集的句子赋予较高几率值的语言模型较好,当语言模型训练完以后,测试集中的句子都是正常的句子,那么训练好的模型就是在测试集上的几率越高越好,对于句子s

S=W_1,W_2,...,W_k

它的概率为:

P(S)=P(W_1,W_2,...,W_k)=P(W_1)P(W_2|W_1)...P(W_k|W_1,W_2,...,W_{k-1})

困惑度与测试集上的句子概率相关,其基本思想是:给测试集的句子赋予较高概率值的语言模型较好,当语言模型训练完之后,测试集中的句子都是正常的句子,那么训练好的模型就是在测试集上的概率越高越好,公式如下:

PP(W)=P(w_1,w_2,...,w_N)^{-\frac1N} = \sqrt[N]{\frac{1}{P(w_1,w_2,...,w_N)}}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,294评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,780评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,001评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,593评论 1 289
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,687评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,679评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,667评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,426评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,872评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,180评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,346评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,019评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,658评论 3 323
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,268评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,495评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,275评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,207评论 2 352

推荐阅读更多精彩内容