8

tensorflow学习,建立LSTM循环神经网络,教机器作诗,训练篇(27)

 3 years ago
source link: https://blog.popkx.com/tensorflow-study-build-lstm-rnn-to-teach-machine-make-poety-training-chapter/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

第26节讨论了如何将诗集数据转换为数字信息,便于训练 长短期记忆循环神经网络(LSTM RNN)第25节则介绍了 LSTM RNN 在 tensorflow 中常用的函数。本节将在此基础上,建立网络,并训练之。


建立多层 LSTM 循环神经网络

先封装一个神经元,使用dropout防止过拟合。

def GetOneCell(lstm_size, keep_prob):
            lstm = tf.nn.rnn_cell.BasicLSTMCell(lstm_size)
            drop = tf.nn.rnn_cell.DropoutWrapper(lstm, output_keep_prob=keep_prob)
            return drop

封装好GetOneCell方法,就可以很方便的建立多层 LSTM 网络了。

cell = tf.nn.rnn_cell.MultiRNNCell(
                [get_a_cell(lstm_size, keep_prob) for _ in range(num_layers)]
            )

建立好以后,就可以用tf.nn.dynamic_rnn方法展开时间维度了,该方法的说明可以参考第25节

initial_state = cell.zero_state(num_seqs, tf.float32)               #初始状态使用零状态
lstm_outputs, final_state = tf.nn.dynamic_rnn(cell, lstm_inputs, initial_state=initial_state)

得到的lstm_outputs其实是 LSTM 的隐状态层 h,所以还需要一层 softmax 计算概率。建立 softmax 层就相当于一层全连接层,首先需要将lstm_outputs的形状 reshape。这里 reshape 成 [-1, lstm_size] 形状,即只保证有 lstm_size 列,不关心到底多少行。因为建立的是多层 LSTM,所以在 reshape 前,先将第二维合并。

lstm_outputs的第一维是 batch_size 即句子的条数,第二维是 诗句的长度,第三维是 lstm size。

代码如下,建立 softmax 层非常熟,不用细说了。

seq_output = tf.concat(lstm_outputs, 1)
x = tf.reshape(seq_output, [-1, lstm_size])

softmax_w = tf.Variable(tf.truncated_normal([lstm_size, num_classes], stddev=0.1))
softmax_b = tf.Variable(tf.zeros(num_classes))
logits = tf.matmul(x, softmax_w) + softmax_b
proba_prediction = tf.nn.softmax(logits)

建立损失函数 loss

这里仍然是使用tf.nn.softmax_cross_entropy_with_logits方法,该方法的使用前面几节介绍的非常清楚,可以翻回去看看。在计算 loss 前,需要先将参考值做点处理:建立one-hot型标签后,reshape 为 logits 的形状即可。具体代码如下

def build_loss():
       y_one_hot = tf.one_hot(targets, num_classes)
       y_reshaped = tf.reshape(y_one_hot, logits.get_shape())
       lossi = tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=y_reshaped)
       loss = tf.reduce_mean(lossi)

对应的优化器可以如下建立:

def build_optimizer():
        # 使用clipping gradients
        tvars = tf.trainable_variables()
        grads, _ = tf.clip_by_global_norm(tf.gradients(self.loss, tvars), self.grad_clip)
        train_op = tf.train.AdamOptimizer(self.learning_rate)
        self.optimizer = train_op.apply_gradients(zip(grads, tvars))

建立数据输入

网络和损失函数、优化器都建立好了,接下来就可以建立数据输入了。使用placeholder,数据通过 feed 传入。因为打算训练的是诗文的数据,所以需要使用embedding层。

inputs = tf.placeholder(tf.int32, shape=(
        num_seqs, num_steps))
targets = tf.placeholder(tf.int32, shape=(
        num_seqs, num_steps))
keep_prob = tf.placeholder(tf.float32)

    # 对于中文,需要使用embedding层
    # 英文字母没有必要用embedding层
with tf.device("/cpu:0"):
    embedding = tf.get_variable('embedding', [num_classes, embedding_size])
    lstm_inputs = tf.nn.embedding_lookup(embedding, inputs)

以上几个模块建立好了以后,定义训练方法就非常简单了。总体过程就是利用第26节建立的数据转换方法,将诗文转换为数字信息,然后再经过embedding层,就可以feed给建立好的网络了。每隔一段训练次数,就保存一次训练结果,防止训练意外中断,又得从头训练,这点之前的有篇博客深有体会。

def train(batch_generator, max_steps, save_path, save_every_n, log_every_n):
    session = tf.Session()
    with session as sess:
        sess.run(tf.global_variables_initializer())
        # Train network
        step = 0
        new_state = sess.run(initial_state)
        for x, y in batch_generator:
            step += 1
            feed = {inputs: x,
                    targets: y,
                    keep_prob: train_keep_prob,
                    initial_state: new_state}
            batch_loss, new_state, _ = sess.run([loss,
                                                 final_state,
                                                 optimizer],
                                                feed_dict=feed)
            if (step % save_every_n == 0):
                self.saver.save(sess, os.path.join(save_path, 'model'), global_step=step)
            if step >= max_steps:
                break
        self.saver.save(sess, os.path.join(save_path, 'model'), global_step=step)

代码和诗集数据可以点击下面链接下载,含义本节已经说得比较清楚。

代码

执行脚本,进行训练,得到以下结果:

$ python train.py   --use_embedding   --input_file data/poetry.txt   --name poetry   --learning_rate 0.005   --num_steps 26   --num_seqs 32   --max_steps 10000
step: 10/10000...  loss: 6.5859...  0.2540 sec/batch
step: 20/10000...  loss: 6.5014...  0.2491 sec/batch
step: 30/10000...  loss: 6.3253...  0.2469 sec/batch
step: 40/10000...  loss: 6.1925...  0.2984 sec/batch
step: 50/10000...  loss: 5.9969...  0.2483 sec/batch
step: 60/10000...  loss: 5.8543...  0.3229 sec/batch
...

发现 loss 在不停的变小,这是网络能够正常工作的必要条件,本节就到这里。下一节,将利用训练好的网络作诗。

本节主要参考《21个项目玩转深度学习》


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK