一、前言

1、图解RNN

2、Tensorflow中RNN实现的正确打开方式

二、实战

1、训练数据处理

(1)文字转为向量

    def _get_poetry(self):with open(self.poetry_file, "r", encoding='utf-8') as f:poetry_list = [line for line in f]return poetry_listdef _gen_poetry_vectors(self):words = sorted(set(''.join(self.poetry_list)+' '))# 每一个字符分配一个索引 为后续诗词向量化做准备int_to_word = {i: word for i, word in enumerate(words)}word_to_int = {v: k for k, v in int_to_word.items()}to_int = lambda word: word_to_int.get(word)poetry_vectors = [list(map(to_int, poetry)) for poetry in self.poetry_list]return poetry_vectors, word_to_int, int_to_word

在这里将训练数据中所有的字生成了一个"文字==>数字"的词袋,并将所有的诗词按行分割转化为数字表示。

(2)生成器

    def batch(self):# 生成器start = 0end = self.batch_sizefor _ in range(self.chunk_size):batches = self.poetry_vectors[start:end]# 输入数据 按每块数据中诗句最大长度初始化数组,缺失数据补全x_batch = np.full((self.batch_size, max(map(len, batches))), self.word_to_int[' '], np.int32)for row in range(self.batch_size): x_batch[row, :len(batches[row])] = batches[row]# 标签数据 根据上一个字符预测下一个字符 所以这里y_batch数据应为x_batch数据向后移一位y_batch = np.copy(x_batch)y_batch[:, :-1], y_batch[:, -1] = x_batch[:, 1:], x_batch[:, 0]yield x_batch, y_batchstart += self.batch_sizeend += self.batch_size

x_batch作为输入,y_batch为标签。诗词生成模型根据上一个字符生成下一个字符,所以这里的标签数据应该是和输入数据的shape一致,但序列字符后移一位。y_batch的最后一位,理论上来说应该是本行诗词的下一行的第一个字,简单起见,这里用本行的第一个字代替。

2、RNN模型

(1)模型初始化

class PoetryModel:def __init__(self):# 诗歌生成self.poetry = Poetry()# 单个cell训练序列个数self.batch_size = self.poetry.batch_size# 所有出现字符的数量self.word_len = len(self.poetry.word_to_int)# 隐层的数量self.rnn_size = 128

rnn_size代表RNN模型中隐层的数量,这个概念要和RNN模型中time_step的数量分开,这里time_step数量指的是每一行诗词的文字数量,即x。batch_size数量指每次训练时,使用的诗词行数。

(2)变量定义

        # 输入句子长短不一致 用None自适应inputs = tf.placeholder(tf.int32, shape=(self.batch_size, None), name='inputs')# 输出为预测某个字后续字符 故输出也不一致targets = tf.placeholder(tf.int32, shape=(self.batch_size, None), name='targets')# 防止过拟合keep_prob = tf.placeholder(tf.float32, name='keep_prob')

(3)embedding定义

    def embedding_variable(inputs, rnn_size, word_len):with tf.variable_scope('embedding'):# 这里选择使用cpu进行embeddingwith tf.device("/cpu:0"):# 默认使用'glorot_uniform_initializer'初始化,来自源码说明:# If initializer is `None` (the default), the default initializer passed in# the variable scope will be used. If that one is `None` too, a# `glorot_uniform_initializer` will be used.# 这里实际上是根据字符数量分别生成state_size长度的向量embedding = tf.get_variable('embedding', [word_len, rnn_size])# 根据inputs序列中每一个字符对应索引 在embedding中寻找对应向量,即字符转为连续向量:[字]==>[1]==>[0,1,0]lstm_inputs = tf.nn.embedding_lookup(embedding, inputs)return lstm_inputs

将诗词的文字对应索引分别转化为变量,引入另一个新概念,input_size,即每一个字所对应的变量长度,这里是训练数据中所有字符的数量,所以实际上我们每次训练使用的数据shape应该是(batch_size,time_step,input_size)。

(4)模型计算图定义

    def rnn_graph(self, batch_size, rnn_size, word_len, lstm_inputs, keep_prob):# cell.state_size ==> 128# 基础cell 也可以选择其他基本cell类型lstm = tf.nn.rnn_cell.BasicLSTMCell(num_units=rnn_size)drop = tf.nn.rnn_cell.DropoutWrapper(lstm, output_keep_prob=keep_prob)# 多层cell 前一层cell作为后一层cell的输入cell = tf.nn.rnn_cell.MultiRNNCell([drop] * 2)# 初始状态生成(h0) 默认为0# initial_state.shape ==> (64, 128)initial_state = cell.zero_state(batch_size, tf.float32)# 使用dynamic_rnn自动进行时间维度推进 且 可以使用不同长度的时间维度# 因为我们使用的句子长度不一致lstm_outputs, final_state = tf.nn.dynamic_rnn(cell, lstm_inputs, initial_state=initial_state)seq_output = tf.concat(lstm_outputs, 1)x = tf.reshape(seq_output, [-1, rnn_size])# softmax计算概率w, b = self.soft_max_variable(rnn_size, word_len)logits = tf.matmul(x, w) + bprediction = tf.nn.softmax(logits, name='predictions')return logits, prediction, initial_state, final_state

(5)权重及偏置定义

    def soft_max_variable(rnn_size, word_len):# 共享变量with tf.variable_scope('soft_max'):w = tf.get_variable("w", [rnn_size, word_len])b = tf.get_variable("b", [word_len])return w, b

RNN与CNN不同的一点在于,RNN的权重及偏置在所有cell中是一样的,这里使用了共享变量。
(6)损失及优化图定义

    @staticmethoddef loss_graph(word_len, targets, logits):# 将y序列按序列值转为one_hot向量y_one_hot = tf.one_hot(targets, word_len)y_reshaped = tf.reshape(y_one_hot, [-1, word_len])loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=y_reshaped))return loss@staticmethoddef optimizer_graph(loss, learning_rate):grad_clip = 5# 使用clipping gradientstvars = tf.trainable_variables()grads, _ = tf.clip_by_global_norm(tf.gradients(loss, tvars), grad_clip)train_op = tf.train.AdamOptimizer(learning_rate)optimizer = train_op.apply_gradients(zip(grads, tvars))return optimizer

RNN会遇到梯度爆炸(gradients exploding)梯度弥散(gradients disappearing)的问题。LSTM解决了梯度弥散的问题,但是gradients仍然可能会爆炸,因此我们采用gradient clippling的方式来防止梯度爆炸。即通过设置一个阈值,当gradients超过这个阈值时,就将它重置为阈值大小,这就保证了梯度不会变得很大。

(7)开始训练

        # 开始训练saver = tf.train.Saver()sess = tf.Session()sess.run(tf.global_variables_initializer())step = 0new_state = sess.run(initial_state)for i in range(epoch):# 训练数据生成器batches = self.poetry.batch()# 随模型进行训练 降低学习率sess.run(tf.assign(learning_rate, 0.001 * (0.97 ** i)))for batch_x, batch_y in batches:feed = {inputs: batch_x, targets: batch_y, initial_state: new_state, keep_prob: 0.5}batch_loss, _, new_state = sess.run([loss, optimizer, final_state], feed_dict=feed)print(datetime.datetime.now().strftime('%c'), ' i:', i, 'step:', step, ' batch_loss:', batch_loss)step += 1model_path = os.getcwd() + os.sep + "poetry.model"saver.save(sess, model_path, global_step=step)sess.close()

随着模型的训练,逐步降低学习率。
(8)生成古诗词

    def gen(self, poem_len):def to_word(weights):t = np.cumsum(weights)s = np.sum(weights)sample = int(np.searchsorted(t, np.random.rand(1) * s))return self.poetry.int_to_word[sample]# 输入# 句子长短不一致 用None自适应self.batch_size = 1inputs = tf.placeholder(tf.int32, shape=(self.batch_size, 1), name='inputs')# 防止过拟合keep_prob = tf.placeholder(tf.float32, name='keep_prob')lstm_inputs = self.embedding_variable(inputs, self.rnn_size, self.word_len)# rnn模型_, prediction, initial_state, final_state = self.rnn_graph(self.batch_size, self.rnn_size, self.word_len, lstm_inputs, keep_prob)saver = tf.train.Saver()with tf.Session() as sess:sess.run(tf.global_variables_initializer())saver.restore(sess, tf.train.latest_checkpoint('.'))new_state = sess.run(initial_state)# 在所有字中随机选择一个作为开始x = np.zeros((1, 1))x[0, 0] = self.poetry.word_to_int[self.poetry.int_to_word[random.randint(1, self.word_len-1)]]feed = {inputs: x, initial_state: new_state, keep_prob: 1}predict, new_state = sess.run([prediction, final_state], feed_dict=feed)word = to_word(predict)poem = ''while len(poem) < poem_len:poem += wordx = np.zeros((1, 1))x[0, 0] = self.poetry.word_to_int[word]feed = {inputs: x, initial_state: new_state, keep_prob: 1}predict, new_state = sess.run([prediction, final_state], feed_dict=feed)word = to_word(predict)return poem

在sep-sep模型中,上一个网络的状态输出应该作为下一个网络的状态输入,所以初始状态为零,后续输入状态都是上一次的输出状态。

(9)结果

筋烛升玄净,云光理片溪。
美子相离处,离来下路疏。
策变因坚薛,灵行一更颇。
卖上狎城天,穿洄欹笔软。
授名时依寂,快举即芳眉。
吊此之当主,长期动世迟。

看起来有模有样的,基本模型是成功了。在这个模型的基础上进行改动,还可以生成小说等。

三、其他

具体源码可以在我的github上找到: https://github.com/lpty/tensorflow_tutorial

基于RNN的中文古诗词生成神经网络实现相关推荐

  1. 深度学习实战篇-基于RNN的中文分词探索

    深度学习实战篇-基于RNN的中文分词探索 近年来,深度学习在人工智能的多个领域取得了显著成绩.微软使用的152层深度神经网络在ImageNet的比赛上斩获多项第一,同时在图像识别中超过了人类的识别水平 ...

  2. TensorFlow练习7: 基于RNN生成古诗词

    RNN不像传统的神经网络-它们的输出输出是固定的,而RNN允许我们输入输出向量序列.RNN是为了对序列数据进行建模而产生的. 样本序列性:样本间存在顺序关系,每个样本和它之前的样本存在关联.比如说,在 ...

  3. 基于RNN的文本生成算法的代码运转

    目录(?)[+] "什么时候能自动生成博客?" 前言 跳过废话,直接看正文 RNN相对于传统的神经网络来说对于把握上下文之间的关系更为擅长,因此现在被大量用在自然语言处理的相关任务 ...

  4. Tensorflow使用CNN卷积神经网络以及RNN(Lstm、Gru)循环神经网络进行中文文本分类

    Tensorflow使用CNN卷积神经网络以及RNN(Lstm.Gru)循环神经网络进行中文文本分类 本案例采用清华大学NLP组提供的THUCNews新闻文本分类数据集的一个子集进行训练和测试http ...

  5. 基于RNN循环神经网络lstm的藏头诗制作

    基于RNN循环神经网络lstm的藏头诗制作 简单介绍 在一次偶然中接触到藏头诗,觉得十分有意思.但是好像都是利用古代本就有的诗句重新组合而成.比如输入清风袭来,结果如下图所示. 之后想到不如利用深度学 ...

  6. 基于DCGAN的动漫头像生成神经网络实现

    一.前言 1.什么是DCGAN? 2.DCGAN的TensorFlow实现 3.什么是转置卷积? 4.转置卷积的Tensorflow实现 5.Batch Normalization解读 本文假设读者已 ...

  7. 基于python的词云生成-中文词云(指定词云形状)

    基于python的词云生成(二) 1.简介    本文是在基于python的词云生成(一)的基础上,进一步对云词进行编写,本文还使用了jieba分词对中文进行分词处理,以做出更好的效果.    jie ...

  8. 基于rnn神经网络的写唐诗机器人

    基于rnn网络的自动写唐诗机器人 项目目录: my_rnn_model用来保存训练的模型: clean_txt.py 脚本负责将清洗唐诗集(poetry.txt) 代码如下 poem_dir = &q ...

  9. 基于RNN-LSTM模型的诗词生成/TensorFlow

    1 研究任务一介绍 1.1 研究任务 给定诗词数据集poems,采用基于循环神经网络(RNN)的LSTM模型实现古诗词自动生成,调整参数实现五言诗.七言诗.五言藏头诗.七言藏头诗和词的自动生成. 1. ...

最新文章

  1. ipsec***原理与配置
  2. 成都亿佰特物联网无线数传专家:lora无线传输模块网关技术的优缺点
  3. scipy.sparse.csr_matrix函数和coo_matrix函数
  4. python培训班靠谱吗-python培训机构靠谱吗?python培训班
  5. Windows内核面试题(持续更新,目前完成度30%约1.8万字)
  6. 小波包8层分解与重构MATLAB代码,谐波小波包分解与重构程序谁有呢?
  7. 基于OMAP-L138 DSP+ARM处理器与FPGA实现SDR软件无线电系统
  8. 广告违规词、敏感词在线检测
  9. 记一次springboot应用偶发502错误的排查过程
  10. 误码率matlab,关于误码率的问题 急!!!!!
  11. 英语练习day2 一般,否定疑问句,现表将来
  12. TL431NSG-A 友顺UTC
  13. 第17章- 5~8 钣金实体书架与刚体平台接触分析、材料弹塑性分析(网格控制、刚体接触设置,刚体只能作为接触的目标面、爆炸显示、载荷步设置、残余应力)
  14. (转)美团面试题整理
  15. 教你使用Python从零开始搭建一个区块链项目!
  16. mysql的二进制安装与备份
  17. Photoshop学习整理---图层的混合模式
  18. 三子棋小游戏,实现人机对战,电脑可做简单拦截(C语言版)
  19. 深入理解Java虚拟机:JVM内存管理与垃圾收集理论
  20. 巨震行情下反映出的人性

热门文章

  1. 3D模型欣赏:2000宝马E46瓦罐 光影材质逼真,还以为是真的一样!
  2. 一文看懂电磁波的波段命名
  3. 使用nodejs+Socket打造P2P实现多人聊天室
  4. ENVI Classic:如何将多个单波段影像合成为一个多波段影像?
  5. 2012年复赛综合训练(一):第一题:nbsp;…
  6. 置顶的搜索框html,HTML实现移动端固定悬浮半透明搜索框
  7. SSH使用及协议分析
  8. Win2008_server_r2虚拟机打开wireshark显示没有接口的【解决方法】
  9. Ubuntu 18.04 系统安装
  10. 英雄远征Erlang源码分析(13)-总结 附上可执行的服务端和客户端代码