参考以下这篇文章学习,从上层模块结构到底层代码都分析得很清晰
http://blog.csdn.net/mydear_11000/article/details/52414342。
直接从模型构建过程开始,RNN的核心单元是一个可沿时间序列展开的cell,一般先定义模型中要使用到的cell结构:
lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(size, forget_bias=0.0, state_is_tuple=True)
if is_training and config.keep_prob < 1:
lstm_cell = tf.nn.rnn_cell.DropoutWrapper(
lstm_cell, output_keep_prob=config.keep_prob)
cell = tf.nn.rnn_cell.MultiRNNCell([lstm_cell] * config.num_layers, state_is_tuple=True)
如果是在training过程中,仅在同一时刻,多层cell之间传递信息的时候进行dropout。tf.nn.rnn_cell.DropoutWrapper对原来的cell增加一个dropout层,tf.nn.rnn_cell.MultiRNNCell构建多层RNN结构。
接下来是word embedding. 预处理的数据是one-hot向量,但是词与词之间的关系没办法用位置关系来描述,因此需要用单词嵌入。
with tf.device("/cpu:0"):
embedding = tf.get_variable(
"embedding", [vocab_size, size], dtype=data_type())
inputs = tf.nn.embedding_lookup(embedding, input_.input_data)
上面是一种单词嵌入的方法,设置一个单词嵌入矩阵,该矩阵的参数也是训练参数,在网络训练过程中同时训练这些参数。当然还有一种方法,使用已经训练好的单词向量,通过词典查找使用,这种方法可以防止在语料不够时,不足以训练出好的单词向量的情况。
设置cell的输入输出
outputs, state = tf.nn.rnn(cell, inputs, initial_state=self._initial_state)
设置最后的输出:
output = tf.reshape(tf.concat(1, outputs), [-1, size])
softmax_w = tf.get_variable(
"softmax_w", [size, vocab_size], dtype=data_type())
softmax_b = tf.get_variable("softmax_b", [vocab_size], dtype=data_type())
logits = tf.matmul(output, softmax_w) + softmax_b
设置损失函数:
loss = tf.nn.seq2seq.sequence_loss_by_example(
[logits],
[tf.reshape(input_.targets, [-1])],
[tf.ones([batch_size * num_steps], dtype=data_type())])
self._cost = cost = tf.reduce_sum(loss) / batch_size
这里的cost是一个batch里面label错误的个数的平均数,在输出的时候我发现输出的评价指标是perplexity,原来以为是语言模型的word perplexity, 在另一篇博客http://blog.csdn.net/u012316600/article/details/53203197 中有提到,但是在PTBModel的run_epoch函数里面发现,perplexity的定义如下:
np.exp(costs / iters)
也就是说依然是cost的正向函数。
接下来是梯度传递函数,与其它的NN一样:
self._lr = tf.Variable(0.0, trainable=False)
tvars = tf.trainable_variables()
grads, _ = tf.clip_by_global_norm(tf.gradients(cost, tvars),
config.max_grad_norm)
optimizer = tf.train.GradientDescentOptimizer(self._lr)
self._train_op = optimizer.apply_gradients(
zip(grads, tvars),
global_step=tf.contrib.framework.get_or_create_global_step())
注意这里的clip_by_global_norm函数是限制梯度过大的时候要削去,即取设置好的最大梯度值,防止训练到局部极小值。
在RNN中,重要的是细节cell如何设置,在文章开始参考的博文中,当然还有官网,都有详细的说明。结合上一篇文章,基本是RNN基础学习的内容。
官网例子代码:https://github.com/tensorflow/tensorflow/tree/master/tensorflow/models/rnn/ptb