我正在构建一个用于语言识别的有状态 LSTM。 有了状态,我可以用较小的文件来训练网络,而新批处理将就像讨论中的下一句话一样。 然而,为了使网络得到正确的训练,我需要在一些批处理之间重置 LSTM 的隐藏状态。
我使用变量来存储 LSTM 的隐藏状态以提高性能:
with tf.variable_scope('Hidden_state'):
hidden_state = tf.get_variable("hidden_state", [self.num_layers, 2, self.batch_size, self.hidden_size],
tf.float32, initializer=tf.constant_initializer(0.0), trainable=False)
# Arrange it to a tuple of LSTMStateTuple as needed
l = tf.unstack(hidden_state, axis=0)
rnn_tuple_state = tuple([tf.contrib.rnn.LSTMStateTuple(l[idx][0], l[idx][1])
for idx in range(self.num_layers)])
# Build the RNN
with tf.name_scope('LSTM'):
rnn_output, _ = tf.nn.dynamic_rnn(cell, rnn_inputs, sequence_length=input_seq_lengths,
initial_state=rnn_tuple_state, time_major=True)
现在我对如何重置隐藏状态感到困惑。我尝试了两种解决方案,但都不起作用:
第一个解决方案
使用以下命令重置“hidden_state”变量:
rnn_state_zero_op = hidden_state.assign(tf.zeros_like(hidden_state))
它确实有效,我认为这是因为在运行 rnn_state_zero_op 操作后,unstack 和元组构造没有“重新播放”到图中。
第二种解决方案
已关注 LSTMStateTuple vs cell.zero_state() for RNN in Tensorflow我尝试使用以下命令重置单元格状态:
rnn_state_zero_op = cell.zero_state(self.batch_size, tf.float32)
似乎也不起作用。
问题
我想到了另一个解决方案,但它最多只是猜测:我没有保留 tf.nn.dynamic_rnn 返回的状态,我已经想到了,但我得到了一个元组,但找不到方法构建一个操作来重置元组。
在这一点上,我必须承认我不太了解 tensorflow 的内部工作原理,以及是否有可能做我想做的事情。 有正确的方法吗?
谢谢!
最佳答案
感谢this answer to another question我找到了一种方法来完全控制 RNN 的内部状态是否(以及何时)应重置为 0。
首先,您需要定义一些变量来存储 RNN 的状态,这样您就可以控制它:
with tf.variable_scope('Hidden_state'):
state_variables = []
for state_c, state_h in cell.zero_state(self.batch_size, tf.float32):
state_variables.append(tf.nn.rnn_cell.LSTMStateTuple(
tf.Variable(state_c, trainable=False),
tf.Variable(state_h, trainable=False)))
# Return as a tuple, so that it can be fed to dynamic_rnn as an initial state
rnn_tuple_state = tuple(state_variables)
请注意,这个版本直接定义了 LSTM 使用的变量,这比我问题中的版本要好得多,因为您不必取消堆栈并构建元组,这会向图中添加一些您无法运行的操作明确地。
其次构建 RNN 并检索最终状态:
# Build the RNN
with tf.name_scope('LSTM'):
rnn_output, new_states = tf.nn.dynamic_rnn(cell, rnn_inputs,
sequence_length=input_seq_lengths,
initial_state=rnn_tuple_state,
time_major=True)
现在您已经有了 RNN 的新内部状态。您可以定义两个操作来管理它。
第一个将更新下一批的变量。因此,在下一批中,RNN 的“initial_state”将被输入上一批的最终状态:
# Define an op to keep the hidden state between batches
update_ops = []
for state_variable, new_state in zip(rnn_tuple_state, new_states):
# Assign the new state to the state variables on this layer
update_ops.extend([state_variable[0].assign(new_state[0]),
state_variable[1].assign(new_state[1])])
# Return a tuple in order to combine all update_ops into a single operation.
# The tuple's actual value should not be used.
rnn_keep_state_op = tf.tuple(update_ops)
只要您想要运行批处理并保持内部状态,您就应该将此操作添加到您的 session 中。
注意:如果您在调用此操作的情况下运行批处理 1,则批处理 2 将以批处理 1 最终状态开始,但如果您在运行批处理 2 时不再调用它,则批处理 3 将以批处理 1 的最终状态开始。也从第 1 批最终状态开始。我的建议是每次运行 RNN 时添加此操作。
第二个操作将用于将 RNN 的内部状态重置为零:
# Define an op to reset the hidden state to zeros
update_ops = []
for state_variable in rnn_tuple_state:
# Assign the new state to the state variables on this layer
update_ops.extend([state_variable[0].assign(tf.zeros_like(state_variable[0])),
state_variable[1].assign(tf.zeros_like(state_variable[1]))])
# Return a tuple in order to combine all update_ops into a single operation.
# The tuple's actual value should not be used.
rnn_state_zero_op = tf.tuple(update_ops)
只要您想重置内部状态,就可以调用此操作。
关于Tensorflow RNN-LSTM - 重置隐藏状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45430933/