基于TextRank+Seq2Seq+Pyqt5文章摘要标题关键词辅助生成系统(含全部python工程源码)+训练数据集

目录

  • 前言
  • 总体设计
    • 系统整体结构图
    • 系统流程图
  • 运行环境
    • Python 环境
    • TextRank环境
    • TensorFlow环境
    • PyQt5及Qt Designer运行环境
  • 模块实现
    • 1. 数据预处理
    • 2. 抽取摘要
    • 3. 模型搭建与编译
    • 4. 模型训练与保存
    • 5. 图形化界面的开发
    • 6. 应用封装
  • 系统测试
    • 1. 训练困惑度
    • 2. 测试效果
    • 3. 模型应用
  • 工程源代码下载
  • 其它资料下载

在这里插入图片描述


前言

本项目以学术论文、维基百科等数据集为基础,通过应用TextRank和Seq2Seq算法对模型进行优化和改进,致力于构建一体化的文章摘要、标题和关键词辅助生成系统。为了提供用户友好的体验,我们设计了可视化界面,并将整个程序封装为可执行文件,可以在PC端直接运行。

首先,我们使用学术论文和维基百科等丰富的数据集作为训练样本。通过训练和优化TextRank算法,我们可以提取文章中的关键句子和关键词,形成精炼的摘要内容。

其次,我们利用Seq2Seq算法进行模型改进,以进一步提高文章相关内容的生成质量。Seq2Seq模型是一种基于循环神经网络(RNN)的序列到序列模型,能够将输入序列转化为输出序列。通过使用Seq2Seq算法,我们可以根据文章内容生成具有概括性和吸引力的标题。

同时,我们还为用户提供了可视化界面,使其能够轻松使用这一一体化的辅助生成系统。用户可以输入文章内容,系统将自动生成文章摘要、标题和关键词,并将结果直观地展示在界面上。

为了方便用户使用,我们将整个项目封装为可执行文件,使其可以在PC端直接运行。这样,用户可以直接打开程序,使用系统提供的功能,而无需进行复杂的配置和设置。

通过本项目的实施,用户可以快速生成具有准确、简洁且吸引人的文章摘要、标题和关键词,大大提高工作效率和创作质量。同时,可视化界面和可执行文件的设计使得系统的使用变得更加便捷和直观,满足用户对于简单易用的需求。

总体设计

本部分包括系统整体结构图和系统流程图。

系统整体结构图

系统整体结构如图所示。

在这里插入图片描述

系统流程图

系统流程如图所示。

在这里插入图片描述

运行环境

本部分包括Python环境、TextRank环境、TensorFlow环境、PyQt5及Qt Designer运行环境。

Python 环境

版本: Python 3. 5。

TextRank环境

从清华仓库镜像中下载numpy-1.9.3.tar.gznetworkx-2.4.tar.gzmath-0.5.tar.gz文件,在本地解压后,使用cmd命令行进入控制台,切换到对应目录中,执行下面命令,完成安装。

python setup.py install 

TensorFlow环境

在终端中,使用pip命令进行安装,使用pip命令安装tensorflow、tarfile、matplotlib、jieba依赖包,实现TensorFlow平台相关模型的准备。

pip3 install <package name>

PyQt5及Qt Designer运行环境

使用pip命令安装与Python语言对应版本的PyQt5工具包,同时在环境中配置PyUIC5和PyQt5-tools,用于图形化界面的快速开发及转换。将上述工具添加至PyCharm编辑器的ExternalTools中。

从PyCharm编辑器的Tools- External Tools中打开Qt Designer,如下图所示,表明Qt Designer安装成功。

在这里插入图片描述

Qt Designer 工具图

模块实现

本项目包括6个模块:数据预处理、抽取摘要、 模型搭建与编译、模型训练与保存、图形化界面的开发和应用封装。下面分别给出各模块的功能介绍及相关代码。

1. 数据预处理

数据预处理下载地址为http://www.sogou.com/labs/resource/cs.php,未经处理的原始数据图如下图所示。

在这里插入图片描述

对于其编码形式,由于文件过大,无法通过打开文件的方式获取编码,采用GBK18030可对其进行编码。处理过程如下。

1)数据提取及划分

使用正则表达式提取数据的内容,按照比例进行训练集和验证集的划分,去除文本内容长度不符合要求的数据,对划分后的标题和内容进行存储,生成的文件使用软件改变编码格式为utf-8。相关代码如下:

a)正则表达式匹配:

for_title='<contenttitle>(.*)</contenttitle>'#筛选标题,去除标签
for_content='<content>(.*)</content>'#筛选内容,去除标签
p1=re.compile(for_title)
p2=re.compile(for_content)

b)将数据筛选进行写入过程:

for i in range(4,len(data.values)+1,6):#针对位置选择相应的数据n=p2.findall(str(data.values[i]))text=n[0]word=textresult=''for w in word:result=result+str(w.word)+' ' 
#对意外的情况进行替换result=result.replace(u'\ u3000','').replace(u'\ ue40c','')
#检查数据长度是否复合需求,太长或者太短,都要舍弃 if len(result)>=1024 or len(result)==0: id.append(i)continue      if i<for_train:f_content_train.write(result+'\n')else:f_content_test.write(result+'\n')print((i/6)/len(range(3,len(data.values)+1,6)))

2)替换和分词

对获得的文本进行标签替换,完成分词操作。相关代码如下:

def token(self, sentence):words = self.segmentor.segment(sentence)  #分词words = list(words)postags = self.postagger.postag(words)    #词性标注postags = list(postags)netags = self.recognizer.recognize(words, postags)#命名实体识别netags = list(netags)result = []for i, j in zip(words, netags):if j in ['S-Nh', 'S-Ni', 'S-Ns']:result.append(j)continueresult.append(i)return result

使用上述代码后,得到4个文件——2 个训练集和2个测试集,对应文件的同一行分别为标题和内容。对所有的文字都进行标签替换,完成分词。

3)数据读取

根据得到的文件进行数据读取,相关代码如下:

data_set = [[] for _ in buckets]  
with tf.gfile.GFile(source_path, mode="r") as source_file:  with tf.gfile.GFile(target_path, mode="r") as target_file:source, target = source_file.readline(), target_file.readline()  counter = 0  #源文件和目标文件while source and target and (not max_size or counter < max_size):  counter += 1  if counter % 10000 == 0:  print("reading data line%d"% counter)#输出信息sys.stdout.flush()  source_ids = [int(x) for x in source.split()]  target_ids = [int(x) for x in target.split()]  target_ids.append(data_utils.EOS_ID)  #添加标识for bucket_id, (source_size, target_size) in enumerate(buckets):  if len(source_ids)<source_size and len(target_ids)<target_size: data_set[bucket_id].append([source_ids, target_ids])  break  source, target = source_file.readline(), target_file.readline()  
return data_set  

该代码会自动读取信息,并将读取的数据存入bucket内,深度学习模型通过学习内容与标题生成,数据预处理在准备数据时进行,使用Python的codecs模块读取即可。

2. 抽取摘要

大多数论文的篇幅都是数万字,直接使用模型对数据进行训练与测试会耗费计算资源。因此,通过文本排序对数据进行重要性提取,算法如下。

1)排序迭代算法

首先,获得二位列表,句子为子列表,元素是单词;其次,通过判断两个单词是否同时出现在同一个时间窗口内确定链接。将所有词添加到图的链接后,使用PageRank算法进行迭代,获得平稳的单词PR值;最后,获取重要的单词列表。

def sort_words(vertex_source, edge_source, window=2, pagerank_config={'alpha': 0.85, }):#对单词的关键程度进行排序
"""
vertex_source:二维列表,子列表代表句子,其元素是单词,用来构造PageRank中的节点
edge_source:二维列表,子列表代表句子,其元素为单词,根据单词位置关系构造PageRank中的边窗口,一个句子中相邻的window个单词,两两之间认为有边
pagerank_config:PageRank的设置
"""sorted_words = []word_index = {}index_word = {}_vertex_source = vertex_source_edge_source = edge_sourcewords_number = 0for word_list in _vertex_source:#对每个句子进行处理,提取包含单词的列表for word in word_list:if not word in word_index:
#更新word_index 假如字典中没有单词,将这个单词与索引添加到字典中word_index[word] = words_numberindex_word[words_number] = word #对word进行反向映射words_number += 1graph = np.zeros((words_number, words_number))
#构建word_number*word_number的矩阵,实现图计算for word_list in _edge_source:for w1, w2 in combine(word_list, window):if w1 in word_index and w2 in word_index:index1 = word_index[w1]index2 = word_index[w2]graph[index1][index2] = 1.0graph[index2][index1] = 1.0
#根据窗口判断其连接nx_graph = nx.from_numpy_matrix(graph)
#构成邻接矩阵scores = nx.pagerank(nx_graph, **pagerank_config)  
#使用PageRank算法进行迭代sorted_scores = sorted(scores.items(), key=lambda item: item[1], reverse=True)for index, score in sorted_scores:item = AttrDict(word=index_word[index], weight=score)sorted_words.append(item)return sorted_words

2)句子相似度算法

在用TextRank算法对句子进行输出时,使用的默认节点是句子,两个节点相互连接的权重使用句子的相似度。相关代码如下:

def get_similarity(word_list1, word_list2):#计算两个句子的相似程度"""默认用于计算两个句子相似度的函数word_list1, word_list2分别代表两个句子,都是由单词组成的列表"""words = list(set(word_list1 + word_list2))vector1 = [float(word_list1.count(word)) for word in words]#统计某个单词在句子中的频率vector2 = [float(word_list2.count(word)) for word in words]vector3 = [vector1[x] * vector2[x] for x in range(len(vector1))]vector4 = [1 for num in vector3 if num > 0.]co_occur_num = sum(vector4)#分子if abs(co_occur_num) <= 1e-12:return 0.denominator = math.log(float(len(word_list1))) + math.log(float(len(word_list2)))  #分母if abs(denominator) < 1e-12:return 0.return co_occur_num / denominator #返回句子的相似度

3. 模型搭建与编译

完成数据集制作后,进行模型搭建、定义模型输入、确定损失函数。

1)模型搭建

以TensorFlow提供的模型为基础,参数使用类进行传递:

class LargeConfig(object): #定义网络结构learning_rate = 1.0  #学习率init_scale = 0.04learning_rate_decay_factor = 0.99 #学习率下降max_gradient_norm = 5.0num_samples = 4096 #采样的Softmaxbatch_size = 64size = 256 #每层节点数num_layers = 4 #层数
vocab_size = 50000
#模型构建
def seq2seq_f(encoder_inputs, decoder_inputs, do_decode):return tf.contrib.legacy_seq2seq.embedding_attention_seq2seq(encoder_inputs,#输入的句子decoder_inputs,#输出的句子cell,#使用的cell、LSTM或者GRUnum_encoder_symbols=source_vocab_size,#源字典的大小num_decoder_symbols=target_vocab_size,#转换后字典的大小embedding_size=size,#embedding的大小output_projection=output_projection,#看字典大小feed_previous=do_decode,#进行训练还是测试dtype=tf.float32)

2)定义模型输入

在模型中,bucket承接输入的字符,所以须为bucket的每个元素构建一个占位符。

#输入self.encoder_inputs = []self.decoder_inputs = []self.target_weights = []for i in xrange(buckets[-1][0]):  self.encoder_inputs.append(tf.placeholder(tf.int32, shape=[None],name="encoder{0}".format(i)))
#为列表对象中的每个元素表示一个占位符,名称分别为encoder0、encoder1...for i in xrange(buckets[-1][1] + 1):self.decoder_inputs.append(tf.placeholder(tf.int32, shape=[None],name="decoder{0}".format(i)))self.target_weights.append(tf.placeholder(tf.float32, shape=[None],name="weight{0}".format(i)))
#target_weights 是一个与 decoder_outputs 大小一样的矩阵
#该矩阵将目标序列长度以外的其他位置填充为标量值0
#目标是将解码器输入移位1targets = [self.decoder_inputs[i + 1]for i in xrange(len(self.decoder_inputs) - 1)]
#将 decoder input向右平移一个单位

3)确定损失函数

在损失函数上,使用TensorFlow中的sampled_softmax_loss()函数。

def sampled_loss(labels, inputs):#使用候选采样损失函数labels = tf.reshape(labels, [-1, 1])
#需要使用32位浮点数计算sampled_softmax_loss,以避免数值不稳定性local_b = tf.cast(b, tf.float32)local_inputs = tf.cast(inputs, tf.float32)return tf.cast(tf.nn.sampled_softmax_loss(  #损失函数weights=local_w_t,biases=local_b,labels=labels,inputs=local_inputs,num_sampled=num_samples,num_classes=self.target_vocab_size),tf.float32)

4. 模型训练与保存

设定模型结构后,定义模型训练函,以导入及调用模型。

1)定义模型训练函数

定义模型训练函数及相关操作。

def train():#准备标题数据print("Preparing Headline data in %s" % FLAGS.data_dir)src_train,,dest_train,src_dev,dest_dev,_,_=data_utils.prepare_headline_data(FLAGS.data_dir, FLAGS.vocab_size)
#将获得的数据进行处理,包括:构建词典、根据词典单词ID的转换,返回路径
config = tf.ConfigProto(device_count={"CPU": 4}, inter_op_parallelism_threads=1, intra_op_parallelism_threads=2) with tf.Session(config = config) as sess:print("Creating %d layers of %d units."%(FLAGS.num_layers, FLAGS.size))model = create_model(sess, False)#创建模型print ("Reading development and training data (limit: %d)."% FLAGS.max_train_data_size)dev_set = read_data(src_dev, dest_dev)train_set = read_data(src_train, dest_train, FLAGS.max_train_data_size)train_bucket_sizes = [len(train_set[b]) for b in xrange(len(buckets))]train_total_size = float(sum(train_bucket_sizes))trainbuckets_scale=[sum(train_bucket_sizes[:i + 1]) / train_total_sizefor i in xrange(len(train_bucket_sizes))]#进行循环训练step_time, loss = 0.0, 0.0current_step = 0previous_losses = []while True:random_number_01 = np.random.random_sample()bucket_id = min([i for i in xrange(len(trainbuckets_scale))if trainbuckets_scale[i] > random_number_01])#随机选择一个bucket进行训练start_time = time.time()encoder_inputs,decoder_inputs,target_weights=model.get_batch(train_set, bucket_id)_,step_loss,_=model.step(sess, encoder_inputs, decoder_inputs,target_weights, bucket_id, False)step_time+=(time.time()-start_time)/FLAGS.steps_per_checkp oint loss += step_loss / FLAGS.steps_per_checkpointcurrent_step += 1if current_step % FLAGS.steps_per_checkpoint == 0:perplexity=math.exp(float(loss))
if	loss<300	
else                                                                         
float("inf")print ("global step %d learning rate %.4f step-time %.2f perplexity ""%.2f" % (model.global_step.eval(), 
model.learning_rate.eval(),step_time, perplexity))   #输出参数if len(previous_losses)>2 and loss > max(previous_losses[-3:]):sess.run(model.learning_rate_decay_op)previous_losses.append(loss)
checkpoint_path=os.path.join(FLAGS.train_dir, "headline_large.ckpt") model.saver.save(sess,checkpoint_path,
global_step=model.global_step) #检查点输出路径step_time, loss = 0.0, 0.0for bucket_id in xrange(len(buckets)):if len(dev_set[bucket_id]) == 0:print("  eval: empty bucket %d" % (bucket_id))continueencoder_inputs,decoder_inputs,target_weights= 
model.get_batch(dev_set, bucket_id)  #编解码及目标加权_,eval_loss,_=model.step(sess,encoder_inputs, 
decoder_inputs, target_weights, bucket_id, True)eval_ppx = math.exp(float(eval_loss))#计算损失 
if eval_loss < 300 
else float("inf")
print("eval:bucket%dperplexity%.2f"%(bucket_id, eval_ppx))#输出困惑度sys.stdout.flush()

2)模型导入及调用

将生成的模型放在/ckpt文件夹内部,运行的过程中加载该模型。当程序获取句子之后,进行以下处理:

while sentence:sen=tf.compat.as_bytes(sentence)sen=sen.decode('utf-8')token_ids = data_utils.sentence_to_token_ids(sen, vocab, 
normalize_digits=False)print (token_ids) # 打印ID#选择合适的bucketbucket_id = min([b for b in xrange(len(buckets)) if buckets[b][0] > len(token_ids)])print ("current bucket id" + str(bucket_id))encoder_inputs, decoder_inputs, target_weights = model.get_batch({bucket_id: [(token_ids, [])]}, bucket_id)#获得模型的输出_, _, output_logits_batch = model.step(sess, encoder_inputs, 
decoder_inputs, target_weights,bucket_id, True)#贪婪解码器 output_logits = []for item in output_logits_batch:output_logits.append(item[0])print (output_logits)print (len(output_logits))print (output_logits[0])outputs = [int(np.argmax(logit)) for logit in output_logits]print(output_logits)#剔除程序对文本进行的标记if data_utils.EOS_ID in outputs:outputs = outputs[:outputs.index(data_utils.EOS_ID)]print(" ".join([tf.compat.as_str(rev_vocab[output]) for output in outputs]))

5. 图形化界面的开发

为提高可用性,将面向代码进行操作的环境转变为面向界面的操作,通过Python提供的QtDesigner及PyQt5环境完成项目的图形化界面。

1)界面设计

从PyCharm的External Tools 中打开配置好的Qt Designer, 创建主窗口,并使用WidgetBox进行组件的布局,如下图所示。

在这里插入图片描述

原生组件的美观性不足,需对各组件进行样式自定义。在监控窗口中选择修改对应组件的样式表,通过添加CSS( Cascading Style Sheets,层叠样式表)完成各组件和界面的美化。如下图所示的美化图展示了“进入程序”按钮的CSS代码,此处分别设置了基础样式、点按样式及鼠标悬浮样式,使按钮的逻辑更贴近真实的使用场景,提升用户体验。

在这里插入图片描述

对主窗口和各组件的样式表修改后进行预览,如下图所示。

在这里插入图片描述

主页设计预览(按钮样式为指针悬浮)图

2)代码转换

将.上述界面设计保存为.ui文件,使用配置好的PyUIC5工具进行处理,得到转换后的.py代码。

对代码中无法通过程序运行渲染出的组件进行调整,例如,通过.qrc文件指定关联引入的icon修改为引用相对地址。相关代码如下:

from PyQt5 import QtCore, QtGui, QtWidgets  #引入所需的库
from PyQt5 import QtCore, QtGui, QtWidgets, Qt  
from PyQt5.QtWidgets import *  
import PreEdit  class Ui_MainWindow_home(QtWidgets.QMainWindow):  #界面类定义def __init__(self):  super(Ui_MainWindow_home,self).__init__()  self.setupUi(self)  self.retranslateUi(self)  def setupUi(self, MainWindow_home):  #设置界面MainWindow_home.setObjectName("MainWindow_home")  MainWindow_home.resize(900, 650)  MainWindow_home.setMinimumSize(QtCore.QSize(900, 650))  MainWindow_home.setMaximumSize(QtCore.QSize(900, 650))  MainWindow_home.setBaseSize(QtCore.QSize(900, 650))  font = QtGui.QFont()  font.setFamily("黑体")  font.setPointSize(12)  MainWindow_home.setFont(font)  #设置字体MainWindow_home.setStyleSheet("QMainWindow#MainWindow_home{\n"  "background:#FFFEF8\n}")  self.centralwidget = QtWidgets.QWidget(MainWindow_home)  self.centralwidget.setStyleSheet("")  #设置表单风格self.centralwidget.setObjectName("centralwidget")  self.pushButton_openfile=QtWidgets.QPushButton(self.centralwidget)self.pushButton_openfile.setGeometry(QtCore.QRect(320,328,258,51))font = QtGui.QFont()  font.setFamily("等线")  font.setPointSize(11)  font.setBold(True)  font.setWeight(75)  self.pushButton_openfile.setFont(font)  #单击按钮,自动浏览文件设置self.pushButton_openfile.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))  self.pushButton_openfile.setStyleSheet("QPushButton#pushButton_openfile{  \n"  "border: 1px solid #9a8878;  \n"  "background-color:#ffffff;\n"  "border-style: solid;  \n"  "border-radius:0px;  \n"  "width: 40px; \n"  "height:20px;  \n"  "padding:0 0px;  \n"  "margin:0 0px;  \n"  "}  \n"  "\n"  "QPushButton#pushButton_openfile:pressed{\n"  "background-color:#FBF7F6;\n"  "border:0.5px solid #DDCFC2;\n"  "}\n"  "\n"  "QPushButton#pushButton_openfile:hover{\n"  "border:0.5px solid #DDCFC2;\n""}")  icon = QtGui.QIcon()  #图标设置icon.addPixmap(QtGui.QPixmap(r".\icon\enter2.png"), 
QtGui.QIcon.Normal, QtGui.QIcon.Off)  icon.addPixmap(QtGui.QPixmap(r".\icon\enter2.png"), 
QtGui.QIcon.Normal, QtGui.QIcon.On)  self.pushButton_openfile.setIcon(icon)  self.pushButton_openfile.setCheckable(False)  self.pushButton_openfile.setObjectName("pushButton_openfile")  self.label_maintitle_shadow=QtWidgets.QLabel(self.centralwidget)self.label_maintitle_shadow.setGeometry(QtCore.QRect(331,188,241, 61))font = QtGui.QFont()  #图形界面的字体设置font.setFamily("微软雅黑")  font.setPointSize(36)  font.setBold(True)  font.setWeight(75)  self.label_maintitle_shadow.setFont(font)  self.label_maintitle_shadow.setStyleSheet("QLabel#label_maintitle_shadow{\n"  " color:#847c74\n"  "}")  #设置表单的风格self.label_maintitle_shadow.setAlignment(QtCore.Qt.AlignCenter)self.label_maintitle_shadow.setObjectName("label_shadow")self.label_format = QtWidgets.QLabel(self.centralwidget)  self.label_format.setGeometry(QtCore.QRect(325, 395, 251, 20))  font = QtGui.QFont()  font.setFamily("黑体")  font.setPointSize(10)  self.label_format.setFont(font)  #设置表单的格式字体self.label_format.setStyleSheet("QLabel#label_format{\n"  "color:#3A332A\n"  "}")  self.label_format.setObjectName("label_format")  self.label_maintitle = QtWidgets.QLabel(self.centralwidget)  self.label_maintitle.setGeometry(QtCore.QRect(331, 189, 241, 61))font = QtGui.QFont()  font.setFamily("微软雅黑")  font.setPointSize(35)  font.setBold(True)  font.setWeight(75)  self.label_maintitle.setFont(font)  self.label_maintitle.setStyleSheet("QLabel#label_maintitle{\n"  "color:#3A332A\n"  "}")  #主题标签的风格设置self.label_maintitle.setAlignment(QtCore.Qt.AlignCenter)  self.label_maintitle.setObjectName("label_maintitle")  self.label_author = QtWidgets.QLabel(self.centralwidget)  self.label_author.setGeometry(QtCore.QRect(328, 600, 251, 20))  font = QtGui.QFont()  font.setFamily("等线")  font.setPointSize(8)  self.label_author.setFont(font)  self.label_author.setStyleSheet("QLabel#label_author{\n"  "color:#97846c\n"  #设置表单风格"}")  self.label_author.setAlignment(QtCore.Qt.AlignCenter)  self.label_author.setObjectName("label_author")  MainWindow_home.setCentralWidget(self.centralwidget)  self.menubar = QtWidgets.QMenuBar(MainWindow_home)  self.menubar.setGeometry(QtCore.QRect(0, 0, 900, 23))  self.menubar.setObjectName("menubar")  MainWindow_home.setMenuBar(self.menubar)  #主窗口设置菜单栏self.statusbar = QtWidgets.QStatusBar(MainWindow_home)  self.statusbar.setObjectName("statusbar")  MainWindow_home.setStatusBar(self.statusbar)  #主窗口设置状态栏self.retranslateUi(MainWindow_home)  QtCore.QMetaObject.connectSlotsByName(MainWindow_home)  def retranslateUi(self, MainWindow_home):  _translate = QtCore.QCoreApplication.translate  MainWindow_home.setWindowTitle(_translate("MainWindow_home",
"MainWindow"))#主窗口设置窗口标题self.pushButton_openfile.setText(_translate("MainWindow_home",
"进入程序"))  self.label_maintitle_shadow.setText(_translate("MainWindow_home",
"论文助手"))  self.label_format.setText(_translate("MainWindow_home",
"支持扩展名: .pdf  .doc  .docx  .txt"))  self.label_maintitle.setText(_translate("MainWindow_home",
"论文助手"))  self.label_author.setText(_translate("MainWindow_home",
"Designed by Hu Tong & Li Shuolin"))  def openfile(self):  openfile_name=QFileDialog.getOpenFileName(self,'选择文件',
'','files(*.doc,*.docx,*.pdf,*.txt)')  

3)界面交互

完成设计后,在界面之间建立交互关系。此处尝试两种方式: 一是定义跳转函数;二是绑定按钮的槽函数,以完成跳转。

a) 定义跳转函数
定义跳转函数及相关操作。

#Jumpmain2pre.py  
from PyQt5 import QtCore, QtGui, QtWidgets  
from home import Ui_MainWindow_home        #跳转按钮所在界面  
from PreEdit import Ui_Form                #跳转到的界面  class Ui_PreEdit(Ui_Form):   				#定义跳转函数的名字  def __init__(self):  super(Ui_PreEdit,self).__init__()  #跳转函数类名  self.setupUi(self)  #主界面  
class Mainshow(Ui_MainWindow_home):         def __init__(self):  super(Mainshow,self).__init__()     self.setupUi(self)  #定义按钮功能  def loginEvent(self):  self.hide()  self.dia = Ui_PreEdit()              #跳转到的界面类名self.dia.show()  def homeshow():                            #调用这个函数来执行  import sys  app=QtWidgets.QApplication(sys.argv)  first=Mainshow()  first.show()  first.pushButton_openfile.clicked.connect(first.loginEvent) 
#绑定跳转功能的按钮  sys.exit(app.exec_()) 

b) 绑定按钮的槽函数
给需要完成跳转功能的按钮定单击事件,并使用槽函数绑定事件,此处以绑定showwaiting()函数为例:

self.pushButton_create.clicked.connect(self.showwaiting)  

将按钮要绑定的事件单独定义为函数:

def showwaiting(self):  import sys  self.MainWindow = QtWidgets.QMainWindow()  self.newshow = Ui_MainWindow_sumcreating()  #图形界面创建self.newshow.setupUi(self.MainWindow)        #界面设置self.hide()  self.MainWindow.show()  print('生成中…')  

c) 示例:在图形化界面中读取本地文件

将打开动作、保存动作、保存内容分别定义为三个函数,便于单击按钮时通过槽进行调用,相关代码如下:

def open_event(self):  #打开文件事件_translate = QtCore.QCoreApplication.translate  directory1 = QFileDialog.getOpenFileName(None, "选择文件", "C:/","Wo
rd文档 (*.docx;*.doc);;文本文件(*.txt);;pdf(*.pdf);;")  print(directory1)  #输出路径path = directory1[0]  self.open_path_text.setText(_translate("Form", path))  if path is not None:  with open(file=path, mode='r+', encoding='utf-8') as file:  self.text_value.setPlainText(file.read())  def save_event(self):  #保存事件global save_path  _translate = QtCore.QCoreApplication.translate  fileName2, ok2 = QFileDialog.getSaveFileName(None, "文件保存", "C:/",
"Text Files (*.txt)")  print(fileName2)  #打印保存文件的全部路径(包括文件名和后缀名)  save_path = fileName2  self.save_path_text.setText(_translate("Form", save_path))  def save_text(self):  #保存文本global save_path  if save_path is not None:  with open(file=save_path, mode='a+', encoding='utf-8') as file:file.write(self.text_value.toPlainText())  print('已保存!')  

给打开、保存按钮绑定单击动作,并通过槽调用上面定义的相应函数。同时,使用相同的方式将open_event()和 save_event( )函数中获取的路径与已定义的两个路径显示框进行关联,相关代码如下:

def retranslateUi(self, Form):  _translate = QtCore.QCoreApplication.translate  Form.setWindowTitle(_translate("Form", "Form"))  self.label_preview.setText(_translate("MainWindow_preview","预览"))  self.open_path_text.setPlaceholderText(_translate("Form","打开"))  self.open_path_but.setText(_translate("Form", "浏览"))  self.save_path_but.setText(_translate("Form", "浏览"))  self.save_path_text.setPlaceholderText(_translate("Form","保存"))  self.save_but.setText(_translate("Form", "保存"))  self.open_path_but.clicked.connect(self.open_event)  self.save_path_but.clicked.connect(self.save_event)  self.save_but.clicked.connect(self.save_text)  self.pushButton_create.clicked.connect(self.showwaiting)  self.pushButton_create.setText(_translate("Main_preview","生成"))  

程序运行效果图分别如下两图所示。

在这里插入图片描述

在这里插入图片描述

4)程序对接

为完成模型与图形化界面的联合,需要在代码中留出相应的对接接口。在本项目中,界面与模型主体的重点对接部分共有四处:调用模型、模型处理结束、结果展示和输出保存。

a) 调用模型

为完成单击生成按钮后开始调用模型进行处理的功能,在PreEdit.py最后的showWaiting()函数中写入调用接口,在摘要生成页弹出的同时调用模型。相关代码如下:

def showwaiting(self):  import sys  self.MainWindow = QtWidgets.QMainWindow()  self.newshow = Ui_MainWindow_sumcreating()  #创建self.newshow.setupUi(self.MainWindow)        #设置self.hide()  
#待对接程序,读取前面保存的文件(文件的路径在save_event函数里)
#调用模型进行输出并保存  self.MainWindow.show()  print('生成中…')  

b)模型处理结束

在模型处理结束后需继续运行结果展示页,故在PaperMain.py的主函数里加一个判断,在判断模型处理完毕后,调用resultShow()函数,继续运行后续的结果展示。相关代码如下:

def main():  homeshow()    #待对接程序在PreEdit.py最后的showwaiting()函数里调用模型  #待对接程序判断处理完成后继续运行结果展示页  
resultshow()  

c)结果展示

模型处理完毕后,需要在结果展示页显示得到摘要、标题、关键词。结果展示页对应result.py文件,对接前,界面显示的结果为固定的字符串;对接时仅需将模型运行的结果存为字符串形式,替换之前固定的内容即可。相关代码如下:

#待对接程序模型运行的结果存几个字符串后替换下面的文字即可
#替换摘要
self.plainTextEdit_summary.setPlainText(_translate("MainWindow_result", "生成的摘要"))   
#替换标题1  
self.lineEdit_title1.setText(_translate("MainWindow_result","标题1"))
#替换标题2  
self.lineEdit_title2.setText(_translate("MainWindow_result","标题2"))
#替换标题3    
self.lineEdit_title3.setText(_translate("MainWindow_result","标题3"))  
#替换关键词
self.lineEdit_keywords.setText(_translate("MainWindow_result","关键词"))

d)输出保存
单击“保存"按钮时,将模型的输出直接保存到本地。该功能由result. pysave_text()函数的f.write()完成,在对接之前f.write()的输出为固定字符串,对接时替换为模型输出的内容即可。相关代码如下:

def save_text(self):  global save_path  if save_path is not None:  with open(file=save_path, mode='a+', encoding='utf-8') as file: #对接file.write这里直接把程序里的字符串加起来写入保存的结果即可file.write("hello,Tibbarr")  print('已保存!')  

6. 应用封装

为提高使用的便捷性,降低用户的使用门槛,本项目需要进行一体化封装。考虑到论文的撰写大多是在PC端完成的,故使用PyInstaller将项目封装为.exe应用程序。

1)安装PyInstaller

从清华仓库镜像中下载PyInstaller-3.6.tar.gz,在本地解压后,使用cmd进入控制台,切换到解压后的对应目录中,执行命令,即可完成安装。:

python setup.py install

2)将程序打包为.exe文件

打开命令窗口,将目录切换到papermain.py路径下,输入命令

pyinstaller -F -w papermain.py

具体如下图所示。

在这里插入图片描述

使用PyInstaller 命令打包成功,如下图所示。

在这里插入图片描述

3)查看.exe 文件

成功打包程序后,在papermain.py文件目录下生成dist文件夹,里面有生成的.exe文件,双击即可运行,程序封装完成。

系统测试

本部分包括训练困惑度、测试效果和模型应用。

1. 训练困惑度

在Seq2Seq模型中,使用困惑度评估最终效果,值越小则代表语言模型效果越好。本项目使用大网络进行训练,共计48000步,在训练过程进行一段时间后,损失不再减少。开始执行训练与构建网络,如下图所示。

在这里插入图片描述

在训练过程中,模型困惑度的值呈下降趋势,即语言的歧义性随着训练的进行而逐渐减小,模型效果逐渐变好。当模型运行到30 000步时,其下降趋势已趋于平缓,困惑度基本不再减小;到47000步时,模型的perplexity值在小范围波动,最终,其困惑度最低点降至232.62,如下图所示。

在这里插入图片描述

2. 测试效果

载入训练好的模型,输入相关文本进行测试。使用Seq2Seq进行标题部分的输出,如下图所示。

在这里插入图片描述

从输出结果可以看到,模型的标题生成能力仍有所欠缺,仅能对简单的内容进行效果较好的标题实现,在处理难度较大的文本时,准确性还有待提高。

摘要提取与关键字提取部分,使用TextRank算法训练模型,用训练好的模型对给定的文本进行输出,经过多次测试,均得到了较好的结果,如下图所示。

在这里插入图片描述

3. 模型应用

由于程序已打包为可执行文件,故将.exe文件下载到计算机中,双击即可运行,应用初始界面如下图所示。

在这里插入图片描述

首页为项目名称、“进入程序”按钮及对支持处理文档格式的说明,单击“进入程序”按钮即可进入文件读取页。

在文件读取页中,分别通过单击打开地址、保存地址对应的浏览和需要处理的文档,并设置修改结果的保存路径及文件名,如下图所示。

在这里插入图片描述

读入文件后,预览及编辑页如下图-1所示。在此处对读入的内容进行预览及修改,单击“保存"按钮暂存修改无误的文档后,单击“生成”按钮,模型开始处理文本内容,进入等待页,如下图-2所示。

在这里插入图片描述

图1 预览和编辑页

在这里插入图片描述

图2 处理等待页

处理模型后,关闭当前窗口,程序会自动跳转至结果展示页。页面由上到下依次展示了三个不同的标题方案、论文摘要及关键词,用户可以在界面中直接复制,或在页面下方选择路径,将全部结果保存到本地机,如下图所示。

在这里插入图片描述

选择保存路径并单击“保存”按钮后,程序会将所有结果保存至指定路径下,并跳转至下载成功页,如下图所示。

在这里插入图片描述

处理完毕,用户直接关闭程序或单击“返回主页”按钮,跳转回首页处理其他文件。在PC端对程序进行测试,输入文件内容、输出内容图及输出结果文件分别如下图3~图5所示。

在这里插入图片描述

图3 输入文件内容图

在这里插入图片描述

图4 输出内容图

在这里插入图片描述

图5 输出结果文件图

工程源代码下载

详见本人博客资源下载页


其它资料下载

如果大家想继续了解人工智能相关学习路线和知识体系,欢迎大家翻阅我的另外一篇博客《重磅 | 完备的人工智能AI 学习——基础知识学习路线,所有资料免关注免套路直接网盘下载》
这篇博客参考了Github知名开源平台,AI技术平台以及相关领域专家:Datawhale,ApacheCN,AI有道和黄海广博士等约有近100G相关资料,希望能帮助到所有小伙伴们。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于langchain-chatglm本地知识库得部署

项目的技术组成 LLM模型 大型语言模型&#xff08;LLM&#xff0c;是large language model&#xff09;是一种人工智能模型&#xff0c;旨在理解和生成人类语言。它们通过在大量文本数据上进行训练&#xff0c;能够执行多种任务&#xff0c;包括文本总结、翻译、情感分析等。L…

电信卡流量套餐超40G后,该如何解除网速限制?

在和朋友开视频的时候&#xff0c;朋友那边忽然网络中断了&#xff0c;过了会他给我发了一张图片过来&#xff0c;图片如下&#xff1a; 朋友的手机是电信的&#xff0c; 然后我们就在网上查各种解除限制的信息&#xff0c;首先我们按照短信上的提示发送SWFJ到10001&#xff0c…

流量控制与RateLimiter

一背景 如何提高系统的稳定性&#xff0c;简单来说除了加机器外就是服务降级、限流。加机器就是常说的分布式&#xff0c;从整个架构的稳定性角度看&#xff0c;一般SOA每个接口的所能提供的单位时间服务能力是有上限。假如超过服务能力&#xff0c;一般会造成整个接口服务停顿…

异常流量检测

项目目标是为了检测网络异常流量&#xff0c;防止网络攻击行为&#xff0c;本人参与了初期的工作&#xff0c;进行了文献阅读-数据处理-模型构建-参数优化工作。 网络攻击行为主要分为Dos、U2R、Probe等&#xff0c;其对应的流量异常特征为集合异常、点异常、上下文异常。 点异…

网络流量监控分析工具ntopng的安装与使用

我写这篇文章的起因&#xff1a;网上介绍ntopng这款工具的博客不算很多&#xff0c;而且安装方法基本没一个行得通&#xff08;可能是版本更新太快了&#xff09;&#xff0c;我在安装过程中遇到了一些问题&#xff0c;想跟大家分享下&#xff1b;其次&#xff0c;在讲使用方法…

流量异常检测

https://mp.weixin.qq.com/s/9h-hOt630W6k077Rupc9CA 流量异常检测主要有以下三个难点&#xff1a; 流量的大小会随着用户行为发生变化。对于大部分百度云上的业务&#xff0c;白天的访问流量较高&#xff0c;深夜的访问流量较低。这使得流量水位值存在上下文相关性&#xff0…

Android应用流量统计——NetworkStatsManager使用

在没有Root的情况下&#xff0c;Android应用流量统计在6.0之前一直没有太好的办法&#xff0c;官方虽然提供了TrafficStats&#xff0c;但其主要功能是设备启动以来流量的统计信息&#xff0c;和时间信息无法很好的配合。最近再看TrafficStats类时&#xff0c;发现说明中提到&a…

仿设置流量使用——细讲android获取流量使用情况,以及解决调用流量接口不准问题(非TrafficStats,而是NetworkStatsHistory)

不积跬步无以至千里 流量使用情况,好多软件都会带这个功能,比如360的流量监控,好多之类的,手机管家都会带上这个流量计算的功能,连系统应用设置里面也会带一个流量使用情况的查看功能,为什么呢?因为流量的使用关乎到用户使用流量的计费,当流量使用了很多,会给用…

vnstat流量统计(2.8版本)

vnstat流量统计&#xff08;2.8版本&#xff09; vnStat 是一个基于控制台的 Linux 和 BSD 网络流量监视器&#xff0c;它为所选接口保留网络流量日志。它使用内核提供的网络接口统计信息作为信息源。这意味着 vnStat 实际上不会嗅探任何流量&#xff0c;并且无论网络流量率如…

中职流量包分析attack/capture(1)

我希望网络安全的世界大家可以贡献自己的一部分&#xff0c;而不是拿来自私自利 作者拿到的流量包和题目是有出入的&#xff0c;但是因为出的题大同小异所以能分析出来 attack 1. 分 析 attack.pcapng 数 据 包 文 件 &#xff0c;通 过 分 析数据 包 attack.pcapng 找出恶意…

抓包部分软件时无网络+过代理检测 解决办法 安卓黄鸟httpcanary+vmos

解决软件抓包时无网络和代理检测&#x1f680; 需要准备的工具&#xff1a; 安卓手机 vmos pro 需要抓包的软件 第一步&#xff1a;下载好相应版的本的vmos room 第二步&#xff1a;文件中转站->我要导入->导入对应真机需要抓包APP 第三步&#xff1a;测试软件在vmos…

测试apk-异常管控NetTraffic攻击者开发

1. 目的 基于《软件绿色联盟应用体验标准》中 NetTraffic 资源的定义&#xff0c;对 NetTraffic 后台多次小流量数据包的行为模拟。旨在触发手机中异常功耗管控机制。 本次灭屏NetTraffic使用次数至少超过的二个等级:30次,60次&#xff0c;执行如下判断&#xff1a; 绿线不管控…

雷电模拟器无法修改网络,没有出现修改网络的选项,导致fiddler无法连接

对于一个小白来说&#xff0c;可能这就能耗掉一个下午的时间了&#xff0c;比如我&#xff0c;&#xff0c;&#xff0c;&#xff0c;要命的是这种问题对于绝大多数小白还完全不是问题&#xff0c;所以找了很久都没有解决答案&#xff0c;所以我是。。小白中的小白。。 模拟器…

TrackingNet上进行评估

TrackingNet上进行评估 说明&#xff1a;在目标跟踪测试数据集中&#xff0c;在TrackingNet和GOT-10K上的评估结果需要通过在线评估的方式获取。 website&#xff1a;Welcome - EvalAI 自行注册账户&#xff0c;注册好后按照以下操作就可以进行评估了。 在All Changes中找到…

ARP欺骗攻击(流量图片)——dsniff与driftnet使用

ARP欺骗攻击&#xff08;流量&图片&#xff09; 原理&#xff1a; 首先我们![请添加图片描述](https://img-blog.csdnimg.cn/7de7923387224bcda1ea4be958032ae9.png 要明白何为ARP&#xff08;地址解析协议&#xff09;&#xff1a;是根据 IP地址 获取 物理地址 的一个 TC…

Google pixel 原生安卓出现 WiFi 网络受限、优化网速、网络无法连接问题

谷歌从 Android 5.0 开始就引入了「Captive Portal」机制&#xff0c;主要用来检测 WiFI 网络认证是否正常&#xff0c;默认检测访问的是谷歌服务器。 众所周知谷歌服务器是需要404工具才能正常访问&#xff0c;所以如果你没有404工具的情况下&#xff0c;WiFi 就会出现网络受…

悉尼科技大学计算机专业就业,悉尼科技大学计算机专业怎么样

悉尼科技大学计算机科学是一门包含各种各样与计算和信息处理相关主题的系统学科&#xff0c;从抽象的算法分析、形式化语法等等&#xff0c;到更具体的主题如编程语言、程序设计、软件和硬件等。信息化产业的今天&#xff0c;这类专业的重要性也愈加显现。悉尼科技大学的互联网…

悉尼大学计算机专业本科2019,2019申请悉尼大学读本科有哪些要求

悉尼大学是澳洲名校&#xff0c;每年都有不少学生慕名前来留学。那你们知道申请悉尼大学读本科有哪些要求呢? 大师兄留学网【留学网 dsxliuxue.com】小编为大家带来悉尼大学申请条件&#xff0c;希望对大家有帮助。 悉尼大学本科申请条件&#xff1a; 学术要求&#xff1a; 对…

悉尼大学理学院计算机科学,澳洲悉尼大学理学院中国留学生

1 悉尼大学理学院简介 据立思辰留学360介绍&#xff0c;悉尼大学理学院的正式建立是1882年。在之后的50年内&#xff0c;悉尼大学理学院一共培养了353名本科学生&#xff0c;以及聘用了6名在物理&#xff0c;化学&#xff0c;动物学&#xff0c;地质学&#xff0c;植物学&#…

悉尼大学计算机专业新生,2020年悉尼大学计算机科学专业课程设置难不难

悉尼大学计算机科学专业课程设置难不难 阅读&#xff1a;786次 更新时间&#xff1a;2016-10-19 09:06:03 添加时间&#xff1a;2016-10-19 编辑&#xff1a;jingwen 来源&#xff1a; 悉尼大学 索取招生简章 已发送786份2020年招生简章 我对该学校感兴趣&#xff0c;请发资料给…