【自然语言处理】基于句子嵌入的文本摘要算法实现

news2024/9/29 18:10:07

基于句子嵌入的文本摘要算法实现

人们在理解了文本的含义后,很容易用自己的话对文本进行总结。但在数据过多、缺乏人力和时间的情况下,自动文本摘要则显得至关重要。一般使用自动文本摘要的原因包括:

  • 减少阅读时间
  • 根据摘要,选择自己想研究的文档
  • 提高索引的有效性
  • 自动摘要算法比人工摘要算法的偏差更小
  • 问答系统中的个性化摘要
  • 能有效增加处理的文本数量

1.方法分类

  • 基于输入
    • 单个文档
    • 多文档
  • 基于目的
    • 通用型。模型不对文本的所属领域或内容做出任何假设,所有输入被视为同质。目前,大部分研究的工作都是围绕这种方法展开的。
    • 特定领域。模型使用特定领域的知识来形成更准确的摘要。例如,总结特定领域的研究论文、生物医学文献等。
    • 基于查询。对相关问题的回答进行摘要。
  • 基于输出
    • 抽取。从输入文本中选择重要的句子形成摘要。目前,大多数摘要方法本质上都是抽取式的。
    • 生成。模型生成短语和句子来提供更连贯的摘要。

在这里插入图片描述

2.Pipeline

本次任务是 对英语、丹麦语、法语等语言的电子邮件进行文本摘要。大多数公开可用的文本摘要数据集都是针对长文档的。由于长文档的结构与电子邮件的结构明显不同,因此使用监督方法训练的模型可能会出现领域适应性差的问题。因此,我们选择无监督方法来提取摘要。

本文使用的方法主要来自论文《Unsupervised Text Summarization Using Sentence Embeddings》。在这里插入图片描述

2.1 Email Cleaning

英文邮件示例:

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

挪威语邮件示例:

Hei

Grunnet manglende dekning på deres kort for månedlig trekk, blir dere nå overført til årlig fakturering.
I morgen vil dere motta faktura for hosting og drift av nettbutikk for perioden 05.03.2018-05.03.2019.
Ta gjerne kontakt om dere har spørsmål.

Med vennlig hilsen
John Doe - SomeCompany.no
04756 | johndoe@somecompany.no

Husk å sjekk vårt hjelpesenter, kanskje du finner svar der: https://support.somecompany.no/

意大利语邮件示例:

Ciao John, 

Grazie mille per averci contattato! Apprezziamo molto che abbiate trovato il tempo per inviarci i vostri commenti e siamo lieti che vi piaccia l'App. 

Sentitevi liberi di parlare di con i vostri amici o di sostenerci lasciando una recensione nell'App Store!

Cordiali saluti, 

Jane Doe
Customer Support

One Infinite Loop
Cupertino
CA 95014

电子邮件开头和结尾的称呼和签名对摘要生成任务没有任何价值。为了使模型可以执行更简单的输入,可以从电子邮件中删除这些无意义的信息。

称呼和签名因电子邮件以及语言而异,因此需要通过正则表达式进行删除。代码的简短版本如下所示(参考了 Mailgun Talon 在 GitHub 中的代码):

# 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)

还可以通过 talon.signature.bruteforce 实现:

from talon.signature.bruteforce import extract_signature
cleaned_email, _ = extract_signature(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.

挪威语电子邮件:

Grunnet manglende dekning på deres kort for månedlig trekk, blir dere nå overført til årlig fakturering. I morgen vil dere motta faktura for hosting og drift av nettbutikk for perioden 05.03.2018-05.03.2019. Ta gjerne kontakt om dere har spørsmål.

意大利语电子邮件:

Grazie mille per averci contattato! Apprezziamo molto che abbiate trovato il tempo per inviarci i vostri commenti e siamo lieti che vi piaccia l’App. Sentitevi liberi di parlare di con i vostri amici o di sostenerci lasciando una recensione nell’App Store.

2.2 Language Detection

由于输入的电子邮件可以是任何语言,因此需要确定电子邮件使用的是哪种语言。许多 Python 库都提供的语言检测功能,例如 polyglotlangdetecttextblob。此处使用 langdetect,它支持 55 55 55 种不同语言的检测。

from langdetect import detect
lang = detect(cleaned_email) # lang = 'en' for an English email

2.3 Sentence Tokenization

不同语言的文本有不同的分割规则,在识别了每封电子邮件使用的语言后,我们可以利用 NLTK 将不同语言的文本分割成句子。

from nltk.tokenize import sent_tokenize
sentences = sent_tokenize(email, language = lang)

在这里插入图片描述

2.4 Skip-Thought Encoder

接下来需要为电子邮件中的每个句子生成固定长度的向量表示。例如 Word2Vec 方法可以为模型词汇表中的每个词提供词嵌入(一些更高级的方法还可以使用子词信息为不在模型词汇表中的词生成嵌入)。下图是 Word2Vec 模型的 Skip-Gram 训练模式。

在这里插入图片描述
对于句子嵌入,一种简单的方法是 对句子所包含的单词的词向量进行加权和。采用加权和是因为频繁出现的词,如 andtothe 等单词所提供的关于句子的信息几乎非常少甚至没有。一些词虽然出现的次数较少,但它们是少数句子所特有的,具有更强的代表性。因此,我们假设权重与单词出现的频率成反比。

然而无监督方法并没有考虑句子中单词的顺序,这可能会影响模型精度。此处,我们选择使用维基百科转储(Wikipedia dumps)作为训练数据,以监督的方式训练一个 Skip-Thought 句子编码器。 该模型主要由两部分组成:

  • 编码器网络(Encoder Network):编码器通常是 GRU-RNN,它为输入中的每个句子 S ( i ) S(i) S(i) 生成固定长度的向量表示 h ( i ) h(i) h(i) h ( i ) h(i) h(i) 是通过将 GRU 单元的最终隐藏状态传递给多个密集层来获得的。
  • 解码器网络(Decoder Network):解码器网络将 h ( i ) h(i) h(i) 作为输入,并尝试生成两个句子: S ( i − 1 ) S(i-1) S(i1) S ( i + 1 ) S(i+1) S(i+1),这两个句子可能分别出现在输入句子之前和之后。每个都实施单独的解码器来生成上一句和下一句,两者都是 GRU-RNN h ( i ) h(i) h(i) 作为解码器网络的 GRU 的初始隐藏状态。

在这里插入图片描述
给定一个包含句子序列的数据集,解码器应该逐字生成上一句和下一句。编码器-解码器(encoder-decoder)网络通过训练使句子重建损失(sentence reconstruction loss)最小化。在此过程中,编码器学习生成向量表示,编码足够的信息供解码器使用,以便它可以生成相邻的句子。这些学习到的表示使得 语义相似的句子的嵌入在向量空间中彼此更接近,因此适用于聚类。我们把电子邮件中的句子作为编码器网络的输入,以获得所需的向量表示。

在这里插入图片描述

此处,我们可以使用 Skip-Thoughts 论文作者 开源的代码。仅需几行代码就可以完成:

# 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)

在这里插入图片描述

2.5 Clustering

在为电子邮件中的每个句子生成句子嵌入后,可以对这些在高维向量空间中的嵌入进行聚类。聚类的数量将等于摘要中所需的句子数量。可以将摘要中的句子数定义为电子邮件中句子总数的平方根,也可以认为它等于句子总数的 30 % 30\% 30%

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)

2.6 Summarization

每个聚类都可以被理解为一组语义相似的句子,其含义可以由摘要中的一个候选句子表达。候选句子是向量表示最接近聚类中心的句子。然后对每个集群对应的候选句子进行排序,以形成电子邮件的摘要。摘要中候选句子的顺序由句子在原始电子邮件中的位置决定。

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])

最终生成的摘要结果如下所示:

英文电子邮件:

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.

丹麦语电子邮件:

Grunnet manglende dekning på deres kort for månedlig trekk, blir dere nå overført til årlig fakturering. I morgen vil dere motta faktura for hosting og drift av nettbutikk for perioden 05.03.2018-05.03.2019. Ta gjerne kontakt om dere har spørsmål.

意大利语电子邮件:

Apprezziamo molto che abbiate trovato il tempo per inviarci i vostri commenti e siamo lieti che vi piaccia l’App. Sentitevi liberi di parlare di con i vostri amici o di sostenerci lasciando una recensione nell’App Store.

3.训练过程

预训练模型可用于编码英语句子。对于丹麦语句子,必须自己训练 Skip-Thought 模型。数据取自丹麦语维基百科转储(Danish Wikipedia dumps)。此处使用 WikiExtractor 解析维基百科转储,虽然它不是最好的工具,但它是免费的,并且可以在合理的时间内完成这项工作。

由此生成的训练数据包括来自维基百科文章的 2 , 712 , 935 2,712,935 2,712,935 个丹麦语句子。训练过程还需要预先训练好的 Word2Vec 词向量。此处使用的是 F a c e b o o k Facebook Facebook F a s t T e x t FastText FastText 的预训练词向量。预训练模型的词汇量为 312 , 956 312,956 312,956 个单词。这些词向量也是在丹麦语维基百科上进行训练的,因此词汇外的词非常少见。

下面是该模块的简化版本,它仅支持英文电子邮件,但实现了上述所有步骤,效果非常好。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Module for E-mail Summarization
*****************************************************************************
Input Parameters:
    emails: A list of strings containing the emails
Returns:
    summary: A list of strings containing the summaries.
*****************************************************************************
"""


# ***************************************************************************
import numpy as np
from talon.signature.bruteforce import extract_signature
from langdetect import detect
from nltk.tokenize import sent_tokenize
import skipthoughts
from sklearn.cluster import KMeans
from sklearn.metrics import pairwise_distances_argmin_min
# ***************************************************************************


def preprocess(emails):
    """
    Performs preprocessing operations such as:
        1. Removing signature lines (only English emails are supported)
        2. Removing new line characters.
    """
    n_emails = len(emails)
    for i in range(n_emails):
        email = emails[i]
        email, _ = extract_signature(email)
        lines = email.split('\n')
        for j in reversed(range(len(lines))):
            lines[j] = lines[j].strip()
            if lines[j] == '':
                lines.pop(j)
        emails[i] = ' '.join(lines)
        
        
def split_sentences(emails):
    """
    Splits the emails into individual sentences
    """
    n_emails = len(emails)
    for i in range(n_emails):
        email = emails[i]
        sentences = sent_tokenize(email)
        for j in reversed(range(len(sentences))):
            sent = sentences[j]
            sentences[j] = sent.strip()
            if sent == '':
                sentences.pop(j)
        emails[i] = sentences
        
        
def skipthought_encode(emails):
    """
    Obtains sentence embeddings for each sentence in the emails
    """
    enc_emails = [None]*len(emails)
    cum_sum_sentences = [0]
    sent_count = 0
    for email in emails:
        sent_count += len(email)
        cum_sum_sentences.append(sent_count)

    all_sentences = [sent for email in emails for sent in email]
    print('Loading pre-trained models...')
    model = skipthoughts.load_model()
    encoder = skipthoughts.Encoder(model)
    print('Encoding sentences...')
    enc_sentences = encoder.encode(all_sentences, verbose=False)

    for i in range(len(emails)):
        begin = cum_sum_sentences[i]
        end = cum_sum_sentences[i+1]
        enc_emails[i] = enc_sentences[begin:end]
    return enc_emails
        
    
def summarize(emails):
    """
    Performs summarization of emails
    """
    n_emails = len(emails)
    summary = [None]*n_emails
    print('Preprecesing...')
    preprocess(emails)
    print('Splitting into sentences...')
    split_sentences(emails)
    print('Starting to encode...')
    enc_emails = skipthought_encode(emails)
    print('Encoding Finished')
    for i in range(n_emails):
        enc_email = enc_emails[i]
        n_clusters = int(np.ceil(len(enc_email)**0.5))
        kmeans = KMeans(n_clusters=n_clusters, random_state=0)
        kmeans = kmeans.fit(enc_email)
        avg = []
        closest = []
        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_,\
                                                   enc_email)
        ordering = sorted(range(n_clusters), key=lambda k: avg[k])
        summary[i] = ' '.join([emails[i][closest[idx]] for idx in ordering])
    print('Clustering Finished')
    return summary

4.结果

当邮件中包含多个句子时,此种摘要方法效果较好。对于三句话的邮件,摘要可能是由两句话组成,但三个句子传达的意义可能完全不同,省略掉任何一个句子的信息都是不合适的。基于此,提取法通常并不适合短文本摘要。监督式 Seq2Seq 模型更适合这项任务。

使用 Skip-Thought 方法进行向量化的一个缺点是模型可能需要训练很长时间。尽管在训练 2 − 3 2-3 23 天后获得了可接受的结果,但 Skip-Thought 模型在丹麦语语料上训练了大约一周。该模型是按句子长度归一化的,所以成本在迭代期间波动很大。

在这里插入图片描述
可以查看数据集中最相似的句子,了解 Skip-Thoughts 模型的效果。

1 1 1

  • I can assure you that our developers are already aware of the issue and are trying to solve it as soon as possible.
  • I have already forwarded your problem report to our developers and they will now investigate this issue with the login page in further detail in order to detect the source of this problem.

2 2 2

  • I am very sorry to hear that.
  • We sincerely apologize for the inconvenience caused.

3 3 3

  • Therefore, I would kindly ask you to tell me which operating system you are using the app on.
  • Can you specify which device you are using as well as the Android or iOS version it currently has installed?

5.优化

通过增加模型的复杂性可以进行一些相关的改进:

  • Quick-Thought VectorsSkip-Thoughts 方法的最新进展,可以显著减少训练时间并提高性能。
  • Skip-Thought 编码表示的维数为 4800 4800 4800。由于维数灾难,这些高维向量不适合聚类。在使用 AutoencoderLSTM-Autoencoder 进行聚类之前,可以进行降维。
  • 可以通过训练解码器网络来实现 生成摘要,而不是提取摘要。解码器网络可以将聚类中心的编码表示转换回自然语言表示的句子。这样的解码器可以通过 Skip-Thoughts 编码器生成的数据进行训练。但是,如果我们希望解码器生成合理且语法正确的句子,则需要对解码器进行非常仔细的超参调整和架构决策。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/373431.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Widget中的State-学习笔记

Widget 有 StatelessWidget 和 StatefulWidget 两种类型。StatefulWidget 应对有交互、需要动态变化视觉效果的场景,而 StatelessWidget 则用于处理静态的、无状态的视图展示。StatefulWidget 的场景已经完全覆盖了 StatelessWidget,因此我们在构建界面时…

如何把Windows自带壁纸、锁屏壁纸取出作为自己的桌面壁纸?(附:批量更改文件后缀名的方法)

这是一个目录0.0Windows桌面自带壁纸(个性化中的壁纸)Windows聚焦的锁屏壁纸批量更改后缀名的办法最近开机时,发现Windows聚焦的锁屏壁纸都很好看,特别想留下来当桌面壁纸,寻找了一下之后,终于找到了储存路…

第一节 变量、数据类型、关键字标识符

变量 什么是变量:就是用来存储一个数据的内存区域,而且里面存储的数据可以变化。 double money 10.0; 变量使用的注意事项: 1.先声明再使用。 2.变量声明后,就不能存储其他数据。 3.变量的有效范围是从定义开始到“}…

Dubbo源码解析-——SPI机制

文章目录一、什么是SPI机制二、Java原生的SPI机制2.1、javaSPI示例2.1.1、编写接口和实现类2.1.2、编写配置文件2.1.3、通过SPI机制加载实现类2.1.4、JAVA SPI 源码解析2.1.4.1、ServiceLoader#load2.1.4.2、ServiceLoader构造方法2.1.4.3、ServiceLoader#reload2.1.4.4、LazyI…

IoT项目系统架构案例2

项目背景 1.这个项目是对之前的案例的升级改造参考:IoT项目系统架构案例_iot案例_wxgnolux的博客-CSDN博客2.基于方案1的项目实施过程中碰到的问题,对硬件设备标准化的理念及新的功能需求(如根据天气预报温度调水温,APP界面可操作性优化等)•采用目前IoT主流厂商的架…

java的一些冷知识

接口并没有继承Object类首先接口是一种特殊的类,理由就是将其编译后是一个class文件大家都知道java类都继承自Object,但是接口其实是并没有继承Object类的 可以自己写代码测试: 获取接口类的class对象后遍历它的methods,可以发现是不存在Obje…

Java EE|TCP/IP协议栈之网络层IP协议详解

文章目录一、IP协议感性认知简介特点二、IP协议报头结构4位版本4位首部长度8位服务类型16位总长度16位标识8位生存时间(TTL)8位协议16位首部长度32位源ip&32位目的地址三、网络地址管理网段划分路由选择参考一、IP协议感性认知 简介 P是整个TCP/IP…

【云原生】k8s的pod基本概念

一、资源限制 Pod 是 kubernetes 中最小的资源管理组件,Pod 也是最小化运行容器化应用的资源对象。一个 Pod 代表着集群中运行的一个进程。kubernetes 中其他大多数组件都是围绕着 Pod 来进行支撑和扩展 Pod 功能的,例如用于管理 Pod 运行的 StatefulSe…

小说网站测试

目录 通用测试点 登录页面测试 接口测试 UI测试 注册页面 接口自动化 UI测试 忘记密码页面 接口测试 UI测试 修改密码页面 进行接口测试 UI测试 主页页面测试 分类页面测试 ​查询页面测试 作者页面测试 阅读小说页面测试 书架页面测试 通用测试点 登录页面测试 接…

k8s-资源限制-探针检查

文章目录一、资源限制1、资源限制的使用2、reuqest资源(请求)和limit资源(约束)3、Pod和容器的资源请求和限制4、官方文档示例5、资源限制实操5.1 编写yaml资源配置清单5.2 释放内存(node节点,以node01为例…

计算机网络题库---错题本

(一)老生常谈 第一章: 1.什么是计算机网络?其主要功能是什么? 解答: 利用通信设备和线路,将分布在地理位置不同的、功能独立的多个计算机系统连接起来,以功能完善的网络软件实现网…

ChatGPT 开发人员教程 - 38种提高工作效率10倍的方法

未来的时代,又将是一个“洋枪洋炮”对“大刀长矛”的时代。在过去的十年里,传统行业在和经过IT改造的行业竞争时,无一例外地败北。08年金融危机前,全世界市值前十的公司,只有微软一家是IT企业。仅仅过去了十年&#xf…

文献阅读:Training language models to follow instructions with human feedback

文献阅读:Training language models to follow instructions with human feedback 1. 文献工作简介2. 模型优化设计3. 实验结果4. 总结 & 思考 文献链接:https://arxiv.org/abs/2203.02155 1. 文献工作简介 这篇文章是OpenAI在上年提出的一篇对于…

Go项目(商品微服务-1)

文章目录简介建表protohandler商品小结简介 商品微服务主要在于表的设计,建哪些表?表之间的关系是怎样的? 主要代码就是 CURD表和字段的设计是一个比较有挑战性的工作,比较难说清楚,也需要经验的积累,这里…

【Linux】工具(2)——vim

本期博客我们进入到Linux环境下vim工具的学习:一、vim是什么📌Vim是一个超级超级强大的文本编辑器。Vim及前身VI,历史悠久(可能比多数读者的年龄更大),经历了几十年的考验和发展。Vim全称叫Vi IMproved. 而…

Linux安装云原生网关Kong/KongA

目录1 概述2 创建服务器3 安装postgres4 安装kong5 安装node6 安装KONGA1 概述 Kong Kong是一款基于OpenResty(NginxLua模块)编写的高可用、易扩展的开源API网关,专为云原生和云混合架构而建,并针对微服务和分布式架构进行了特别…

蓝桥杯算法模板

模拟散列表拉链法import java.io.*; import java.util.*; public class a1 {static int n;static int N100003;static int[] hnew int[N];static int[] enew int[N];static int[] nenew int[N]; static int idx; static void insert(int x){int k(x%NN)%N;e[idx]x;ne[idx]h[k];…

终端软件架构说

目录 零:前言 一,基于服务的架构 二,基于多进程多线程的架构 三,以数据为中心的架构 四,类Android的分层架构设计 五,总结 零:前言 谈到架构,可能大家的第一感觉是信息系统的…

2023年三月份图形化三级打卡试题

活动时间 从2023年3月1日至3月21日,每天一道编程题。 本次打卡的规则如下: 小朋友每天利用10~15分钟做一道编程题,遇到问题就来群内讨论,我来给大家答疑。 小朋友做完题目后,截图到朋友圈打卡并把打卡的截图发到活动群…

Vue 3第三章:模板语法及指令介绍

文章目录1. 插值表达式1.1. 声明变量可直接在模板中使用,采用{{变量名称}}的方式1.2. 模板语法支持三元表达式1.3. 模板语法支持运算1.4. 模板语法支持方法调用2. 指令2.1. v-bind:用于绑定属性或动态绑定对象的值到元素上。2.2. v-if、v-else-if、v-els…