Установка скрытого состояния для каждого мини-пакета с разными скрытыми размерами и несколькими слоями LSTM в Keras

#python #tensorflow #keras #deep-learning #lstm

#python #tensorflow #keras #глубокое обучение #lstm

Вопрос:

Я создал LSTM, используя Keras с TensorFlow в качестве серверной части. Перед тем, как мини-пакет с num_step 96 будет передан в обучение, скрытое состояние LSTM устанавливается в истинные значения предыдущего временного шага.

Сначала параметры и данные:

 batch_size = 10
num_steps = 96
num_input = num_output = 2
hidden_size = 8
X_train = np.array(X_train).reshape(-1, num_steps, num_input)
Y_train = np.array(Y_train).reshape(-1, num_steps, num_output)
X_test = np.array(X_test).reshape(-1, num_steps, num_input)
Y_test = np.array(Y_test).reshape(-1, num_steps, num_output)
  

Модель Keras состоит из двух слоев LSTM и одного слоя для обрезки вывода до num_output, который равен 2:

 model = Sequential()
model.add(LSTM(hidden_size, batch_input_shape=((batch_size, num_steps, num_input)),
               return_sequences=True, stateful = True)))
model.add(LSTM(hidden_size, return_sequences=True)))
model.add(Dropout(0.2))
model.add(TimeDistributed(Dense(num_output, activation='softmax')))

model.compile(loss='mean_squared_error', optimizer='adam', metrics=['accuracy'])
  

Генератор, а также обучение (hidden_states[x] имеет форму (2,)):

 def gen_data():
        x = np.zeros((batch_size, num_steps, num_input))
        y = np.zeros((batch_size, num_steps, num_output))
        while True:
            for i in range(batch_size):
                model.layers[0].states[0] = K.variable(value=hidden_states[gen_data.current_idx]) # hidden_states[x] has shape (2,)
                x[i, :, :] = X_train[gen_data.current_idx]
                y[i, :, :] = Y_train[gen_data.current_idx]
                gen_data.current_idx  = 1
            yield x, y
gen_data.current_idx = 0


for epoch in range(100):
    model.fit_generator(generate_data(), len(X_train)//batch_size, 1,
                        validation_data=None, max_queue_size=1, shuffle=False)
    gen_data.current_idx = 0
  

Этот код не выдает мне ошибку, но у меня есть два вопроса по этому поводу:

1) Внутри генератора я устанавливаю скрытое состояние LSTM model.layers[0].states[0] в переменную on hidden_states[gen_data.current_idx] с формой (2,). Почему это возможно для LSTM со скрытым размером больше 2?

2) Значения в hidden_states[gen_data.current_idx] также могут быть выводом из модели Keras. Имеет ли смысл для двухслойного LSTM устанавливать скрытое состояние таким образом?

Ответ №1:

Состояния в LSTM

LSTM состоит из элементов, которые вычисляют cell state и hidden state . введите описание изображения здесь

На рисунке верхняя стрелка, выходящая справа от LSTM, указывает на состояние ячейки ( c_t ), а нижняя стрелка — на скрытое состояние ( h_t ). Состояния ячеек являются результатом манипулирования с закрытыми настройками, а размер состояния такой же, как hidden_size у LSTM. Каждое развертывание (с соответствующим вводом X) приводит к собственному состоянию ячейки. В случае LSTM состояние ячейки состоит из двух значений hidden_state( h_t ) из (batch_size x hidden_size) и cell_state ( c_t ) из (batch_size x hidden_size).

 batch_size = 2
num_steps = 5
num_input = num_output = 1
hidden_size = 8

inputs = Input(batch_shape=(batch_size,num_steps, num_input))
lstm, state_h, state_c = LSTM(hidden_size, return_state=True, return_sequences=True)(inputs)
model = Model(inputs=inputs, outputs=[state_h, state_c])

print (model.predict(np.zeros((batch_size, num_steps, num_input))))
print (model.layers[1].cell.state_size)
  

Примечание: В случае GRU / RNN нет состояния ячейки, есть только скрытое состояние, поэтому состояние ячейки в случае просто h_t размера (batch_size , hidden_size)

Ссылка:

Реализация LSTM в Keras

Keras Docs:

количество тензоров состояния равно 1 (для RNN и GRU) или 2 (для LSTM).

Иллюстрированное руководство по LSTM и GRU

Состояния подачи

В вашем примере layers[0] относится к 1 LSTM и layers[1] относится ко 2-му LSTM. Если вы намерены инициализировать состояние ячейки ( c_t ) n-го пакета из состояния ячейки of (n-1), т. е. предыдущего пакета, есть два варианта

  • То, что вы делаете в генераторе, но используйте, states[1] если хотите c_t и states[0] для h_t . Аналогично используйте layers[0] для 1-го LSTM и layers[1] для второго LSTM. Но вместо этого используйте set_value методы. Смотрите редактирование ниже.

  • Используйте keras Stateful=True : При значении состояния true состояния LSTM не сбрасываются после каждого пакета. Таким образом, если у вас есть пакет с 5 образцами данных (каждый с некоторой длиной последовательности), вы получите состояние ячейки для каждого из 5 образцов данных. При значении состояния true эти состояния используются для инициализации состояния ячейки следующего пакета для следующего пакета.

Редактировать:

Метод set_value следует использовать для установки значения тензорной переменной. Код model.layers[0].states[0] = K.variable(value=hidden_states[gen_data.current_idx]) действителен, потому что то, что он делает, изменяет состояние [0], которое указывало на переменную размера (batch_size X hidden_size) на переменную размера (batch_size x 2). Это не изменяет значение тензорной переменной, а скорее указывает на новую тензорную переменную другого измерения.

Тестовый код:

  print (model.layers[0].states[0], hex(id(model.layers[0].states[0])))
 model.layers[0].states[0]= K.variable(np.random.randn(10,2))
 print (model.layers[0].states[0], hex(id(model.layers[0].states[0])))
  

Вывод

 <tf.Variable 'lstm_18/Variable:0' shape=(10, 8) dtype=float32_ref> 0x7f8812e6ee10
<tf.Variable 'Variable_2:0' shape=(10, 2) dtype=float32_ref> 0x7f881269afd0
  

Как вы можете видеть, это две разные переменные. Правильный способ сделать это

  print (model.layers[0].states[0], hex(id(model.layers[0].states[0])))
 K.set_value(model.layers[0].states[0], np.random.randn(10,8))
 print (model.layers[0].states[0], hex(id(model.layers[0].states[0])))
  

Вывод

 <tf.Variable 'lstm_20/Variable:0' shape=(10, 8) dtype=float32_ref> 0x7f881138eb70
<tf.Variable 'lstm_20/Variable:0' shape=(10, 8) dtype=float32_ref> 0x7f881138eb70
  

Если ваш код исправлен, то

 K.set_value(model.layers[0].states[0], np.random.randn(10,2))
  

Выдаст ошибку, поскольку размер тензора и размер значения, которое вы устанавливаете, не совпадают.

Комментарии:

1. спасибо за ваш ответ, но я не вижу ответа на свои вопросы. Мои вопросы были связаны со скрытым состоянием h_t . Мой первый вопрос был: почему в моем примере можно установить h_t с помощью (batch_size x 2), когда обычно требуется ввод формы (batch_size x hidden_size)?

2. @MerklT вы должны использовать метод set_value для установки значения тензора. Пожалуйста, проверьте отредактированный для получения подробной информации.