基于深度学习的新闻摘要生成算法实现与详解(Encoder-Decoder框架模型)
目录
摘要:
摘要是文本的主要内容和核心思想的最小化表达,从海量文本数据中快速寻找有价值的信息具有重要意义。利用深度神经网络Encoder-Decoder基本框架,通过引入注意力模型,本次将尝试实现应用LSTM+attention算法自动生成新闻摘要。首选利用LSTM神经网络编码出中间语义特征,最后利用注意力模型与LSTM神经网络解码出中间语义特征,最终实现自动生成新闻摘要。本次实现算法模型采用keras神经网络编程框架,数据集为英文数据,由于数据量稍微有点大,这次只运行个demo结果。
文本摘要生成概述:
目前主流的文本摘要自动生成有两种方式,一种是抽取式(extractive),另一种是生成式 (abstractive)。
抽取式顾名思义,就是按照一定的权重,从原文中寻找跟中心思想最接近的一条或几条句子。而生成式则是计算机通读原文后,在理解整篇文章意思的基础上,按自己的话生成流畅的翻译。
抽取式摘要是一种比较成熟的方案,其中Text rank排序算法以其简洁、高效的特点被工业界广泛运用。大体思想是先去除文章中的一些停用词,之后对句子的相似度进行度量,计算每一句相对另一句的相似度得分,迭代传播,直到误差小于0.0001。再对上述得到的关键语句进行排序,便能得到想要的摘要。抽取式摘要主要考虑单词词频,并没有过多的语义信息,像“猪八戒”,“孙悟空”这样的词汇都会被独立对待,无法建立文本段落中的完整语义信息。
抽取式的摘要目前已经比较成熟,但是抽取质量及内容流畅度均差强人意。伴随着深度学习的研究,生成式摘要的质量和流畅度都有很大的提升,但目前也受到原文本长度过长、抽取内容不佳等的限制。
生成式文本摘要主要依靠深度神经网络结构实现,2014年由Google Brain团队提出的Sequence-to-Sequence序列(Sequence-to-Sequence又称为编、解码器(Encoder、Decoder)架构),开启了NLP中端到端网络的火热研究。因此,便采用次方法进行摘要的自动生成。
Encoder-Decoder模式思想:
Encoder-Decoder架构是针对序列预测问题组织循环神经网络的一种方式,它具有可变数目的输入、输出,或是输入和输出。该架构涉及两个组件:一个编码器和一个解码器:
编码器:编码器读取整个输入序列,并将其编码为一种中间表示,通常是一个被称为上下文向量的定长向量。对应本文所示的生成摘要来说即是Encoder负责把原文编码为一个向量C;
解码器:解码器从编码器读取编码输入序列,并生成输出序列。对应本文所示的生成摘要来说:Decoder负责从这个向量C中提取信息,获取语义,生成文本摘要。
我看了不少博客及源码解析,个人认为Encoder-Decoder模式,在代码实现及问题解决上我感觉类似于M个输入时间步长去预测输出N个时间步长(many-to-many)的序列预测问题,只是我们采用Encoder-Decoder模式解决文本到文本的输出或者图像到文本的输出,其输出可能不是定长。即是输入输出文本长度可能在变,例如我们输入一段很长(长短不一)的文本,自动生成很短(长短不一)的摘要。在代码实现上,采用传统的LSTM方法很难实现这种方式。因为,LSTM预测输出为预先定义好的固定长度。所以我认为采用编码和解码其实就是通过实现多个神经网络层之间的权值参数的共享,进行输出变长序列(标签)。我认为这种思想和迁移学习冻结神经网络层有点像?额也不确定?
数据集描述:
本数据集为网上找的英文文章及摘要数据集(类似新闻,但是不是那种简报的形式,所以输入较长)。共有6335条样本。其中max_input_seq_length: 500
max_target_seq_length: 50
模型构建与代码描述(LSTM+Attention)
代码结构:
模型结构图:
核心代码(带注释):
def encoder_decoder(data):
print('Encoder_Decoder LSTM...')
"""# 定义训练编码器"""
encoder_inputs = Input(shape=en_shape)#定义输入,n_input表示特征这一维(维的大小即特征的数目)
encoder_LSTM = LSTM(hidden_units,dropout_U=0.2,dropout_W=0.2,return_sequences=True,return_state=True)#定义编码器的,hidden_units即神经元单元数,正向LSTM
encoder_LSTM_rev=LSTM(hidden_units,return_state=True,return_sequences=True,dropout_U=0.05,dropout_W=0.05,go_backwards=True)#反向LSTM,定义编码器的,hidden_units即神经元单元数
encoder_outputs, state_h, state_c = encoder_LSTM(encoder_inputs)# 取出正向LSTM输入生成的隐藏状态和细胞状态,作为解码器的隐藏状态和细胞状态的初始化值。
encoder_outputsR, state_hR, state_cR = encoder_LSTM_rev(encoder_inputs)# 取出反向LSTM输入生成的隐藏状态和细胞状态,作为解码器的隐藏状态和细胞状态的初始化值。
state_hfinal=Add()([state_h,state_hR])
state_cfinal=Add()([state_c,state_cR])
encoder_outputs_final = Add()([encoder_outputs,encoder_outputsR])#综合为BiLSTM输出
encoder_states = [state_hfinal,state_cfinal]#BiLSTM取出反向LSTM输入生成的隐藏状态和细胞状态
"""定义解码器"""
decoder_inputs = Input(shape=(None,de_shape[1]))#解码器输入,n_output:输出响应序列的特征维的大小。
decoder_LSTM = LSTM(hidden_units,return_sequences=True,dropout_U=0.2,dropout_W=0.2,return_state=True)##因解码器用编码器的隐藏状态和细胞状态,所以hidden_units必等
decoder_outputs, _, _ = decoder_LSTM(decoder_inputs,initial_state=encoder_states)# # 这个解码层在后面推断中会被共享!!
#注意力机制
attention = TimeDistributed(Dense(1, activation = 'tanh'))(encoder_outputs_final)#编码输出作为输入
attention = Flatten()(attention)
attention = Multiply()([decoder_outputs, attention])#点乘注意力,decoder_outputs输出与attention点乘
attention = Activation('softmax')(attention)
attention = Permute([2, 1])(attention)
decoder_dense = Dense(de_shape[1],activation='softmax')# 这个full层在后面推断中会被共享
decoder_outputs = decoder_dense(attention)#具有注意力机制的特征作为输入,进行输出,
model= Model(inputs=[encoder_inputs,decoder_inputs], outputs=decoder_outputs)# 定义模型。得到以输入序列和目标序列作为输入,以目标序列的移位为输出的训练模型
print(model.summary())
rmsprop = RMSprop(lr=learning_rate,clipnorm=clip_norm)
model.compile(loss='categorical_crossentropy',optimizer=rmsprop,metrics=['accuracy'])
x_train,x_test,y_train,y_test=tts(data["article"],data["summaries"],test_size=0.20)
history= model.fit(x=[x_train,y_train],
y=y_train,
batch_size=batch_size,
epochs=epochs,
verbose=1,
validation_data=([x_test,y_test], y_test))
print(model.summary())
#定义推断解码器,由于循环网络的性质,由输入状态(前)推理出输出状态(后)
encoder_model_inf = Model(encoder_inputs,encoder_states)
decoder_state_input_H = Input(shape=(en_shape[0],))
decoder_state_input_C = Input(shape=(en_shape[0],))
decoder_state_inputs = [decoder_state_input_H, decoder_state_input_C]
decoder_outputs, decoder_state_h, decoder_state_c = decoder_LSTM(decoder_inputs,
initial_state=decoder_state_inputs)
decoder_states = [decoder_state_h, decoder_state_c]
decoder_outputs = decoder_dense(decoder_outputs)
decoder_model_inf= Model([decoder_inputs]+decoder_state_inputs,
[decoder_outputs]+decoder_states)
scores = model.evaluate([x_test,y_test],y_test, verbose=1)
return model,encoder_model_inf,decoder_model_inf,history
模型训练LOSS函数图像为:
虽然曲线还行,但是输出了一下,生成的摘要并不是很好,所以不在展示。可能是我们的文本太长,数据集不行。
总结:
此次算是初探了Encoder-Decoder架构进行实现文本摘要的自动生成。但文本摘要自动生成依然还有很多难题,比如如果段落太长,那么机器对段落的理解时间就要很长,而过长的时间会导致机器对段落信息的记忆的损失。因此,训练出的模型其结果并不怎么好。因此,我打算下一步找一些好的语料进行测试,以补齐结果展示。接着,试下中文的摘要生成。总的来说,文本摘要自动生成是个非常具有前景但也非常具有挑战性的技术。
参考文献:
https://my.oschina.net/u/3733374/blog/1585590
Bahdanau, Dzmitry, Kyunghyun Cho, and Yoshua Bengio. Neural machine translation by jointly learning to align and translate