Получение слоя keras LSTM для приема двух входов? - PullRequest
0 голосов
/ 09 мая 2018

Я работаю с дополненными последовательностями максимальной длины 50. У меня есть два типа данных последовательности:

1) Последовательность seq1 целых чисел (1-100), соответствующих типам событий (например, [3,6,3,1,45,45 .... 3]

2) Последовательность seq2 целых чисел, представляющая время в минутах от последнего события в seq1. Таким образом, последний элемент равен нулю по определению. Так, например, [100, 96, 96, 45, 44, 12, ... 0]. seq1 и seq2 имеют одинаковую длину, 50.

Я пытаюсь запустить LSTM в первую очередь на данных события / seq1, но время / seq2 сильно влияет на ворота забывания в LSTM. Причина этого в том, что я хочу, чтобы LSTM действительно наказывал старые события и с большей вероятностью забывал их. Я думал о том, чтобы умножить вес забвения на обратную величину текущего значения последовательности время / секв2. Или, может быть (1 / seq2_element + 1), для обработки случаев, когда это ноль минут.

Я вижу в коде keras (класс LSTMCell), где изменение должно быть:

f = self.recurrent_activation(x_f + K.dot(h_tm1_f,self.recurrent_kernel_f))

Так что мне нужно изменить код LSTM в keras, чтобы он принимал несколько входов. В качестве начального теста в классе LSTMCell я изменил функцию вызова, чтобы она выглядела следующим образом:

 def call(self, inputs, states, training=None):
        time_input = inputs[1]
        inputs = inputs[0]

Так что он может обрабатывать два входа, заданные в виде списка.

Когда я пытаюсь запустить модель с помощью Functional API:

# Input 1: event type sequences
# Take the event integer sequences, run them through an embedding layer to get float vectors, then run through LSTM
main_input = Input(shape =(max_seq_length,), dtype = 'int32', name = 'main_input')
x = Embedding(output_dim = embedding_length, input_dim = num_unique_event_symbols, input_length = max_seq_length, mask_zero=True)(main_input)

## Input 2: time vectors 
auxiliary_input = Input(shape=(max_seq_length,1), dtype='float32', name='aux_input')
m = Masking(mask_value = 99999999.0)(auxiliary_input)

lstm_out = LSTM(32)(x, time_vector = m)

# Auxiliary loss here from first input
auxiliary_output = Dense(1, activation='sigmoid', name='aux_output')(lstm_out)

# An abitrary number of dense, hidden layers here
x = Dense(64, activation='relu')(lstm_out)

# The main output node
main_output = Dense(1, activation='sigmoid', name='main_output')(x)

## Compile and fit the model
model = Model(inputs=[main_input, auxiliary_input], outputs=[main_output, auxiliary_output])
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'], loss_weights=[1., 0.2])
print(model.summary())
np.random.seed(21)
model.fit([train_X1, train_X2], [train_Y, train_Y], epochs=1, batch_size=200)

Однако я получаю следующую ошибку:

An `initial_state` was passed that is not compatible with `cell.state_size`. Received `state_spec`=[InputSpec(shape=(None, 50, 1), ndim=3)]; however `cell.state_size` is (32, 32)

Любой совет?

Ответы [ 2 ]

0 голосов
/ 10 мая 2018

Я хотел бы добавить сюда другие идеи. Они не требуют от вас изменения кода Keras.

После слоя внедрения типов событий сложите вложения с затраченным временем. Функция Keras keras.layers.Concatenate(axis=-1). Представьте себе, что один четный тип отображается в n мерный вектор с помощью слоя внедрения. Вы просто добавляете прошедшее время как еще одно измерение после встраивания, чтобы оно стало n+1 вектором.

Другая идея, в некотором роде связанная с вашей проблемой / вопросом и может помочь здесь, это 1D свертка. Свертка может произойти сразу после конкатенированных вложений. Интуиция применения свертки к типам событий и прошедшему времени - фактически свертка 1x1. Таким образом, что вы линейно объединяете два вместе и параметры обучаются. Обратите внимание, что с точки зрения свертки размеры векторов называются каналами. Конечно, вы также можете свернуть более одного события за шаг. Просто попробуйте. Это может или не может помочь.

0 голосов
/ 10 мая 2018

Вы не можете передать список входных данных в рекуррентные слои по умолчанию в Keras. input_spec является фиксированным, и рекуррентный код реализован на основе одного тензорного ввода, также указанного в документации , то есть он не выполняет магическую итерацию по 2 входам с одинаковыми временными шагами и передает этов клетку.Отчасти это связано с тем, как оптимизируются итерации и сделаны предположения, если сеть развернута и т. Д.

Если вам нравятся 2 ввода, вы можете передать constants ( doc ) в ячейкукоторый пройдет тензор как есть.Это в основном для реализации моделей внимания в будущем.Таким образом, 1 вход будет повторяться по временным шагам, а другой - нет.Если вам действительно нужно, чтобы 2 входа повторялись как zip() в python, вам придется реализовать пользовательский слой.

...