Является ли исходное состояние RNN reset для последующих мини-партий?

Может кто-то прояснить, является ли начальное состояние RNN в TF reset для последующих мини-партий, или последнее состояние предыдущей мини-партии используется, как указано в Илья Суцкев и др., ICLR 2015

Ответ 1

tf.nn.dynamic_rnn() или tf.nn.rnn() позволяют указать начальное состояние RNN с помощью параметра initial_state. Если вы не укажете этот параметр, скрытые состояния будут инициализированы нулевыми векторами в начале каждой учебной партии.

В TensorFlow вы можете обернуть тензоры в tf.Variable(), чтобы сохранить их значения в графике между несколькими сеансами сеанса. Просто следите за тем, чтобы они не обучались, потому что оптимизаторы по умолчанию настраивают все обучаемые переменные.

data = tf.placeholder(tf.float32, (batch_size, max_length, frame_size))

cell = tf.nn.rnn_cell.GRUCell(256)
state = tf.Variable(cell.zero_states(batch_size, tf.float32), trainable=False)
output, new_state = tf.nn.dynamic_rnn(cell, data, initial_state=state)

with tf.control_dependencies([state.assign(new_state)]):
    output = tf.identity(output)

sess = tf.Session()
sess.run(tf.initialize_all_variables())
sess.run(output, {data: ...})

Я не тестировал этот код, но он должен дать вам подсказку в правильном направлении. Существует также tf.nn.state_saving_rnn(), к которому вы можете предоставить объект сохранения состояния, но я еще не использовал его.

Ответ 2

В дополнение к ответу danijar, вот код для LSTM, состояние которого является кортежем (state_is_tuple=True). Он также поддерживает несколько уровней.

Мы определяем две функции: одну для получения переменных состояния с начальным нулевым состоянием и одну функцию для возврата операции, которую мы можем передать в session.run, чтобы обновить переменные состояния с последним скрытым состоянием LSTM.

def get_state_variables(batch_size, cell):
    # For each layer, get the initial state and make a variable out of it
    # to enable updating its value.
    state_variables = []
    for state_c, state_h in cell.zero_state(batch_size, tf.float32):
        state_variables.append(tf.contrib.rnn.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
    return tuple(state_variables)


def get_state_update_op(state_variables, new_states):
    # Add an operation to update the train states with the last state tensors
    update_ops = []
    for state_variable, new_state in zip(state_variables, 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 actual value should not be used.
    return tf.tuple(update_ops)

Как и в случае с danijar, мы можем использовать это, чтобы обновить состояние LSTM после каждой партии:

data = tf.placeholder(tf.float32, (batch_size, max_length, frame_size))
cell_layer = tf.contrib.rnn.GRUCell(256)
cell = tf.contrib.rnn.MultiRNNCell([cell_layer] * num_layers)

# For each layer, get the initial state. states will be a tuple of LSTMStateTuples.
states = get_state_variables(batch_size, cell)

# Unroll the LSTM
outputs, new_states = tf.nn.dynamic_rnn(cell, data, initial_state=states)

# Add an operation to update the train states with the last state tensors.
update_op = get_state_update_op(states, new_states)

sess = tf.Session()
sess.run(tf.global_variables_initializer())
sess.run([outputs, update_op], {data: ...})

Основное отличие состоит в том, что state_is_tuple=True делает LSTM состоянием LSTMStateTuple, содержащим две переменные (состояние ячейки и скрытое состояние), а не только одну переменную. Используя несколько слоев, затем LSTM устанавливает кортеж LSTMStateTuples - по одному на каждый слой.