首页 PaddleNLP 帖子详情
基于Seq2Seq搭建对联(下联)自动生成系统
收藏
快速回复
PaddleNLP 文章NLP学习资料 2269 6
基于Seq2Seq搭建对联(下联)自动生成系统
收藏
快速回复
PaddleNLP 文章NLP学习资料 2269 6

#

对联自动生成系统

我的项目直达:https://aistudio.baidu.com/aistudio/projectdetail/2424665?contributionType=1&shared=1

我参考的项目:https://aistudio.baidu.com/aistudio/projectdetail/1321118?shared=1

## 1.项目目标

设计一个基于深度学习的对联生成系统。最终结果可以是一个简单的界面,在界面中,我输入一句上联,通过点击相应按钮,系统生成相应下联并显示出来。

## 2.国内外相关工作

对联是属于我们中华民族独有的一种文学形式,国外研究甚少,所以在此主要阐述一下国内的研究情况。

我以“对联深度学习”和“couplet”为key word分别在中国知网和DBLP中检索了从18年至今的文献,中国知网有3篇硕士论文,DBLP有10篇英文文献(但仅有2篇可以SCI检索下载)。在我搜集到的5篇文献中,朱媛媛等人(2018,2021,吉林大学),卫万成等人(2019,桂林电子科技大学),Shengqiong Yuan等人(2019,武汉理工大学)都是基于Encoder-Decoder框架和Attention机制进行研究;张江等人(2020,南京邮电大学)基于transformer模型进行研究。

朱媛媛等人在2018年基于编码器-解码器模型进行研究,在词向量的预训练方法上进行了创新,提出不仅考虑序列中前后字的上下文关系,还同时考虑上下联之间对应字的相关性;紧接着,他们在2021年提出了“Trapezoidal Context’字符向量(从摘要看,还是18年的内容)。

卫万成等人在2019年同样采用编码器—解码器模型进行,但他是做的基于多任务学习模型生成诗歌和对联;编码器参数共享,解码器参数不共享。

张江等人主要是对基于注意力机制搭建的transformer模型进行改进,提出三种改进策略:(1)提出融合词性特征信息的词向量训练方法(2)提出一种低频词处理方法(3)提出对联生成的润色机制。


## 3.自己在本项目中承担工作
本项目一个人独自完成,工作大体可分为:
  1. 数据集搜集及整理,预处理
  2. 模型搭建训练及模型预测
  3. 最终展示界面搭建
  4. 报告撰写

## 4.实现系统(或模块)的核心思想和算法描述

### 4.1 数据处理部分:

#### 4.1.1 噪声数据摘除:
数据集来源:https://github.com/wb14123/couplet-dataset 此数据集包含了五个文件,将文件按照(test+train)的顺序进行合并。之后发现有**14**条数据有问题,索引为:badid=[103807, 176565, 257631,265657, 358953, 489089, 558495, 561447, 707870, 710226, 236151,517221,549031,707322](索引从0开始)。其中前10个问题为上联,后4个问题为下联。我把处理之后的数据集分享在:https://aistudio.baidu.com/aistudio/datasetdetail/110057

问题数据展示如下:

经过上述处理,最终获得**744915**条对联数据。

#### 4.1.2 添加输入开始与结束标志
   - < start> 表示一个输入的开始
   - < end> 表示一个输入的结束

需要注意的是:(1)一般的NLP任务都会设置一个< pad>字段表示填充,这里我们使用< end>表示;(2)我们并没有设置< unk> 标志来表示未登录词汇,根据我们的统计,本词汇共9017个,数量相对较小,可全部使用。 我们把每个字符(汉字或者标点)看作一个词汇。

#### 4.1.3 建立词库与字典
  - 词库:由上下联所有字符,可用**列表**表示
  - 字典:建立词汇-->向量,向量-->词汇两个字典。向量在这里可以理解为数字化,最终的目的是向量化。

在字典的创建过程中,主要先用一个辅助字典,存储每个词汇出现的频率,然后根据频率排序辅助字典。然后初始化两个字典,遍历辅助字典,可用当前字典(非辅助字典)的长度作为词汇数字标识。 在该过程中,我们还可以根据频率筛选出频率大于一定阈值的词汇,即抛弃低频词汇。

#### 4.1.4 数据向量化

根据前一步中创建的“词汇-->向量”字典将所有数据向量化。

向量化示意图:

#### 4.1.5 数据集划分及封装
我们总的数据为744915条,按照8:1:1的方式划分训练集,验证集,测试集。

数据集的封装主要使用paddlepaddle以及paddlenlp提供的一套方法,写法较固定,其中paddlenlp主要是进行每个minibath数据的padding操作,统一长度。详情可见代码或者官网讲解:

paddlepaddle数据集封装:https://www.paddlepaddle.org.cn/documentation/docs/zh/guides/02_paddle2.0_develop/02_data_load_cn.html

paddlenlp数据padding:
https://paddlenlp.readthedocs.io/zh/latest/data_prepare/data_preprocess.html

最终我们得到封装好的训练集、验证集,测试集。以训练集为例,每个元素包括五部分:

1. 上联输入向量
2. 输入向量未填充前的长度,用于控制LSTM的隐藏状态是否更新填充位置
3. 下联输入向量,不包含最后一个位置的元素
4. 下联输入向量,不包含第一个元素,然后在最后一个扩维,用于loss计算
5. 下联输入向量的mask向量

### 4.2 模型搭建及预测

#### 4.2.1 训练模型

训练模型使用Encoder-Decoder框架(Seq2Seq模型)。

##### 4.2.1.1 Encoder

encoder模块内部由一个embedding层和一个LSTM层顺序连接。

  - embedding层需要指定使用的词汇量和编码维度,词汇量我们使用全部的9017,编码维度我们使用的256
  - LSTM层,指定输入的维度,隐藏层的大小,以及LSTM的层数。

##### 4.2.1.2 Decoder
deocder模块内部由一个embedding嵌入层和一个“LSTM+注意力”单元以及一个全连接层组成。
  - embedding层需要指定使用的词汇量和编码维度,词汇量我们使用全部的9017,编码维度我们使用的256
  - LSTM+注意力:在该单元,我们将encoder的输出和decoder中lstm的输出作为注意力机制的输入,将注意力机制的输出作为最终的结果。
  - 全连接层:指定输入维度和输出维度。输入维度为隐藏层的大小,输入维度应为词汇量的大小,将输出映射到词汇量大小的空间。

##### 4.2.1.3 参数设定

  - num_layers=2:LSTM的层数
  - hidden_size=128:隐藏层的状态数
  - embedding_dim=256:嵌入层的维度
  - lr=0.001:学习率
  - log_freq=200:每200个batch输入一次日志信息
  - max_grad_norm=5:梯度裁剪
  - optimizer=Adam():优化器,严格的说,优化器不是参数,在这里我们把他看作一个参数。
  - loss=CrossEntropy():损失函数,使用的是带掩码的交叉熵,基于框架自带的交叉熵损失函数实现。
  - metrics=Preplexity():评价准则,我们使用的是困惑度,框架自带。

##### 4.2.1.4 模型训练及验证
  - epcohs=20
  - 使用model.fit()函数进行训练及验证。模型提供的高阶接口。
  - 训练我们在百度公司提供的AI Studio平台进行,项目链接:https://aistudio.baidu.com/aistudio/projectdetail/2424665?contributionType=1&shared=1
  - 我们使用训练好的模型,直接在测试集上进行验证,结果截图如下:

#### 4.2.2 模型预测

模型的预测使用了beam search。常规的search方法有greedy search(贪心)和exhaustive search(穷举)。

  - 穷举:穷举所有可能的输出结果。例如输出序列长度为3,候选项为4,那么就有4*4*4=64种可能,当输出序列长度为10时,就会有4**10种可能,这种幂级增长对于计算机性能的要求是极高的,耗时耗力。
  - 贪心:每次选择概率最大的候选者作为输出。search空间小,以局部最优解期望全局最优解,无法保证最终结果是做优的,但是效率高。
  - beam search:beam可以看作是穷举和贪心的折中方案。需要设定一个beam size(束宽),当设为1时即为贪心,当设为候选项的数量时即为穷举。

### 4.3 展示界面搭建

#### 4.3.1 Tkinter
展示界面我主要使用Python自带的TKinter包进行搭建,主要包括两个文本框和两个动作按钮。
#### 4.3.2 内部流程
用户输入对联的上联,然后点击相应按钮,系统会提取用户的输入,将其向量化,然后送入训练好的模型中,产生输出,然后显示在另一个文本框中。

## 5.系统主要模块流程
系统主要模块流程如下图:

## 6.实验结果及分析

### 6.1 loss
loss曲线数据由PaddlePaddle提供的接口在训练时保存在log文件中,之后通过可视化工具进行展示。横轴表示训练的minibatch,纵轴表示loss值。

通过训练集与验证集的lossqu曲线可以看出,训练在前期收敛较快,训练集后期有波动,但是验证集后期仍为缓慢下降趋势,说明模型的训练效果是不错的。

训练集loss曲线:

验证集loss曲线:

#### 6.2 困惑度

困惑度数据的获取方式同loss。通过训练集与验证集的困惑度曲线,我们也可任务模型训练效果可以。但是训练集的困惑度后期呈现为直线,这应该是存在问题的,有待分析解决。

我们在测试集上进行了困惑度分析,每个batch的数据困惑度基本一致,说明模型波动较小,效果理想。

训练集困惑度变化曲线:

验证集困惑度变化曲线:

与张江等人使用transformer模型的困惑度比较,我们的结果还算可以。但是张江等人使用的数据集没有明确,可能是因为不同数据集造成的差异。然后,通过人工判定:生成几个例子,邀请舍友评价,总的结论是还可以。
#### 6.3 界面展示
我们使用搭建好的简易界面进行对联自动生成模型的成果展示:

1
收藏
回复
全部评论(6)
时间顺序
三岁
#2 回复于2021-12

项目挺好的,还是用md写的,哈哈哈哈哈哈,强!!!

0
回复
DeepGeGe
#3 回复于2021-12

上次去参加飞桨WAVE SUMMIT峰会,听到好像飞桨支持字符串张量了,以后这种文本可以直接输入,省事很多。

0
回复
玥亮
#4 回复于2021-12
上次去参加飞桨WAVE SUMMIT峰会,听到好像飞桨支持字符串张量了,以后这种文本可以直接输入,省事很多。

那可真省事哈哈

0
回复
玥亮
#5 回复于2021-12
三岁 #2
项目挺好的,还是用md写的,哈哈哈哈哈哈,强!!!

前几周的作业了,还要好多要学的,嘿嘿

0
回复
大连之星snort
#7 回复于2022-03

不错,学习中

0
回复
f
fool
#8 回复于2022-03

不错,学习中

0
回复
需求/bug反馈?一键提issue告诉我们
发现bug?如果您知道修复办法,欢迎提pr直接参与建设飞桨~
在@后输入用户全名并按空格结束,可艾特全站任一用户