2017-08-01 107 views
1

我正在构建用于语言识别的statefull LSTM。 正在有条件的我可以用更小的文件来训练网络,并且新的批处理将会像讨论中的下一句话一样。 但是,要正确训练网络,我需要重置一些批次之间的LSTM的隐藏状态。Tensorflow RNN-LSTM - 重置隐藏状态

我使用一个变量来存储LSTM的hidden_​​state性能:

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操作后,构造不会“重新播放”到图中。

解决方法二

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的内部工作,如果甚至有可能做我想做的事情。 有没有适当的方法来做到这一点?

谢谢!

回答

2

感谢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和检索最终状态:所以现在你有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) 

。您可以定义两个操作来管理它。

第一个将更新下一批次的变量。

# 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) 

你应该要运行一个批处理这个运算添加到您的会话随时随地保持内部:那么在下一批次的“initial_state”的RNN将与前一批次的最终状态下供给州。

请注意:如果您运行带有此op的批处理1,则批2将以批1的最终状态开始,但如果在运行批2时不再调用它,则批3将以批1开始最终状态也。我的建议是每次运行RNN时添加此操作。

第二OP将用于该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) 

,每当你想重置内部状态,您可以调用这个运算。

0

简化AMairesse后的版本为一个LSTM层:

zero_state = tf.zeros(shape=[1, units[-1]]) 
self.c_state = tf.Variable(zero_state, trainable=False) 
self.h_state = tf.Variable(zero_state, trainable=False) 
self.init_encoder = tf.nn.rnn_cell.LSTMStateTuple(self.c_state, self.h_state) 

self.output_encoder, self.state_encoder = tf.nn.dynamic_rnn(cell_encoder, layer, initial_state=self.init_encoder) 

# save or reset states 
self.update_ops += [self.c_state.assign(self.state_encoder.c, use_locking=True)] 
self.update_ops += [self.h_state.assign(self.state_encoder.h, use_locking=True)] 

,也可以使用替代init_encoder在步骤== 0复位状态(需要传递到self.step_tf session.run()作为占位符):

self.step_tf = tf.placeholder_with_default(tf.constant(-1, dtype=tf.int64), shape=[], name="step") 

self.init_encoder = tf.cond(tf.equal(self.step_tf, 0), 
    true_fn=lambda: tf.nn.rnn_cell.LSTMStateTuple(zero_state, zero_state), 
    false_fn=lambda: tf.nn.rnn_cell.LSTMStateTuple(self.c_state, self.h_state))