在双向 RNN 中获得极低的损失?

Getting extremely low loss in a bidirectional RNN?

我使用 BasicLSTMCellrnn.bidirectional_rnn 在 TensorFlow 中实现了双向 RNN。在连接我收到的输出后,我正在使用 seq2seq.sequence_loss_by_example 计算损失。我的应用程序是下一个字符预测器。

我得到一个 极低的 cost,(比单向 RNN 低约 50 倍)。我怀疑我在 seq2seq.sequence_loss_by_example 步骤中犯了一个错误。

这是我的模型 -

# Model begins
cell_fn = rnn_cell.BasicLSTMCell
cell = fw_cell = cell_fn(args.rnn_size, state_is_tuple=True)
cell2 = bw_cell = cell_fn(args.rnn_size, state_is_tuple=True)

input_data = tf.placeholder(tf.int32, [args.batch_size, args.seq_length])
targets = tf.placeholder(tf.int32, [args.batch_size, args.seq_length])
initial_state = fw_cell.zero_state(args.batch_size, tf.float32)
initial_state2 = bw_cell.zero_state(args.batch_size, tf.float32)

with tf.variable_scope('rnnlm'):
  softmax_w = tf.get_variable("softmax_w", [2*args.rnn_size, args.vocab_size])
  softmax_b = tf.get_variable("softmax_b", [args.vocab_size])
  with tf.device("/cpu:0"):
    embedding = tf.get_variable("embedding", [args.vocab_size, args.rnn_size])
    input_embeddings = tf.nn.embedding_lookup(embedding, input_data)
    inputs = tf.unpack(input_embeddings, axis=1)

outputs, last_state, last_state2 = rnn.bidirectional_rnn(fw_cell,
                                                         bw_cell,
                                                         inputs,
                                                         initial_state_fw=initial_state,
                                                         initial_state_bw=initial_state2,
                                                         dtype=tf.float32)
output = tf.reshape(tf.concat(1, outputs), [-1, 2*args.rnn_size])
logits = tf.matmul(output, softmax_w) + softmax_b

probs = tf.nn.softmax(logits)
loss = seq2seq.sequence_loss_by_example([logits],
        [tf.reshape(targets, [-1])],
        [tf.ones([args.batch_size * args.seq_length])],
        args.vocab_size)
cost = tf.reduce_sum(loss) / args.batch_size / args.seq_length
lr = tf.Variable(0.0, trainable=False)
tvars = tf.trainable_variables()
grads, _ = tf.clip_by_global_norm(tf.gradients(cost, tvars),
        args.grad_clip)
optimizer = tf.train.AdamOptimizer(lr)
train_op = optimizer.apply_gradients(zip(grads, tvars))

我认为你的代码没有任何错误。

问题出在您的应用程序(下一个字符预测器)中使用 Bi-RNN 模型的 objective 函数。

单向RNN(比如ptb_word_lm or char-rnn-tensorflow),它真的是用来做预测的模型,比如如果raw_text1,3,5,2,4,8,9,0,那么,你的inputstarget 将是:

inputs:   1,3,5,2,4,8,9
target:   3,5,2,4,8,9,0

预测为 (1)->3, (1,3)->5, ..., (1,3,5,2,4,8,9)->0

但是在Bi-RNN中,第一个预测真的不只是(1)->3,因为你代码中的output[0]通过使用[=21包含raw_text的反向信息=](也不是 (1,3)->5,...,(1,3,5,2,4,8,9)->0)。一个类似的例子是:我告诉你那朵花是玫瑰,比我让你预测那朵花是什么?我想你可以很容易地给我正确的答案,这也是你在你的应用程序的 Bi-RNN 模型中得到极低 loss 的原因。

事实上,我认为 Bi-RNN(或 Bi-LSTM)不是一个适用于下一个字符预测器应用的模型。 Bi-RNN 工作时需要完整的序列,当你想预测下一个字符时,你会发现你不能轻易使用这个模型。