模型概述

序列建模seq2seq,给定一个序列A,模型生产另一个序列B,然后模型再由序列B生成C,以此一直持续下去。

基本工作流程如下:
序列A中的每一个单词通过word_embedding操作以后,作为input进seq2seq入模型,模型生成同样维度的序列A_out
训练的时候,模型的输出序列A_out与序列B之间的交叉熵作为模型的目标函数,采用clip控制过的梯度进行收敛;
生成的时候,首先给定一个种子序列作为模型输入,初始化模型,让模型可以自循环,并生产指定长度的序列

模型数据流

自己手写的,凑合看下,注意向量和tensor列表之间的区别

第一部分:生成数据

数据源 JayLyrics.txt

dataGenerator.py
定义参数

log_dir = './logs'
seq_length = 20 # 每一个序列的长度
batch_size = 32 #每一个batch的长度
datafiles = 'JayLyrics.txt'

读取文本,进行词频统计,将文本与数字进行一一对应,方便进行处理

with open(datafiles, encoding='utf-8') as f:data = f.read()
total_len = len(data)
words = list(set(data))
words.sort()
vocab_size = len(words)
char2id_dict = {w: i for i, w in enumerate(words)}
id2char_dict = {i: w for i, w in enumerate(words)}

进行这一步之后可以得到

将上面的数据对应表进行存储,注意tsv与csv格式不同,是以tab进行分隔的

_pointer = 0
def char2id( c):return char2id_dict[c]def id2char(id):return id2char_dict[id]metadata = 'metadata2.tsv'
def save_metadata(file):with open(file, 'w') as f:f.write('id\tchar\n')for i in range(vocab_size):c = id2char(i)f.write('{}\t{}\n'.format(i, c))
save_metadata(metadata)

下面进行关键的将原始文本转换为输入数据序列和输入标签
我们可以看到,文本数据与训练数据集是如何进行转换的。

def next_batch():_pointer = 0x_batches = []y_batches = []for i in range(batch_size):if _pointer + seq_length + 1 >= total_len:_pointer = 0bx = data[_pointer: _pointer + seq_length]by = data[_pointer +1: _pointer + seq_length + 1]_pointer += seq_length  # update pointer position# convert to idssbx = [char2id(c) for c in bx]by = [char2id(c) for c in by]x_batches.append(bx)y_batches.append(by)return x_batches, y_batches
data[_pointer: _pointer + seq_length]
Out[22]: '作词:黄俊郎 \n作曲:周杰伦\n编曲:黄雨'
# 以上是 bx
data[_pointer +1: _pointer + seq_length + 1]
Out[23]: '词:黄俊郎 \n作曲:周杰伦\n编曲:黄雨勛'
# 以上是 by

再将上面的数据转化为数字

eg = next_batch()
# 一个batch 就这样生成了
#应注意到输入数据是一个32*20维的数据矩阵
#输入标签同样是一个32*20维的数据矩阵

[char2id(c) for c in bx]

第二部分 构建模型逻辑

构建seq2seq模型

3层LSTMCell 每一层100个神经元

    state_size = 100num_layers = 3#定义神经网络cell = rnn_cell.BasicLSTMCell(state_size)cell = rnn_cell.MultiRNNCell([cell] * num_layers)# 神经元的初始状态,将神经元设置为全零状态initial_state = cell.zero_state(batch_size, tf.float32)

将输入数据传递的seq2seq模型中

采用tf.nn.dynamic_rnn
inputs: The RNN inputs.
Tensor of shape: [batch_size, max_time, …]

dynamic_rnn 返回
outputs: The RNN output Tensor.
If time_major == False (default), this will be a Tensor shaped:
[batch_size, max_time, cell.output_size].
state: The final state. If cell.state_size is an int, this
will be shaped [batch_size, cell.state_size].

   with tf.variable_scope('rnnlm'):with tf.device("/cpu:0"):embedding = tf.get_variable('embedding', [vocab_size, state_size])inputs = tf.nn.embedding_lookup(embedding, input_data)# 将输入数据传递的seq2seq模型中# 采用tf.nn.dynamic_rnn# inputs: The RNN inputs.# Tensor of shape: [batch_size, max_time, ...]outputs, last_state = tf.nn.dynamic_rnn(cell, inputs, initial_state=initial_state)

embedding input 的详细解释 下面是看到的比较好的解释

引用自http://blog.csdn.net/mydear_11000/article/details/52414342

我们预处理了数据之后得到的是一个二维array,每个位置的元素表示这个word在vocabulary中的index。但是传入graph的数据不能讲word用index来表示,这样词和词之间的关系就没法刻画了。我们需要将word用dense vector表示,这也就是广为人知的word embedding。paper中并没有使用预训练的word embedding,所有的embedding都是随机初始化,然后在训练过程中不断更新embedding矩阵的值。
123

with tf.device("/cpu:0"): embedding = tf.get_variable("embedding", vocab_size, state_size]) inputs = tf.nn.embedding_lookup(embedding, self._input_data)

首先要明确几点:
既然我们要在训练过程中不断更新embedding矩阵,那么embedding必须是tf.Variable并且trainable=True(default)
目前tensorflow对于lookup embedding的操作只能再cpu上进行
embedding矩阵的大小是多少:每个word都需要有对应的embedding vector,总共就是vocab_size那么多个embedding,每个word embed成多少维的vector呢?因为我们input embedding后的结果就直接输入给了第一层cell,刚才我们知道cell的hidden units size,因此这个embedding dim要和hidden units size对应上(这也才能和内部的各种门的W和b完美相乘)。因此,我们就确定下来
embedding matrix shape=[vocab_size, hidden_units_size]

最后生成真正的inputs节点,也就是从embedding_lookup之后得到的结果,这个tensor的shape=[batch_size, num_stemps, size]

第三部分 构建模型损失函数和收敛方法

先定义参数w(100*2636)和b(2636)
再将output 展开成[-1*state_size]维即是[-1*100]
再用(output*w)+b获得输出序列logits
下面便可以使用sequence_loss_by_example将模型输出logits和训练标签targets计算序列交叉熵

with tf.name_scope('model'):with tf.variable_scope('rnnlm'):w = tf.get_variable( 'softmax_w', [state_size, vocab_size])b = tf.get_variable('softmax_b', [vocab_size])with tf.name_scope('loss'):output = tf.reshape(outputs, [-1, state_size])logits = tf.matmul(output, w) + bprobs = tf.nn.softmax(logits)last_state = last_statetargets = tf.reshape(target_data, [-1])
# 将targets 展平 维度从(32*20)转化为640
# pass '[-1]' to flatten 't'
#reshape(t, [-1]) ==> [1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6]loss = seq2seq.sequence_loss_by_example([logits],[targets],[tf.ones_like(targets, dtype=tf.float32)])cost = tf.reduce_sum(loss) / batch_size#下面采用scalar 是用来在tensorboard 显示数据的tf.summary.scalar('loss', cost)

第四部分 优化器设定

首先 定义lr 是不可训练的
关键地方 clip_by_global_norm的作用
设置梯度的最大范数
Gradient Clipping的方法,控制梯度的最大范数。
可以防止梯度爆炸的问题,如果梯度不加限制,则可能因为迭代中梯度过大导致训练难以收敛。

optimizer.apply_gradients则将前面clip过的梯度应用到所有可以训练的tvars上

with tf.name_scope('optimize'):lr = tf.placeholder(tf.float32, [])tf.summary.scalar('learning_rate', lr)optimizer = tf.train.AdamOptimizer(lr)#获取全部可以训练的参数tvarstvars = tf.trainable_variables()
# 提前计算梯度grads = tf.gradients(cost, tvars)#显示在tensorboardfor g in grads:tf.summary.histogram(g.name, g)# 由它们的范数之和之比求多个张量的值grads, _ = tf.clip_by_global_norm(grads, grad_clip)# 将前面clip过的梯度应用到可训练的参数上train_op = optimizer.apply_gradients(zip(grads, tvars))merged_op = tf.summary.merge_all()

第五部分 训练

启动模型,设定tensorboard,导入数据,记录数据

with tf.Session() as sess:#启动模型sess.run(tf.global_variables_initializer())saver = tf.train.Saver()writer = tf.summary.FileWriter(log_dir, sess.graph)# 设定tensorboard# Add embedding tensorboard visualization. Need tensorflow version# >= 0.12.0RC0config = projector.ProjectorConfig()embed = config.embeddings.add()embed.tensor_name = 'rnnlm/embedding:0'embed.metadata_path = metadataprojector.visualize_embeddings(writer, config)# 导入数据max_iter = n_epoch * \(data.total_len // seq_length) // batch_sizefor i in range(max_iter):learning_rate = learning_rate * \(decay_rate ** (i // decay_steps))x_batch, y_batch = data.next_batch()feed_dict = {model.input_data: x_batch,model.target_data: y_batch, model.lr: learning_rate}train_loss, summary, _, _ = sess.run([model.cost, model.merged_op, model.last_state, model.train_op],feed_dict)
# 记录数据if i % 10 == 0:writer.add_summary(summary, global_step=i)print('Step:{}/{}, training_loss:{:4f}'.format(i,max_iter, train_loss))if i % 2000 == 0 or (i + 1) == max_iter:saver.save(sess, os.path.join(log_dir, 'lyrics_model.ckpt'), global_step=i)

第五部分 生成文本

首先从保存的模型中取出参数,初始化模型
再设定种子
将种子进行处理
初始化模型
按照设定的生成数量生成文本

#首先从保存的模型中取出参数,初始化模型
saver = tf.train.Saver()
with tf.Session() as sess:ckpt = tf.train.latest_checkpoint(args.log_dir)print(ckpt)saver.restore(sess, ckpt)# 再设定种子# initial phrase to warm RNNprime = u'你要离开我知道很简单'state = sess.run(cell.zero_state(1, tf.float32))# 将种子进行处理
# 初始化模型for word in prime[:-1]:x = np.zeros((1, 1))x[0, 0] = char2id(word)feed = {input_data: x, initial_state: state}state = sess.run(last_state, feed)# 按照设定的生成数量生成文本word = prime[-1]lyrics = primefor i in range(args.gen_num):x = np.zeros([1, 1])x[0, 0] = char2id(word)feed_dict = {input_data: x, initial_state: state}probs, state = sess.run([probs, last_state], feed_dict)p = probs[0]word = id2char(np.argmax(p))print(word, end='')sys.stdout.flush()time.sleep(0.05)lyrics += wordreturn lyrics

代码还是很复杂很复杂的,看了好几天,还是有些不明白的,
有些只能等以后再慢慢专研,现在主干是抓住了。

tensorflow代码全解析 -3- seq2seq 自动生成文本相关推荐

  1. 主板诊断卡代码全解析

    主板诊断卡代码全解析 RUN灯功能介绍 该灯只用极少部件,故自身故障率极低,且只需极少的主板插槽信号,故即使插到一个坏的插槽中虽无法走代码,或其它的所有指示灯都不亮,但该灯很有可能照常工作,您可根据: ...

  2. Vision Transformer(ViT)PyTorch代码全解析(附图解)

    Vision Transformer(ViT)PyTorch代码全解析 最近CV领域的Vision Transformer将在NLP领域的Transormer结果借鉴过来,屠杀了各大CV榜单.本文将根 ...

  3. 使用TensorFlow搭建智能开发系统,自动生成App UI代码

    本文转自微信号EAWorld.扫描下方二维码,关注成功后,回复"普元方法+",将会获得热门课堂免费学习机会! 本文目录: 一.我们的现状与期望 二.我们的初级探索及建议 三.智能开 ...

  4. mybatis生成mysql代码_如何让 Mybatis 自动生成代码,提高开发效率

    Actually being alone is not lonely.The real loneliness is when you miss someone. 其实一个人并不孤单,想念一个人的时候才 ...

  5. tmx瓦片地图文件内容的解析与地图自动生成

    想在游戏中使用瓦片地图,但发现手动拼地图确实很麻烦,于是就想能不能自动生成地图.打开一个我编辑好的地图: 保存之后会是一个.tmx格式的文件,用文本编辑器打开这个文件,你会发现这个文件是一个xml文件 ...

  6. 准工业级代码分享:Python用于自动生成EXCEL周期报告

    前言 Python自动化在我看来一直是个小打小闹的需求,无法独立成为工业级或者商业级的产品需求.尤其是Python操作PPT,在我看来根本没有一点用武之地.因为好的商业PPT远不是枯燥的复制和粘贴,绝 ...

  7. 玩转Keras之Seq2Seq自动生成标题 | 附开源代码

    作者丨苏剑林 单位丨广州火焰信息科技有限公司 研究方向丨NLP,神经网络 个人主页丨kexue.fm 话说自称搞了这么久的 NLP,我都还没有真正跑过 NLP 与深度学习结合的经典之作--Seq2Se ...

  8. OpenAI的GPT-3花费了1200万美元,现在放出商用API,人人皆可拿来自动生成文本、编写代码...

    晓查 发自 凹非寺  量子位 报道 | 公众号 QbitAI OpenAI,这次真的要Open了. 那些训练费用动辄几百上千万美元的巨型NLP模型,不久后每个人都能用上,虽然是付费形式. 就在不久前, ...

  9. circlegan_CycleGAN原理以及代码全解析

    许多名画造假者费尽毕生的心血,试图模仿出艺术名家的风格.如今,CycleGAN就可以初步实现这个神奇的功能.这个功能就是风格迁移,比如下图,照片可以被赋予莫奈,梵高等人的绘画风格 这属于是无配对数据( ...

最新文章

  1. (十五)java数组
  2. 云原生生态周报 Vol. 12 | K8s 1.16 API 重大变更
  3. source tree常用功能
  4. Redis系列(二):Redis缓存穿透和缓存雪崩是什么?
  5. java windows wrapper_Java Service Wrapper 发布windows后台程序的方法
  6. Android 10 发布
  7. 我们差点就用不上 Java 了!
  8. php抽奖设置数量,php实现自定义中奖项数和概率的抽奖函数示例
  9. 转 Linux查看文件编码格式及文件编码转换
  10. 动态链接库的设计(DLL)
  11. idea2017显示maven Project菜单
  12. 关于学习 unity3D 的知识预储备
  13. 完全卸载VS 2015各版本
  14. 【动画消消乐|CSS】088.HTML+CSS实现自定义简易过渡动画
  15. CSR8系列ROM版本芯片介绍
  16. html需要背的标签,html的header标签需要怎么使用
  17. 如何选择物联网服务商
  18. Android 11 : 隐私和安全
  19. 顺序表的基本操作(增删改查)——C语言
  20. No.053<软考>《(高项)备考大全》【冲刺7】《软考之 119个工具 (5)》

热门文章

  1. 超好用的鼠标增强软件:Smooze for Mac
  2. 如何查看 SQL 执行频率
  3. Spring和Spring Boot区别
  4. 利用esp8266接入小爱同学,实现智能台灯的改造物联网初识
  5. 电信运营商云计算发展战略分析
  6. 10. 哈夫曼树、Trie、补充
  7. LED驱动程序第一课
  8. 付宇泽20190912-3 词频统计
  9. Linux的体系结构
  10. matlab中leg的用法,leg_leg的意思和用法搭配