非监督文本摘要

作者: fighting41love | 来源:发表于2018-11-14 20:41 被阅读0次

    本文将介绍如何利用sentence embedding来做文本摘要。

    什么是文本摘要?

    文本摘要是从一些文本资源中抽取重要信息并生成“主旨、概要”的过程。

    我们小时候的语文课上,老师要求概括段落大意,指出主题思想。所以,人类很擅长“文本摘要”这样的工作,
    首先通过理解文字内容的含义,抽取重要信息,并用自己的语言概括。在这样一个信息爆炸的时代,人类已经
    没有足够的精力阅读海量文本,自动文本摘要算法应运而生:

    文本摘要节省阅读时间
    文本摘要精简了文本信息,让文本检索过程更简单,提升了检索效率
    文本摘要算法更加客观,减少了人类的主观“偏见”
    QA系统中的文本摘要,利于理解用户个性化的需求

    文本摘要的类型

    文本摘要的类型有很多种,根据输入、意图、输出可以分为以下几类:
    [图片上传失败...(image-c85cf9-1542199235016)]

    根据输入类型划分

    单文档文本摘要

    输入是单个文档,输入的文本长度不长,可以是一篇新闻。早起的文本摘要系统都是处理单文档的。

    多文档文本摘要

    输入时多个文档,可以是多篇新闻。

    根据意图划分

    通用文本摘要

    输入文本可以是各种各样的文本,比如新闻、小说等。这一部分有大量的研究工作。

    特定领域文本摘要

    文本摘要模型要融入领域相关知识,来生成更准确的摘要,比如生物医学文档的文本摘要生成。

    基于用户请求的文本摘要

    根据用户与会话机器人的对话内容,生成会话内容相关的文本摘要。

    基于输出类型的文本摘要

    抽取式

    从文本中抽取句子,然后组合成为摘要。这是目前广泛使用的文本摘要算法,这种文本摘要算法产生的句子一般没有语病、逻辑问题(因为是从文本中抽取的嘛)。

    生成式

    生成式的文本摘要首先从模型中,抽取phrase和sentence,然后生成摘要(很像人们概括段落大意的方式)。所以,这种方法更有趣、更贴近实际,当然也更加难。

    很多文本摘要算法的训练都需要有raw text和对应的summary作为训练数据。但是在大量的nlp任务中,很难获得训练数据,或者获得训练数据的代价非常大。所以在实际的业务中,更倾向于unsupervised的方法。这里简单介绍一下Kushal Chauhan在邮件文本summary方面的工作,介绍他是如何使用sentence embedding来做email summary的。

    Kushal Chauhan为什么要用unsupervised text summarization方法呢?通用的文本摘要无法在邮件文本中发挥作用。一方面,数据分布是不同的;另一方面,Kushal面对的事多语言的文档包含English, Danish, French等语言。他借鉴了《Unsupervised Text Summarization Using Sentence Embeddings》这篇论文中的方法,构建了如下Pipeline:


    image.png
    步骤1:email数据清洗

    首先,我们来看一下email文本:

    Hi Jane,
    
    Thank you for keeping me updated on this issue. I'm happy to hear that the issue got resolved after all and you can now use the app in its full functionality again. 
    Also many thanks for your suggestions. We hope to improve this feature in the future. 
    
    In case you experience any further problems with the app, please don't hesitate to contact me again.
    
    Best regards,
    
    John Doe
    Customer Support
    
    1600 Amphitheatre Parkway
    Mountain View, CA
    United States
    

    email开头的 Hi name以及结尾的 best regards + name对文本摘要是没有用处的。邮件中的开头和结尾“形态各异”,需要相应的正则表达式去识别并删除。mailgun/talon在其github repo中实现了删除邮件开头、结尾的功能,支持多种语言(对于中文的支持,尚需检验)。这里我们给出代码示例:

    # clean() is a modified version of extract_signature() found in bruteforce.py in the GitHub repository linked above
    cleaned_email, _ = clean(email)
    
    lines = cleaned_email.split('\n')
    lines = [line for line in lines if line != '']
    cleaned_email = ' '.join(lines)
    

    上面的email经过处理,可以得到:

    Thank you for keeping me updated on this issue. I'm happy to hear that the issue got resolved after all and you can now use the app in its full functionality again. Also many thanks for your suggestions. We hope to improve this feature in the future. In case you experience any further problems with the app, please don't hesitate to contact me again.
    
    步骤2: 语言检测

    不同语言的sentence tokenization不同,不能都当做英文进行处理。所以,首先使用polyglot, langdetect 或 textblob来进行语言检测。langdetect的相关内容,我在funNLP中介绍过,它支持55种不同的语言识别,如下所示:

    from langdetect import detect
    lang = detect(cleaned_email) # lang = 'en' for an English email
    
    步骤3: 句子分割

    识别出email使用的语言后,使用对应语言的tokenization方法,对email进行句子分割。对于英文email,可以使用nltk中的sent_tokenize进行分割即可:

    from nltk.tokenize import sent_tokenize
    sentences = sent_tokenize(email, language = lang)
    
    句子分割
    步骤4: skip-thought encoder

    这一部分介绍如何对句子进行编码。句子的编码方式多种多样,最简单的莫过于将句子中的每个词对应的词向量加起来,再平均,类似于fasttext的做法。在此基础上,复杂一点的,不同的词有不同的权重,比如 and, the 这类词权重就应该低一些。此时,可以使用tf-idf相关信息做权重。论文《A SIMPLE BUT TOUGH-TO-BEAT BASELINE FOR SEN- TENCE EMBEDDINGS》就是这么做的。

    上述方法,没有考虑句子中的词的顺序,这很可能会影响summarization的模型表现,所以采用了skip-thought sentence encoder,并以wikipedia作为训练数据。skip-thought sentence encoder包含两个部分:

    1. encoder network: GRU-RNN用于生成固定长度的句子S_i向量表示。
    2. decoder network: 用于产生S_i的前后句S_{i-1}S_{i+1},前后两句采用分别的decoder:previous decoder和next decoder。
      image.png

    跟skip gram有点像,给定中间的元素,预测前后的元素。skip-thought encoder最小化句子重构的Loss,这样encoder就能够学会正确地编码句子。对于具有类似意思的句子,其编码后的向量依然相近。《Skip-Thought Vectors》论文中阐述了更多的细节。
    [图片上传失败...(image-932a53-1542199235016)]](https://img.haomeiwen.com/i2528310/637b6b05249bcd13.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

    作者使用了theano开源代码来做训练,pytorch版本开源代码

    Skip-Thoughts Encoder-Decoder Architecture

    将句子编码的代码就变得非常简单了:

    # The 'skipthoughts' module can be found at the root of the GitHub  repository linked above
    import skipthoughts
    
    # You would need to download pre-trained models first
    model = skipthoughts.load_model()
    
    encoder = skipthoughts.Encoder(model)
    encoded =  encoder.encode(sentences)
    
    步骤5: 聚类

    将email中的每一个句子编码后,可以使用k-means进行聚类。聚类的数目等于summary的句子数目。

    import numpy as np
    from sklearn.cluster import KMeans
    
    n_clusters = np.ceil(len(encoded)**0.5)
    kmeans = KMeans(n_clusters=n_clusters)
    kmeans = kmeans.fit(encoded)
    
    步骤5: 形成摘要

    对于几个cluster,选取距离cluster中心最近的句子。选出句子后,如何对这些句子排序呢?分析每个cluster中的全部句子在原文中的顺序,如果该cluster中的多数句子排在第一,那么该cluster中选取的那个句子也排在第一句,代码如下:

    from sklearn.metrics import pairwise_distances_argmin_min
    avg = []
    for j in range(n_clusters):
        idx = np.where(kmeans.labels_ == j)[0]
        avg.append(np.mean(idx))
    closest, _ = pairwise_distances_argmin_min(kmeans.cluster_centers_, encoded)
    ordering = sorted(range(n_clusters), key=lambda k: avg[k])
    summary = ' '.join([email[closest[idx]] for idx in ordering])
    

    上文中的邮件,summary结果如下:

    I'm happy to hear that the issue got resolved after all and you can now use the app in its full functionality again. 
    Also many thanks for your suggestions. 
    In case you experience any further problems with the app, please don't hesitate to contact me again.
    

    skip-thought encoder的训练语料来自wikipedia。email summarization的源代码详见github

    总结一下,本文使用了wikipedia的数据,训练了skip-thought encoder,用来做sentence embedding,拿到embedding后,做clustering,然后挑选句子,并根据cluster中的所有句子的位置 进行排序。

    相关文章

      网友评论

        本文标题:非监督文本摘要

        本文链接:https://www.haomeiwen.com/subject/wqhjfqtx.html