Tensorflow, как передать состояние MultiRNN в feed_dict

#tensorflow

#tensorflow

Вопрос:

Я пытаюсь создать генеративную модель RNN в tensorflow. Что меня раздражает, так это то, что с новым переключением на state_is_tupe значение true по умолчанию в библиотеке RNN, мне трудно найти лучший способ сохранения состояния между пакетами. Я знаю, что могу изменить его обратно на значение False, но я не хочу этого делать, поскольку оно устарело. Когда я закончу обучение, мне нужно иметь возможность сохранять скрытые состояния между вызовами session.run, поскольку я буду генерировать последовательности по одному образцу за раз. Я понял, что могу вернуть состояние rnn следующим образом.

         rnn = tf.nn.rnn_cell.MultiRNNCell(cells)  
        zero_state = rnn.zero_state(batch_size, tf.float32)
        output, final_state = tf.nn.dynamic_rnn(rnn, self.input_sound, initial_state = zero_state)
        sess = tf.Session()
        sess.run(tf.initialize_all_variables())
        state_output = sess.run(final_state, feed_dict = {self.input_sound: np.zeros((64, 32, 512))})
 

Это было бы здорово, но проблема возникает, когда я хочу передать state_output обратно в модель. Поскольку заполнителем может быть только тензорный объект, я не могу передать его обратно в тупель state_output .

Я ищу очень общее решение. Rnn может быть MultiRNNCell или одной LSTMCell или любой другой мыслимой комбинацией.

Ответ №1:

Я думаю, я понял это. Я использовал следующий код, чтобы сгладить кортежи состояний в один одномерный тензор. Я могу измельчить его, когда передам его обратно в модель в соответствии со спецификацией размера ячейки rnn.

 def flatten_state_tupel(x):
    result = []
    for x_ in x:
        if isinstance(x_, tf.Tensor) or not hasattr(x_, '__iter__'):
            result.append(x_)
        else:
            result.extend(flatten_state_tupel(x_))
    return result

def pack_state_tupel(state):
    return tf.concat(0, [tf.reshape(s, (-1,)) for s in flatten_state_tupel(state)])

def unpack_state_tupel(state, size):
    state = tf.reshape(state, (-1, tf.reduce_sum(flatten_state_tupel(size))))
    def _make_state_tupel(sz, i):
        if hasattr(sz, '__iter__'):
            result = []
            for s in sz:
                base_index, y = _make_state_tupel(s, i)
                result.append(y)
            return base_index, tf.nn.rnn_cell.LSTMStateTuple(*result) if isinstance(sz, tf.nn.rnn_cell.LSTMStateTuple) else tuple(result)
        else:
            return i   sz, state[..., i : i   sz]
    return _make_state_tupel(size, 0)[-1]
 

Я использую функции следующим образом.

 rnn = tf.nn.rnn_cell.MultiRNNCell(cells)  
zero_state = pack_state_tupel(rnn.zero_state(batch_size, tf.float32))
self.initial_state = tf.placeholder_with_default(zero_state, None)

output, final_state = tf.nn.dynamic_rnn(rnn, self.input_sound, initial_state = unpack_state_tupel(self.initial_state, rnn.state_size))

packed_state = pack_state_tupel(final_state)

sess = tf.Session()
sess.run(tf.initialize_all_variables())

state_output = sess.run(packed_state, feed_dict = {self.input_sound: np.zeros((64, 32, 512))})
print(state_output.shape)
state_output = sess.run(packed_state, feed_dict = {self.input_sound: np.zeros((64, 32, 512)), self.initial_state: np.zeros(state_output.shape[0])})
print(state_output)
 

Таким образом, состояние будет обнуляться, если я ничего не передам (что будет иметь место во время обучения), однако я могу сохранять и передавать состояние между пакетами во время генерации.