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

Я создал 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] к переменной на hidden_states[gen_data.current_idx] с формой (2,).Почему это возможно для LSTM со скрытым размером больше 2?

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

1 Ответ

3 голосов
/ 06 апреля 2019

Состояния в LSTM

LSTM состоит из вентилей, которые вычисляют cell state и hidden state.enter image description here

На рисунке верхняя стрелка, выходящая справа от 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)

Ссылка:

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

Документы Keras:

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

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

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

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

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

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

Edit:

Метод 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))

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

...