在双向 RNN 中获得极低的损失?
Getting extremely low loss in a bidirectional RNN?
我使用 BasicLSTMCell
和 rnn.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_text
是1,3,5,2,4,8,9,0
,那么,你的inputs
和 target
将是:
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 工作时需要完整的序列,当你想预测下一个字符时,你会发现你不能轻易使用这个模型。
我使用 BasicLSTMCell
和 rnn.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_text
是1,3,5,2,4,8,9,0
,那么,你的inputs
和 target
将是:
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 工作时需要完整的序列,当你想预测下一个字符时,你会发现你不能轻易使用这个模型。