Python 利用深度学习做文本摘要

Python中的文本摘要生成:从入门到进阶 文本摘要是将一个长篇的文档或文章压缩为一个简短的内容,保留最为重要的、核心的信息。抽取式摘要(Extractive Summarization):该方法从原文中提取出关键句子或段落,组成新的摘要,通常不修改提取的文本。生成式摘要(Abstractive Summarization):该方法不仅仅是从原文中提取句子,而是通过理解和重组原文内容,生成全新的句子。生成式摘要更像是人类写作的方式,通常会对文本进行更为复杂的处理。 阅读详情

前言

本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理。

PS:如有需要Python学习资料的小伙伴可以点击下方链接自行获取

python免费学习资料、代码以及交流解答点击即可加入


介绍

“我不想要完整的报告,只需给我一个结果摘要”。我发现自己经常处于这种状况——无论是在大学还是在职场中。我们准备了一份综合全面的报告,但教师/主管却仅仅有时间阅读摘要。

听起来很熟悉?好吧,我决定对此采取一些措施。手动将报告转换为摘要太耗费时间了,对吧?那我可以依靠自然语言处理(NLP)技术来帮忙吗?

这就是使用深度学习的文本摘要真正帮助我的地方。它解决了以前一直困扰着我的问题——现在我们的模型可以理解整个文本的上下文。对于所有需要把文档快速摘要的人来说,这个梦想已成现实!

 

 

我们使用深度学习完成的文本摘要结果如何呢?非常出色。因此,在本文中,我们将逐步介绍使用深度学习构建文本摘要器的过程,其中包含构建它所需的全部概念。然后将用Python实现我们的第一个文本摘要模型!

注意:本文要求对一些深度学习概念有基本的了解。

目录

1. NLP中的文本摘要是什么?
2. 序列到序列(Seq2Seq)建模简介
3. 理解编码器(Encoder)-解码器(Decoder)架构
4. 编码器-解码器结构的局限性
5. 注意力机制背后的直觉
6. 理解问题陈述
7. 使用Keras在Python中实现文本摘要模型
8. 注意力机制如何运作?

我在本文的最后面保留了“注意力机制如何运作?”的部分。这是一个数学密集的部分,并不强制了解Python代码的工作原理。但是,我鼓励你通读它,因为它会让你对这个NLP概念有一个坚实的理解。

1. NLP中的文本摘要是什么?

在了解它是如何工作之前,我们先来看看文本摘要是什么。如下是一个简洁的定义,我们开始吧:
“自动文本摘要的任务是生成简明扼要的摘要,同时保留关键信息内容和整体含义”

大致有两种不同的方法用于文本摘要:

  • 抽取式摘要(Extractive Summarization)
  • 生成式摘要(Abstractive Summarization)

     

     

    让我们更详细地看一下这两种类型。

  • 抽取式摘要
    这个名字透露了这种方法的作用。我们从原文中找出重要的句子或短语,并从中抽取。这些抽取出的句子将成为我们的总结。下图简要说明了抽取式摘要:

     

  • 生成式摘要
    这是一个非常有趣的方法。当中,我们会从原文中生成新的句子。这与我们之前看到的抽取方法形成了对比,之前我们只使用了现存的句子。通过生城式摘要生成的句子可能并未出现在原文中:

     

     

    你可能已经猜到了——我们将在本文中使用深度学习构建一个生成式文本摘要器! 在深入实现这部分之前,我们先了解一些构建文本摘要生成模型所需的概念。

前方高能!

2. 序列到序列(Seq2Seq)建模简介

我们可以针对涉及顺序信息的任何问题构建Seq2Seq模型。顺序信息的一些非常常见的应用包括情感分类,神经网络机器翻译和命名实体识别。

在神经网络机器翻译的情况下,输入是某一种语言的文本,输出是另一种语言的文本:


在命名实体识别中,输入是一个单词序列,而输出是输入序列中每个单词的标记序列:


我们的目标是构建一个文本摘要生成器,其中输入是一个单词的长序列(文本正文),输出是一个简短的摘要(也是一个序列)。 因此,我们可以将其建模为多对多Seq2Seq问题。 以下是一个典型的Seq2Seq模型架构:


Seq2Seq模型有两个主要组件:

 

  • 编码器
  • 解码器

我们来详细了解一下这两个组件。这些对于理解文本摘要是如何工作的代码至关重要。

3. 理解编码器-解码器架构

编码器-解码器架构主要用于解决输入和输出序列长度不同的序列到序列(Seq2Seq)问题。

让我们从文本摘要的角度来理解这一点。输入是一长串单词,输出是输入序列的简短版本。

 

 

通常,循环神经网络(RNN)的变体,比如门控循环神经网络(GRU)或长短时记忆(LSTM),将优选作为编码器和解码器组件。这是因为它们能够通过克服梯度弥散问题来捕获长期依赖性。

我们可以分两个阶段设置编码器-解码器:

  • 训练阶段
  • 推理阶段

让我们通过LSTM模型来理解这些概念。

  • 训练阶段

在训练阶段,我们将首先设置编码器和解码器。然后,我们将训练模型以预测偏移一个时间步长的目标序列。我们详细了解一下如何设置编码器和解码器。

  • 编码器

编码器长短时记忆模型(LSTM)读取整个输入序列,其中在每个时间步,一个单词被送到编码器。然后,它在每个时间步处理信息并捕获输入序列中存在的上下文信息。

下图说明了这个过程:

 

 

最后一个时间步的隐藏状态(hi)和单元状态(ci)用于初始化解码器。请记住,这是因为编码器和解码器是两套LSTM架构。

  • 解码器

解码器也是LSTM网络,它逐字读取整个目标序列并在每一个时间步预测相同的序列偏移。训练解码器以达到,给定前一个词预测序列中的下一个词。

 

 

<start>和<end>是在将其提供给解码器之前添加到目标序列的特殊标记。解码测试序列时,目标序列是未知的。因此,我们通过将第一个字(始终是<start>标记)传递给解码器来开始预测目标序列,并且<end>标记表示句子的结尾。

到目前为止非常直观。

推理阶段

训练后,用目标序列未知的新序列来测试模型。因此,我们需要设置推理架构来解码测试序列:

 

推理过程如何工作?

以下是解码测试序列的步骤:
1. 对整个输入序列进行编码,并使用编码器的内部状态初始化解码器
2. 将<start>标记作为解码器的输入
3. 使用内部状态运行解码器一个时间步
4. 输出将是下一个单词的概率。将选择具有最大概率的单词
5. 在下一个时间步中将采样的字作为输入传递给解码器,并使用当前时间步更新内部状态
6. 重复步骤3-5,直到我们生成<end>标记或达到目标序列的最大长度

我们举一个例子,测试序列由[x1,x2,x3,x4]给出。推理过程如何作用于此测试序列?希望你在往下看之前先自己考虑一下。
1. 将测试序列编码为内部状态向量
2. 观察解码器如何在每个时间步预测目标序列:

  • Timestep: t=1

     

  • Timestep: t=2

     

  • Timestep: t=3

     

4. 编码器-解码器结构的局限性

尽管这种编码器-解码器架构很有用,但它也有一些限制。

  • 编码器将整个输入序列转换为固定长度的向量,然后解码器预测输出序列。这仅适用于短序列,因为解码器需要查看整个输入序列来预测
  • 长序列的问题是,编码器难以将长序列记忆成一个固定长度的向量

“这种编码器-解码器方法的潜在问题是神经网络需要能够将源句子的所有必要信息压缩成固定长度的向量。这可能使神经网络难以应对长句。随着输入句子长度的增加,基本的编码器-解码器性能将迅速恶化。”

那么我们如何克服长序列这个问题呢?这就是注意力机制被引入的地方。它旨在通过仅仅查看序列的一些特定部分而不是整个序列来预测单词。这听起来就很棒!

5. 注意力机制背后的直觉

我们来考虑一个简单的例子来理解注意力机制的工作原理:

  • 源序列:“你最喜欢哪项运动?(Which sport do you like the most?)
  • 目标序列:“我喜欢板球”(I love cricket)

目标序列中的第一个单词'I',与源序列中的第四个单词'you'相连,对吗? 类似地,目标序列中的第二个单词“love”与源序列中的第五个单词“like”相关联。

因此,我们可以增加源序列中特定部分(正是这部分与目标序列相关)的重要性,而不是查看源序列中的所有单词。这正是注意力机制背后的基本思想。

根据参与的上下文向量的派生方式,有2种不同类型的注意力机制:

  • 全局注意力(Global Attention)
  • 局部注意力(Local Attention)

让我们简要介绍一下这些分类。

全局注意力

这种情况下,注意力集中在所有源位置上。换句话说,编码器的所有隐藏状态都被考虑用于导出参与的上下文向量:

 

局部注意力

这种情况下,只关注几个源位置。仅考虑编码器的几个隐藏状态来导出参与的上下文向量:

 

 

我们将在本文中使用全局注意力机制。

6. 理解问题陈述

客户评论通常很长且具有描述性。正如你可以想象的那样,手动分析这些评论非常耗时。这是自然语言处理可用于生成长评论摘要的地方。

我们将基于一个非常酷的数据集来工作。我们的目标是使用之前学到的基于生成式的方法生成亚马逊美食评论的摘要。

可以从此处下载数据集。
https://www.kaggle.com/snap/amazon-fine-food-reviews

7. 使用Keras在Python中实现文本摘要

现在是时候开启我们的Jupyter notebook了!让我们马上深入了解实施细节。

自定义注意力层

Keras官方没有正式支持注意力层。 因此,我们要么实现自己的注意力层,要么使用第三方实现。在本文中我们采用后者。你可以从此处下载注意力层,并将其复制到名为attention.py的文件中。

https://github.com/thushv89/attention_keras/blob/master/layers/attention.py

将它导入我们的环境:

from attention import AttentionLayer  

导入库


import numpy as np    
import pandas as pd   
import re             
from bs4 import BeautifulSoup   
from keras.preprocessing.text import Tokenizer   
from keras.preprocessing.sequence import pad_sequences  
from nltk.corpus import stopwords     
from tensorflow.keras.layers import Input, LSTM, Embedding, Dense, Concatenate, TimeDistributed, Bidirectional  
from tensorflow.keras.models import Model  
 from tensorflow.keras.callbacks import EarlyStopping  
 import warnings  
 pd.set_option("display.max_colwidth", 200)  
 warnings.filterwarnings("ignore")

读取数据集

该数据集包括亚马逊美食的评论。 这些数据涵盖了超过10年的时间,截至2012年10月的所有约500,000条评论。这些评论包括产品和用户信息,评级,纯文本评论和摘要。它还包括来自所有其他亚马逊类别的评论。

我们将抽样出100,000个评论,以缩短模型的训练时间。如果你的机器具有强大的计算能力,也可以使用整个数据集来训练模型。


data=pd.read_csv("../input/amazon-fine-food-reviews/Reviews.csv",nrows=100000)  

删除重复项和NA值


data.drop_duplicates(subset=['Text'],inplace=True)  #dropping duplicates  
data.dropna(axis=0,inplace=True)   #dropping na  

预处理

在我们进入模型构建部分之前,执行基本的预处理步骤非常重要。使用脏乱和未清理的文本数据是一个潜在的灾难性举措。因此,在此步骤中,我们将从文本中删除不影响问题目标的所有不需要的符号,字符等。

这是我们用于扩展缩略形式的字典:


contraction_mapping = {"ain't": "is not", "aren't": "are not","can't": "cannot", "'cause": "because", "could've": "could have", "couldn't": "could not",  
  
                           "didn't": "did not", "doesn't": "does not", "don't": "do not", "hadn't": "had not", "hasn't": "has not", "haven't": "have not",  
  
                           "he'd": "he would","he'll": "he will", "he's": "he is", "how'd": "how did", "how'd'y": "how do you", "how'll": "how will", "how's": "how is",  
  
                           "I'd": "I would", "I'd've": "I would have", "I'll": "I will", "I'll've": "I will have","I'm": "I am", "I've": "I have", "i'd": "i would",  
  
                           "i'd've": "i would have", "i'll": "i will",  "i'll've": "i will have","i'm": "i am", "i've": "i have", "isn't": "is not", "it'd": "it would",  
   
                            "it'd've": "it would have", "it'll": "it will", "it'll've": "it will have","it's": "it is", "let's": "let us", "ma'am": "madam",  
   
                            "mayn't": "may not", "might've": "might have","mightn't": "might not","mightn't've": "might not have", "must've": "must have",  
   
                            "mustn't": "must not", "mustn't've": "must not have", "needn't": "need not", "needn't've": "need not have","o'clock": "of the clock",  
   
                            "oughtn't": "ought not", "oughtn't've": "ought not have", "shan't": "shall not", "sha'n't": "shall not", "shan't've": "shall not have",  
   
                            "she'd": "she would", "she'd've": "she would have", "she'll": "she will", "she'll've": "she will have", "she's": "she is",  
   
                            "should've": "should have", "shouldn't": "should not", "shouldn't've": "should not have", "so've": "so have","so's": "so as",  
   
                            "this's": "this is","that'd": "that would", "that'd've": "that would have", "that's": "that is", "there'd": "there would",  
   
                            "there'd've": "there would have", "there's": "there is", "here's": "here is","they'd": "they would", "they'd've": "they would have",  
   
                            "they'll": "they will", "they'll've": "they will have", "they're": "they are", "they've": "they have", "to've": "to have",  
   
                            "wasn't": "was not", "we'd": "we would", "we'd've": "we would have", "we'll": "we will", "we'll've": "we will have", "we're": "we are",  
   
                            "we've": "we have", "weren't": "were not", "what'll": "what will", "what'll've": "what will have", "what're": "what are",  
   
                            "what's": "what is", "what've": "what have", "when's": "when is", "when've": "when have", "where'd": "where did", "where's": "where is",  
   
                            "where've": "where have", "who'll": "who will", "who'll've": "who will have", "who's": "who is", "who've": "who have",  
   
                            "why's": "why is", "why've": "why have", "will've": "will have", "won't": "will not", "won't've": "will not have",  
   
                            "would've": "would have", "wouldn't": "would not", "wouldn't've": "would not have", "y'all": "you all",  
   
                            "y'all'd": "you all would","y'all'd've": "you all would have","y'all're": "you all are","y'all've": "you all have",  
   
                            "you'd": "you would", "you'd've": "you would have", "you'll": "you will", "you'll've": "you will have",  
   
                            "you're": "you are", "you've": "you have"}  

我们需要定义两个不同的函数来预处理评论并生成摘要,因为文本和摘要中涉及的预处理步骤略有不同。

a)文字清理

让我们看一下数据集中的前10个评论,以了解该如何进行文本预处理步骤:

data['Text'][:10]  

输出:

 

 

我们将为我们的数据执行以下预处理任务:

  • 将所有内容转换为小写
  • 删除HTML标签
  • 缩略形式映射
  • 删除('s)
  • 删除括号内的任何文本()
  • 消除标点符号和特殊字符
  • 删除停用词
  • 删除简短的单词

让我们定义一下这个函数:


stop_words = set(stopwords.words('english'))   
def text_cleaner(text):  
    newString = text.lower()  
    newString = BeautifulSoup(newString, "lxml").text  
    newString = re.sub(r'\([^)]*\)', '', newString)  
    newString = re.sub('"','', newString)  
    newString = ' '.join([contraction_mapping[t] if t in contraction_mapping else t for t in newString.split(" ")])      
    newString = re.sub(r"'s\b","",newString)  
    newString = re.sub("[^a-zA-Z]", " ", newString)   
     tokens = [w for w in newString.split() if not w in stop_words]  
     long_words=[]  
     for i in tokens:  
         if len(i)>=3:                  #removing short word  
             long_words.append(i)     
     return (" ".join(long_words)).strip()  
   
 cleaned_text = []  
 for t in data['Text']:  
     cleaned_text.append(text_cleaner(t))  

b)摘要清理

现在,我们将查看前10行评论,以了解摘要列的预处理步骤:


1. data['Summary'][:10] 

输出:

 

 

定义此任务的函数:


def summary_cleaner(text):  
    newString = re.sub('"','', text)  
    newString = ' '.join([contraction_mapping[t] if t in contraction_mapping else t for t in newString.split(" ")])      
    newString = re.sub(r"'s\b","",newString)  
    newString = re.sub("[^a-zA-Z]", " ", newString)  
    newString = newString.lower()  
    tokens=newString.split()  
    newString=''  
    for i in tokens:  
         if len(i)>1:                                   
             newString=newString+i+' '    
     return newString  
   
 #Call the above function  
 cleaned_summary = []  
 for t in data['Summary']:  
     cleaned_summary.append(summary_cleaner(t))  
   
 data['cleaned_text']=cleaned_text  
 data['cleaned_summary']=cleaned_summary  
 data['cleaned_summary'].replace('', np.nan, inplace=True)  
 data.dropna(axis=0,inplace=True)  

请记住在摘要的开头和结尾添加START和END特殊标记:


 data['cleaned_summary'] = data['cleaned_summary'].apply(lambda x : '_START_ '+ x + ' _END_')  

现在,我们来看看前5个评论及其摘要:

for i in range(5):  
     print("Review:",data['cleaned_text'][i])  
     print("Summary:",data['cleaned_summary'][i])  
     print("\n")  

输出:

 

 

了解序列的分布

在这里,我们将分析评论和摘要的长度,以全面了解文本长度的分布。这将帮助我们确定序列的最大长度:


import matplotlib.pyplot as plt  
text_word_count = []  
summary_word_count = []  
  
# populate the lists with sentence lengths  
for i in data['cleaned_text']:  
      text_word_count.append(len(i.split()))  
  
for i in data['cleaned_summary']:  
       summary_word_count.append(len(i.split()))  
   
 length_df = pd.DataFrame({'text':text_word_count, 'summary':summary_word_count})  
 length_df.hist(bins = 30)  
 plt.show()  

输出:

 

 

有趣。我们可以将评论的最大长度固定为80,因为这似乎是多数评论的长度。同样,我们可以将最大摘要长度设置为10:


max_len_text=80   
max_len_summary=10  

我们越来越接近模型的构建部分了。在此之前,我们需要将数据集拆分为训练和验证集。我们将使用90%的数据集作为训练数据,并在其余10%上评估(保留集)表现:


from sklearn.model_selection import train_test_split  
x_tr,x_val,y_tr,y_val=train_test_split(data['cleaned_text'],data['cleaned_summary'],test_size=0.1,random_state=0,shuffle=True)   

准备分词器(Tokenizer)

分词器构建词汇表并将单词序列转换为整数序列。继续为文本和摘要构建分词器:

a) 文本分词器


 #prepare a tokenizer for reviews on training data  
 x_tokenizer = Tokenizer()  
 x_tokenizer.fit_on_texts(list(x_tr))  
   
 #convert text sequences into integer sequences  
 x_tr    =   x_tokenizer.texts_to_sequences(x_tr)   
 x_val   =   x_tokenizer.texts_to_sequences(x_val)  
   
 #padding zero upto maximum length  
 x_tr    =   pad_sequences(x_tr,  maxlen=max_len_text, padding='post')   
 x_val   =   pad_sequences(x_val, maxlen=max_len_text, padding='post')  
   
 x_voc_size   =  len(x_tokenizer.word_index) +1  

b)摘要分词器


#preparing a tokenizer for summary on training data   
y_tokenizer = Tokenizer()  
y_tokenizer.fit_on_texts(list(y_tr))  
#convert summary sequences into integer sequences  
y_tr    =   y_tokenizer.texts_to_sequences(y_tr)   
y_val   =   y_tokenizer.texts_to_sequences(y_val)   
#padding zero upto maximum length  

 y_tr    =   pad_sequences(y_tr, maxlen=max_len_summary, padding='post')  
 y_val   =   pad_sequences(y_val, maxlen=max_len_summary, padding='post')  
 y_voc_size  =   len(y_tokenizer.word_index) +1  

模型构建

终于来到了模型构建的部分。但在构建之前,我们需要熟悉所需的一些术语。

  • Return Sequences = True:当return sequences参数设置为True时,LSTM为每个时间步生成隐藏状态和单元状态
  • Return State = True:当return state = True时,LSTM仅生成最后一个时间步的隐藏状态和单元状态
  • Initial State:用于在第一个时间步初始化LSTM的内部状态
  • Stacked LSTM:Stacked LSTM具有多层LSTM堆叠在彼此之上。这能产生更好地序列表示。我鼓励你尝试将LSTM的多个层堆叠在一起(这是一个很好的学习方法)

在这里,我们为编码器构建一个3层堆叠LSTM:


from keras import backend as K   
K.clear_session()   
latent_dim = 500   
  
# Encoder   
encoder_inputs = Input(shape=(max_len_text,))   
enc_emb = Embedding(x_voc_size, latent_dim,trainable=True)(encoder_inputs)   
  
#LSTM 1   
 encoder_lstm1 = LSTM(latent_dim,return_sequences=True,return_state=True)   
 encoder_output1, state_h1, state_c1 = encoder_lstm1(enc_emb)   
   
 #LSTM 2   
 encoder_lstm2 = LSTM(latent_dim,return_sequences=True,return_state=True)   
 encoder_output2, state_h2, state_c2 = encoder_lstm2(encoder_output1)   
   
 #LSTM 3   
 encoder_lstm3=LSTM(latent_dim, return_state=True, return_sequences=True)   
 encoder_outputs, state_h, state_c= encoder_lstm3(encoder_output2)   
   
 # Set up the decoder.   
 decoder_inputs = Input(shape=(None,))   
 dec_emb_layer = Embedding(y_voc_size, latent_dim,trainable=True)   
 dec_emb = dec_emb_layer(decoder_inputs)   
   
 #LSTM using encoder_states as initial state  
 decoder_lstm = LSTM(latent_dim, return_sequences=True, return_state=True)   
 decoder_outputs,decoder_fwd_state, decoder_back_state = decoder_lstm(dec_emb,initial_state=[state_h, state_c])   
   
 #Attention Layer  
 Attention layer attn_layer = AttentionLayer(name='attention_layer')   
 attn_out, attn_states = attn_layer([encoder_outputs, decoder_outputs])   
   
 # Concat attention output and decoder LSTM output   
 decoder_concat_input = Concatenate(axis=-1, name='concat_layer')([decoder_outputs, attn_out])  
   
 #Dense layer  
 decoder_dense = TimeDistributed(Dense(y_voc_size, activation='softmax'))   
 decoder_outputs = decoder_dense(decoder_concat_input)   
   
 # Define the model  
 model = Model([encoder_inputs, decoder_inputs], decoder_outputs)   
 model.summary()

输出:


我使用sparse categorical cross-entropy作为损失函数,因为它在运行中将整数序列转换为独热(one-hot)向量。这克服了任何内存问题。

 


 model.compile(optimizer='rmsprop', loss='sparse_categorical_crossentropy') 

还记得early stopping的概念吗?它用于通过监视用户指定的度量标准,在适当的时间停止训练神经网络。在这里,我监视验证集损失(val_loss)。一旦验证集损失反弹,我们的模型就会停止训练:


es = EarlyStopping(monitor='val_loss', mode='min', verbose=1)  

我们将在批量大小为512的情况下训练模型,并在保留集(我们数据集的10%)上验证它:


history=model.fit([x_tr,y_tr[:,:-1]], y_tr.reshape(y_tr.shape[0],y_tr.shape[1], 1)[:,1:] ,epochs=50,callbacks=[es],batch_size=512, validation_data=([x_val,y_val[:,:-1]], y_val.reshape(y_val.shape[0],y_val.shape[1], 1)[:,1:]))  

了解诊断图

现在,我们将绘制一些诊断图来了解模型随时间的变化情况:


from matplotlib import pyplot   
pyplot.plot(history.history['loss'], label='train')   
pyplot.plot(history.history['val_loss'], label='test')   
pyplot.legend() pyplot.show()  

输出:

 

 

我们可以推断,在第10个周期(epoch)之后,验证集损失略有增加。因此,我们将在此之后停止训练模型。

接下来,让我们构建字典,将目标和源词汇表中的索引转换为单词:

 reverse_target_word_index=y_tokenizer.index_word   
 reverse_source_word_index=x_tokenizer.index_word   
 target_word_index=y_tokenizer.word_index  

推理

设置编码器和解码器的推理:


# encoder inference  
encoder_model = Model(inputs=encoder_inputs,outputs=[encoder_outputs, state_h, state_c])  
  
# decoder inference  
# Below tensors will hold the states of the previous time step  
decoder_state_input_h = Input(shape=(latent_dim,))  
decoder_state_input_c = Input(shape=(latent_dim,))  
decoder_hidden_state_input = Input(shape=(max_len_text,latent_dim))  
  
 # Get the embeddings of the decoder sequence  
 dec_emb2= dec_emb_layer(decoder_inputs)  
   
 # To predict the next word in the sequence, set the initial states to the states from the previous time step  
 decoder_outputs2, state_h2, state_c2 = decoder_lstm(dec_emb2, initial_state=[decoder_state_input_h, decoder_state_input_c])  
   
 #attention inference  
 attn_out_inf, attn_states_inf = attn_layer([decoder_hidden_state_input, decoder_outputs2])  
 decoder_inf_concat = Concatenate(axis=-1, name='concat')([decoder_outputs2, attn_out_inf])  
   
 # A dense softmax layer to generate prob dist. over the target vocabulary  
 decoder_outputs2 = decoder_dense(decoder_inf_concat)  
   
 # Final decoder model  
 decoder_model = Model(  
 [decoder_inputs] + [decoder_hidden_state_input,decoder_state_input_h, decoder_state_input_c],  
 [decoder_outputs2] + [state_h2, state_c2])

下面我们定义了一个函数,是推理过程的实现(我们在上一节中介绍过):


1. def decode_sequence(input_seq):  
def decode_sequence(input_seq):  
    # Encode the input as state vectors.  
    e_out, e_h, e_c = encoder_model.predict(input_seq)  
  
    # Generate empty target sequence of length 1.  
    target_seq = np.zeros((1,1))  
  
    # Chose the 'start' word as the first word of the target sequence  
    target_seq[0, 0] = target_word_index['start']  
   
     stop_condition = False  
     decoded_sentence = ''  
     while not stop_condition:  
         output_tokens, h, c = decoder_model.predict([target_seq] + [e_out, e_h, e_c])  
   
         # Sample a token  
         sampled_token_index = np.argmax(output_tokens[0, -1, :])  
         sampled_token = reverse_target_word_index[sampled_token_index]  
   
         if(sampled_token!='end'):  
             decoded_sentence += ' '+sampled_token  
   
             # Exit condition: either hit max length or find stop word.  
             if (sampled_token == 'end' or len(decoded_sentence.split()) >= (max_len_summary-1)):  
                 stop_condition = True  
   
         # Update the target sequence (of length 1).  
         target_seq = np.zeros((1,1))  
         target_seq[0, 0] = sampled_token_index  
   
         # Update internal states  
         e_h, e_c = h, c  
   
     return decoded_sentence

我们来定义函数,用于将摘要和评论中的整数序列转换为单词序列:


1. def seq2summary(input_seq):  
 def seq2summary(input_seq):  
     newString=''  
     for i in input_seq:  
       if((i!=0 and i!=target_word_index['start']) and i!=target_word_index['end']):  
         newString=newString+reverse_target_word_index[i]+' '  
     return newString  
   
 def seq2text(input_seq):  
     newString=''  
     for i in input_seq:  
       if(i!=0):  
         newString=newString+reverse_source_word_index[i]+' '  
     return newString  
 for i in range(len(x_val)):  
   print("Review:",seq2text(x_val[i]))  
   print("Original summary:",seq2summary(y_val[i]))  
   print("Predicted summary:",decode_sequence(x_val[i].reshape(1,max_len_text)))
   print("\n")

以下是该模型生成的一些摘要:

 

 

 

 

 

 

这真的很酷。即使我们模型生成的摘要和实际摘要并不完全匹配,但它们都传达了相同的含义。我们的模型能够根据文本中的上下文生成清晰的摘要。

以上就是我们如何使用Python中的深度学习概念执行文本摘要。

我们如何进一步提高模型的性能?

你的学习并不止于此!你可以做更多的事情来尝试模型:

  • 我建议你增加训练数据集大小并构建模型。随着训练数据集大小的增加,深度学习模型的泛化能力增强
  • 尝试实现双向LSTM,它能够从两个方向捕获上下文,并产生更好的上下文向量
  • 使用集束搜索策略(beam search strategy)解码测试序列而不是使用贪婪方法(argmax)
  • 根据BLEU分数评估模型的性能
  • 实现pointer-generator网络和覆盖机制

8. 注意力机制如何运作?

现在,我们来谈谈注意力机制的内部运作原理。正如我在文章开头提到的那样,这是一个数学密集的部分,所以将其视为可选部分。不过我仍然强烈建议通读来真正掌握注意力机制的运作方式。

编码器输出源序列中每个时间步j的隐藏状态(hj)。

类似地,解码器输出目标序列中每个时间步i的隐藏状态(si)。

我们计算一个被称为对齐分数(eij)的分数,基于该分数,源词与目标词对齐。使用得分函数从源隐藏状态hj和目标隐藏状态si计算对齐得分。由下面公式给出:
eij =score(si,hj)

其中eij表示目标时间步i和源时间步j的对齐分数。

根据所使用评分函数的类型,存在不同类型的注意力机制。我在下面提到了一些流行的注意力机制:

 

 

我们使用softmax函数标准化对齐分数以获得注意力权重(aij):

 


我们计算注意力权重aij和编码器hj的隐藏状态的乘积的线性和,以产生参与的上下文向量(Ci):

 

将参与的上下文向量和在时间步长i处的解码器的目标隐藏状态连接以产生参与的隐藏向量Si;

 


然后将参与的隐藏向量Si送入dense层以产生yi;


让我们借助一个例子来理解上面的注意力机制步骤。将源序列视为[x1,x2,x3,x4],将目标序列视为[y1,y2]。

  • 编码器读取整个源序列并输出每个时间步的隐藏状态,如h1,h2,h3,h4

     

  • 解码器读取偏移一个时间步的整个目标序列,并输出每个时间步的隐藏状态,如s1,s2,s3

     

     

    目标时间步i = 1

  • 使用得分函数从源隐藏状态hi和目标隐藏状态s1计算对齐得分e1j:

     

  • 使用softmax标准化对齐分数e1j会产生注意力权重a1j:

     

     

    参与的上下文向量C1由编码器隐藏状态hj和对齐分数a1j的乘积的线性和导出:

     

     

  • 将参与的上下文向量C1和目标隐藏状态s1连接以产生参与的隐藏向量S1

     

  • 然后将隐藏向量S1送到全连接层中以产生y1

     

     

    目标时间步i = 2

  • 使用给出的得分函数从源隐藏状态hi和目标隐藏状态s2计算对齐分数e2j

     

  • 使用softmax标准化对齐分数e2j会产生注意力权重a2j:

     

  • 参与的上下文向量C2由编码器隐藏状态hi和对齐分数a2j的乘积的线性和导出:

     

     

  • 将参与的上下文向量C2和目标隐藏状态s2连接以产生参与的隐藏向量S2

     

  • 然后将隐藏向量S2送到全连接层中以产生y2

     

     

    我们可以对目标时间步i = 3执行类似的步骤以产生y3。

我知道这部分数学和理论有点多,但理解这一点将帮助你掌握注意力机制背后的基本思想。它已经催生了NLP最近的许多发展,现在轮到你了!

代码

请在这里找到整个notebook。

https://github.com/aravindpai/How-to-build-own-text-summarizer-using-deep-learning/blob/master/How_to_build_own_text_summarizer_using_deep_learning.ipynb

结语

深吸一口气,我们在本文中介绍了很多内容。并祝贺你使用深度学习构建了第一个文本摘要模型!我们已经了解了如何使用Python中的Seq2Seq构建自己的文本摘要生成器。

深度学习文本摘要:使用深度神经网络生成精确的文本摘要 传统的文本摘要方法通常依赖于手工设计的规则和特征工程,而深度学习技术的出现为自动化文本摘要提供了新的可能性。本文将介绍使用深度神经网络生成精确的文本摘要的方法,并提供相应的源代码。此外,为了提高模型的性能,可以考虑使用更大规模的数据集进行训练,并采用一些技巧,如批次训练、提前停止等。总结起来,本文介绍了使用深度神经网络生成文本摘要的方法,并提供了相应的源代码。数据集的预处理包括分词、去除停用词等步骤,以便于模型的训练和测试。通过上述代码,我们成功构建了一个基于注意力机制的文本摘要生成模型,并进行了训练。 阅读详情

相关推荐

【NLP】文本摘要的SOTA模型及简单代码实现

文本摘要是将一段长文本缩减为一段简短的内容要点的过程。它可以帮助人们快速地了解一篇文章或一段文字的主要内容,节省时间和精力。文本摘要通常分为两种类型:提取式摘要和生成式摘要。提取式摘要使用文本中已有的句子或段落来生成摘要。这种方法通常涉及到对文本进行语言处理和关键词提取,然后从中选择最重要或最相关的内容。生成式摘要则是从头开始生成一段新的摘要内容,而不是仅仅从原文中提取已有的句子或段落。这种方法通常涉及到使用机器学习算法或深度学习模型对文本进行理解和总结,然后根据这些理解和总结来生成新的内容。

sikh_0529的博客 6424

小试牛刀:应用深度强化学习优化文本摘要思路及在裁判文书摘要上的实践效果

该文是本人在研究强化学习时的突发奇想,初步验证了引入合适的奖励函数来优化抽取式摘要模型是有效的。

余俊晖,NLP炼丹师,目前专注自然语言处理领域研究。曾获得国内外自然语言处理算法竞赛TOP奖项近二十项。 1748

使用Python实现文本自动摘要

文本自动摘要分为抽取式摘要和生成式摘要两种方法。其中抽取式摘要是从原文中选择一定比例的句子拼凑成一个摘要,而生成式摘要是通过对原文进行解析、理解、推理等方式生成摘要。但需要注意的是,文本自动摘要技术只能帮助我们了解文章大意,并不能取代阅读。在互联网时代,信息量不断增加,但人类阅读速度是有限的,如何高效地阅读和获取信息成为一项重要的任务。接着,在使用文本自动摘要前,我们需要对原文进行分词,因为摘要需要从句子或者词汇中选择关键信息。接着,我们需要计算每个句子的权重,以便于选择出摘要句子。

学习使你进步。 1509

深度学习文本摘要_使用深度神经网络的文本摘要

深度学习文本摘要 介绍 (Introduction) The amount of textual data being produced every day is increasing rapidly both in terms of complexity as well as volume. Social Media, News articles, emails, text messages (...

weixin_26704853的博客 1909

使用 Python 爬虫爬取新闻数据并训练文本摘要模型:从数据采集到自动化摘要生成

通常,新闻的描述部分可以作为模型的摘要标签。在本例中,我们假设每篇新闻的描述就是它的实际摘要。python复制编辑在文本摘要任务中,使用预训练的序列到序列(Seq2Seq)模型是当前的最佳实践。BART(Bidirectional and Auto-Regressive Transformers)模型是一个强大的预训练模型,适合进行文本生成任务。我们将使用Hugging Face 的库来加载和训练 BART 模型。python复制编辑# 加载预训练的 BART 模型和分词器# 定义训练函数。

2201_76125261的博客 563

基于Python的知乎日报数据抓取与文本摘要生成

本文介绍了如何利用Python实现知乎日报数据的自动抓取和文本摘要生成。通过分析知乎日报API接口,使用requests+BeautifulSoup抓取文章内容,并采用HTML清理和TextRank算法实现提取式摘要。示例代码展示了从数据获取到摘要生成的全流程,帮助用户快速获取知乎日报精华内容。未来可结合深度学习模型提升摘要质量,构建个性化推荐系统。该方法为高效获取网络信息提供了实用解决方案。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 437

独家 | Python利用深度学习进行文本摘要的综合指南(附教程)

作者:ARAVIND PAI翻译:和中华校对:申利彬本文约7500字,建议阅读15分钟。本文介绍了如何利用seq2seq来建立一个文本摘要模型,以及其中的注意力机制。并利...

数据派THU 6110

中英文文献标题及摘要情感分析与可视化 Python

本文介绍了如何使用Python进行中英文文献标题及摘要的情感分析,并通过可视化方式展示情感分析结果。情感分析可以帮助我们了解文本中所表达的情感倾向,为决策和评估提供有价值的信息。通过使用上述的情感分析和可视化方法,我们可以对中英文文献标题及摘要进行情感分析,并将结果可视化展示出来。本文介绍了如何使用Python进行中英文文献标题及摘要的情感分析,并通过可视化方式展示情感分析结果。通过对文本的情感分析,我们可以了解用户对于某个主题、产品或事件的态度和情感倾向,为决策提供有价值的信息。希望本文对你有所帮助!

CodeHeroicX的博客 245

Python利用深度学习进行文本摘要的综合指南!

介绍 “我不想要完整的报告,只需给我一个结果摘要”。我发现自己经常处于这种状况——无论是在大学还是在职场中。我们准备了一份综合全面的报告,但教师/主管却仅仅有时间阅读摘要。 Python资源共享群:484031800 听起来很熟悉?好吧,我决定对此采取一些措施。手动将报告转换为摘要太耗费时间了,对吧?那我可以依靠自然语言处理(NLP)技术来帮忙吗? 自然语言处理(NLP) https:/...

Pythoncxy的博客 2347

AI:141-利用自然语言处理改进医疗信息提取与分类

AI:141-利用自然语言处理改进医疗信息提取与分类 在人工智能领域,自然语言处理(Natural Language Processing,NLP)技术的发展为医疗信息提取与分类提供了强大的工具。随着医学领域数据的快速增长,以及医疗文本的复杂性,传统的信息提取和分类方法显得力不从心。本文将探讨如何利用自然语言处理技术改进医疗信息的提取和分类,并提供一个简单的代码实例。

一键难忘的博客 4657

Hive数据仓库分层架构实战:4层黄金模型×6大业务场景×万亿级数据优化方案

根据《2023数据中台成熟度报告》,‌78%的ETL任务性能瓶颈‌源于分层设计不合理。本文基于某头部电商平台PB级数据仓库建设经验,结合金融风控、用户画像、实时大屏等核心场景,深度解析‌ODS→DWD→DWS→ADS‌四层架构设计原则,揭秘‌万亿级数据治理方案‌与‌维度建模20大避坑策略‌。

优快云博客专家,领域包括但不限于:AI、大数据、Python、架构师,有合作、课程、问题、疑惑请私信博主 1484

Python利用深度学习进行文本摘要的综合指南!

介绍 “我不想要完整的报告,只需给我一个结果摘要”。我发现自己经常处于这种状况——无论是在大学还是在职场中。我们准备了一份综合全面的报告,但教师/主管却仅仅有时间阅读摘要。 听起来很熟悉?好吧,我决定对此采取一些措施。手动将报告转换为摘要太耗费时间了,对吧?那我可以依靠自然语言处理(NLP)技术来帮忙吗? Python资源共享群:484031800 自然语言处理(NLP) https:...

Pythoncxy的博客 880

C2000 ePWM与SDFM同步配置:从寄存器到Driverlib实战解析

在嵌入式实时控制系统中,脉宽调制(PWM)是实现电机驱动、数字电源等应用的核心技术,其信号质量和时序精度直接决定了系统性能。为实现精确控制,PWM信号常需与模数转换器(ADC)或Sigma-Delta滤波器(SDFM)的采样时刻严格同步,以消除开关噪声并获取准确的反馈信号。其技术原理在于通过硬件同步机制,将PWM的特定时间点(如周期中心)作为触发源,控制数据采集的启动时刻。这种硬件级同步能有效提升闭环控制的稳定性和动态响应速度,广泛应用于伺服驱动、变频器等高性能场景。本文聚焦于TI C2000系列微控制器,

weixin_33692284的博客 444

python基于LSTM的新闻文本摘要系统

基于LSTM(长短时记忆网络)的新闻文本摘要系统是一种利用深度学习技术自动生成新闻摘要的系统。以下是对该系统的详细介绍:一、系统概述新闻文本摘要系统的核心任务是将长篇的新闻文章自动转换为简短、精炼的摘要,同时保留原文的关键信息。基于LSTM的系统在这一任务中表现出了显著的优势,因为LSTM能够捕捉文本中的长期依赖关系,这对于理解新闻文章的上下文和生成准确的摘要至关重要。

qq_1262330535的博客 530

激光可燃气体传感器:核心技术环节分析

激光可燃气体传感器核心技术涵盖七个维度:1)TDLAS光谱吸收与调制技术(检测下限ppm级);2)DFB激光器与双闭环温控系统(波长稳定性±0.0036nm);3)微弱信号处理技术(信噪比提升60dB);4)环境补偿算法(温压补偿误差<±1%);5)本质安全防爆设计(ExiaIICT4Ga等级);6)智能边缘计算(STM32L476芯片);7)多重性能验证(响应时间<1秒)。通过微型化、多气体检测等创新,该技术已在工业安全等领域替代传统方案,实现高精度检测。(149字)

上市公司前技术负责人,20 年软硬件深耕 + 百人研发团队管理经验,名校理工科背景加持。从技术攻坚到团队掌舵,沉淀海量项目实战与管理心得,专注分享软硬件干货、疑难问题解决方案,既是靠谱知识传播者,也盼链接优质项目共成长。 1042

全双工AI语音交互:从原理到实践,构建实时对话系统

语音交互技术正从传统的半双工模式向全双工模式演进,以实现更自然、实时的对话体验。全双工交互的核心原理在于模拟人类电话通话,允许双方同时发送和接收音频流,这需要流式语音识别(Streaming ASR)和实时自然语言理解(Real-time NLU)技术的深度整合。其技术价值在于显著降低交互延迟,支持智能打断(Barge-in),从而提升人机对话的流畅度和自然度。在应用场景上,全双工技术是智能助手、实时翻译、车载语音及无障碍交互等领域的关键突破。本文以微软MAI Realtime等模型为例,探讨如何利用开源技

weixin_33693070的博客 404

PyScribe:智能文本转录与总结工具的革命

PyScribe:智能文本转录与总结工具的革命 PyScribeDEPCRECATED/UNMAINTAINED - A Python library to make debugging with print statements simpler and more effective.项目地址:https://gitcode.com/gh_mirrors/py/PyScribe 项目简介 是一个...

gitblog_00025的博客 840

AgentScope Java多智能体框架

AgentScope Java 的核心设计理念是“Agent-Oriented Programming” (面向智能体编程)。

zzz19920821的博客 1737

关键词提取和摘要生成是文本处理和分析系统

关键词提取和摘要生成是文本处理和分析领域中的重要任务。拟解决的关键问题:本研究将从以下几个方面来解决现有的文本关键词提取和摘要生成问题:1. 数据集的募集和筛选:本研究将募集大量的中文文本数据集,并对其进行筛选,以保证数据集的质量;2. 基于深度学习的关键词提取和摘要生成算法的改进:本研究将基于深度学习的关键词提取和摘要生成算法进行改进,以提高其提取效果和摘要生成的质量;3. 应用价值的评估:本研究将评估基于深度学习的文本关键词提取和摘要生成方法在文本处理和分析中的应用价值,以验证其在实际应用中的可行性。

825

利用Python爬虫采集京东商品评论情感分析案例(含完整代码)

在电商蓬勃发展的今天,商品评论蕴含着巨大的商业价值。本文以京东商品评论为研究对象,系统介绍如何使用Python构建一个完整的评论采集与情感分析系统。文章涵盖京东反爬机制分析、动态请求模拟、评论数据解析、中文文本预处理、基于SnowNLP和深度学习的情感极性分类、以及可视化展示等完整技术链路。所有代码均基于2025-2026年最新可用接口编写,并提供可直接运行的完整源码。全文力求详实,总字数逾八千字,适合Python数据分析从业者、电商运营人员及自然语言处理初学者参考实践。目录摘要第一章 引言。

2201_76125261的博客 88

一套适合 ABAP 初级和中级开发人员,从入门到提高的 ABAP 学习教程

曾几何时,ABAP 就是 SAP 的代名词。ABAP 这门编程语言造就了 SAP 名噪一时的 R/3 产品,同时也是如今 SAP 旗舰级产品,SAP S/4HANA 底层的实现语言。 ABAP 不仅代表着 SAP 这家公司在企业级管理软件市场辉煌的过去,ABAP 自身也在不断地进化着。SAP 不仅在本地部署(On-Premise)领域继续保持着自己绝对的统治地位,而且在云应用领域(Software-as-a-Service, 简称 SaaS), 也推出了自己的解决方案,比如 SAP S/4HANA Clo

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 5922

ChatTTS——Python自然语言处理项目

  hatTTS是一个基于Python的自然语言处理项目,专注于文本到文本的转换。它能够理解和生成人类语言,适用于各种自然语言处理任务,如情感分析、摘要生成、机器翻译等。

2401_85750860的博客 577

2025华为杯第二十二届中国研究生数学建模竞赛D题:低空湍流监测及最优航路规划 - 完整解题分析+完整MATLAB源码!(上篇)

🎓 本文收录于 《滚雪球学数学建模》专栏,本专栏专注于从零基础出发,带你循序渐进掌握数学建模的核心方法与思维路径。通过“滚雪球式”学习法,从最简单的生活化案例到经典建模工具,再到省赛、国赛真题实战演练,逐步积累知识与技能,帮助你搭建完整的建模体系。无论你是刚接触建模的新生,还是希望提升科研与竞赛能力的学者与工程师,本专栏都将为你提供一条清晰、高效、可实操的建模成长路线,助力你快速进阶,突破难点,迈向数学建模竞赛与实际应用的更高峰 🚀!

**My Coding Family** 2587

使用深度学习进行重要事件抽取:探索`ImportantEventExtractor`

使用深度学习进行重要事件抽取:探索ImportantEventExtractor 在信息爆炸的时代,自动抽取文本中的关键信息变得越来越重要。 是一个基于深度学习的开源项目,旨在帮助开发者和数据科学家高效地从大量文本中提取出重要事件。本文将深入探讨该项目的技术细节、应用场景及其独特优势。 项目简介 ImportantEventExtractor是一个利用自然语言处理(NLP)技术的Python库,专...

gitblog_00009的博客 594

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

上一篇: Python 很慢?Python 之父一句话亮了
下一篇: 利用Python做一个小姐姐词云跳舞视频
酸菜鱼编程
博客等级 码龄6年 155粉丝 63原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值