基于循环神经网络(RNN)的古诗生成器
2019.01.02更新:
代码比较老了,当时的开发环境为Python 2.7 + TensorFlow 1.4,现在可能无法直接运行了。如果有兴趣,可以移步我用Python 3.7 + TensorFlow 2.0 重写的新项目:
有趣的深度学习——使用TensorFlow 2.0 + RNN 实现一个古体诗生成器
转载请注明出处:https://blog.csdn.net/aaronjny/article/details/79677457
之前在手机百度上看到有个“为你写诗”功能,能够随机生成古诗,当时感觉很酷炫= =
在学习了深度学习后,了解了一下原理,打算自己做个实现练练手,于是,就有了这个项目。文中如有瑕疵纰漏之处,还请路过的诸位大佬不吝赐教,万分感谢!
使用循环神经网络实现的古诗生成器,能够完成古体诗的自动生成。我简单地训练了一下,格式是对上了,至于意境么。。。emmm,呵呵
举一下模型测试结果例子:
1.生成古体诗
示例1:
树阴飞尽水三依,谩自为能厚景奇。
莫怪仙舟欲西望,楚人今此惜春风。
示例2:
岩外前苗点有泉,紫崖烟霭碧芊芊。
似僧月明秋更好,一踪颜事欲犹伤?
2.生成藏头诗(以“天空”为例)
示例:
天序曾柏乌倾鱼,空老桐歌尘翁红。
下面记录项目实现过程(由于都是文本处理方面,跟前一个项目存在很多类似的内容,对于这部分内容,我就只简单提一下,不展开了,新的东西再具体说):
1.数据预处理
数据集使用四万首的唐诗训练集,可以点击这里进行下载。
数据预处理的过程与前一个项目TensorFlow练手项目一:使用循环神经网络(RNN)实现影评情感分类大同小异,可以参考前一个项目,这里就不多说了,直接上代码。
# -*- coding: utf-8 -*-
# @Time : 18-3-13 上午11:04
# @Author : AaronJny
# @Email : Aaron__7@163.com
import sys
reload(sys)
sys.setdefaultencoding('utf8')
import collections
ORIGIN_DATA = 'origin_data/poetry.txt' # 源数据路径
OUTPUT_DATA = 'processed_data/poetry.txt' # 输出向量路径
VOCAB_DATA = 'vocab/poetry.vocab'
def word_to_id(word, id_dict):
if word in id_dict:
return id_dict[word]
else:
return id_dict['<unknow>']
poetry_list = [] # 存放唐诗的数组
# 从文件中读取唐诗
with open(ORIGIN_DATA, 'r') as f:
f_lines = f.readlines()
print '唐诗总数 : {}'.format(len(f_lines))
# 逐行进行处理
for line in f_lines:
# 去除前后空白符,转码
strip_line = line.strip().decode('utf8')
try:
# 将唐诗分为标题和内容
title, content = strip_line.split(':')
except:
# 出现多个':'的将被舍弃
continue
# 去除内容中的空格
content = content.strip().replace(' ', '')
# 舍弃含有非法字符的唐诗
if '(' in content or '(' in content or '<' in content or '《' in content or '_' in content or '[' in content:
continue
# 舍弃过短或过长的唐诗
lenth = len(content)
if lenth < 20 or lenth > 100:
continue
# 加入列表
poetry_list.append('s' + content + 'e')
print '用于训练的唐诗数 : {}'.format(len(poetry_list))
poetry_list=sorted(poetry_list,key=lambda x:len(x))
words_list = []
# 获取唐诗中所有的字符
for poetry in poetry_list:
words_list.extend([word for word in poetry])
# 统计其出现的次数
counter = collections.Counter(words_list)
# 排序
sorted_words = sorted(counter.items(), key=lambda x: x[1], reverse=True)
# 获得出现次数降序排列的字符列表
words_list = ['<unknow>'] + [x[0] for x in sorted_words]
# 这里选择保留高频词的数目,词只有不到七千个,所以我全部保留
words_list = words_list[:len(words_list)]
print '词汇表大小 : {}'.format(words_list)
with open(VOCAB_DATA, 'w') as f:
for word in words_list:
f.write(word + '\n')
# 生成单词到id的映射
word_id_dict = dict(zip(words_list, range(len(words_list))))
# 将poetry_list转换成向量形式
id_list=[]
for poetry in poetry_list:
id_list.append([str(word_to_id(word,word_id_dict)) for word in poetry])
# 将向量写入文件
with open(OUTPUT_DATA, 'w') as f:
for id_l in id_list:
f.write(' '.join(id_l) + '\n')
2.模型编写
这里要编写两个模型,一个用于训练,一个用于验证(生成古体诗)。两个模型大体上一致,因为用途不同,所以有些细节有出入。当进行验证时,验证模型读取训练模型的参数进行覆盖。
注释比较细,就不多说了,看代码。对于两个模型不同的一些关键细节,我也用注释进行了说明。
# -*- coding: utf-8 -*-
# @Time : 18-3-13 下午2:06
# @Author : AaronJny
# @Email : Aaron__7@163.com
import tensorflow as tf
import functools
import setting
HIDDEN_SIZE = 128 # LSTM隐藏节点个数
NUM_LAYERS = 2 # RNN深度
def doublewrap(function):
@functools.wraps(function)
def decorator(*args, **kwargs):
if len(args) == 1 and len(kwargs) == 0 and