Модель LSTM в Keras с дополнительными входами

У меня есть набор данных с двумя столбцами. Каждый столбец содержит набор документов. Я должен сопоставить документ в столбце A с документами, представленными в столбце B. Это проблема контролируемой классификации. Таким образом, мои обучающие данные содержат столбец меток, указывающий, совпадают ли документы или нет.

Чтобы решить эту проблему, я создал набор функций, скажем, f1-f25 (путем сравнения двух документов), а затем обучил двоичный классификатор этим функциям. Этот подход работает достаточно хорошо, но теперь я хотел бы оценить модели глубокого обучения по этой проблеме (в частности, модели LSTM).

Я использую библиотеку keras в Python. После изучения документации keras и других руководств, доступных в Интернете, мне удалось сделать следующее:

from keras.layers import Input, Embedding, LSTM, Dense
from keras.models import Model

# Each document contains a series of 200 words 
# The necessary text pre-processing steps have been completed to transform  
  each doc to a fixed length seq
main_input1 = Input(shape=(200,), dtype='int32', name='main_input1')
main_input2 = Input(shape=(200,), dtype='int32', name='main_input2')

# Next I add a word embedding layer (embed_matrix is separately created    
for each word in my vocabulary by reading from a pre-trained embedding model)
x = Embedding(output_dim=300, input_dim=20000, 
input_length=200, weights = [embed_matrix])(main_input1)
y = Embedding(output_dim=300, input_dim=20000, 
input_length=200, weights = [embed_matrix])(main_input2)

# Next separately pass each layer thru a lstm layer to transform seq of   
vectors into a single sequence
lstm_out_x1 = LSTM(32)(x)
lstm_out_x2 = LSTM(32)(y)

# concatenate the 2 layers and stack a dense layer on top
x = keras.layers.concatenate([lstm_out_x1, lstm_out_x2])
x = Dense(64, activation='relu')(x)
# generate intermediate output
auxiliary_output = Dense(1, activation='sigmoid', name='aux_output')(x)

# add auxiliary input - auxiliary inputs contains 25 features for each document pair
auxiliary_input = Input(shape=(25,), name='aux_input')

# merge aux output with aux input and stack dense layer on top
main_input = keras.layers.concatenate([auxiliary_output, auxiliary_input])
x = Dense(64, activation='relu')(main_input)
x = Dense(64, activation='relu')(x)

# finally add the main output layer
main_output = Dense(1, activation='sigmoid', name='main_output')(x)

model = Model(inputs=[main_input1, main_input2, auxiliary_input], outputs= main_output)
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])

model.fit([x1, x2,aux_input], y,
      epochs=3, batch_size=32)

Однако, когда я оцениваю это на данных обучения, я получаю ту же проблему. оценка для всех случаев. Проблема, по-видимому, связана с тем, как подается дополнительный вход (потому что он генерирует значимый вывод, когда я удаляю дополнительный вход). Я также пробовал вставлять вспомогательный вход в разные места в сети. Но почему-то я не мог заставить это работать.

Любые указатели?


person Dataminer    schedule 07.05.2017    source источник
comment
Не уверен, что это предназначено, но вспомогательный_выход - это только (1,). Это действительно то, что вы ожидаете? Объединить 25 вспомогательных входов только с одним результатом? -- Предполагается ли, что модель перед вспомогательным выходом не поддается обучению, пока вы обучаете только последнюю часть?   -  person Daniel Möller    schedule 12.05.2017
comment
Ну да. Это модель бинарной классификации, поэтому окончательный результат равен (1,). Должен ли вспомогательный выход быть другим? Я просто подаю дополнительный набор из 25 функций в качестве вспомогательного ввода и, следовательно, форму (25,)   -  person Dataminer    schedule 13.05.2017
comment
Вы пробовали больше эпох?   -  person Marcin Możejko    schedule 29.10.2017


Ответы (2)


Ну, это открыто в течение нескольких месяцев, и люди голосуют за него.
Недавно я сделал что-то очень похожее, используя этот набор данных, который можно использовать для прогнозирования дефолтов по кредитным картам, и он содержит категориальные данные о клиентах (пол, уровень образования, статус брака и т. д.), а также история платежей в виде временных рядов. Поэтому мне пришлось объединить временные ряды с несерийными данными. Мое решение было очень похоже на ваше, объединив LSTM с плотным, я пытаюсь перенять подход к вашей проблеме. Что сработало для меня, так это плотный слой (слои) на вспомогательном входе.

Кроме того, в вашем случае общий слой имел бы смысл, поэтому для «чтения» обоих документов используются одинаковые веса. Мое предложение по тестированию на ваших данных:

from keras.layers import Input, Embedding, LSTM, Dense
from keras.models import Model

# Each document contains a series of 200 words 
# The necessary text pre-processing steps have been completed to transform  
  each doc to a fixed length seq
main_input1 = Input(shape=(200,), dtype='int32', name='main_input1')
main_input2 = Input(shape=(200,), dtype='int32', name='main_input2')

# Next I add a word embedding layer (embed_matrix is separately created    
for each word in my vocabulary by reading from a pre-trained embedding model)
x1 = Embedding(output_dim=300, input_dim=20000, 
input_length=200, weights = [embed_matrix])(main_input1)
x2 = Embedding(output_dim=300, input_dim=20000, 
input_length=200, weights = [embed_matrix])(main_input2)

# Next separately pass each layer thru a lstm layer to transform seq of   
vectors into a single sequence
# Comment Manngo: Here I changed to shared layer
# Also renamed y as input as it was confusing
# Now x and y are x1 and x2
lstm_reader = LSTM(32)
lstm_out_x1 = lstm_reader(x1)
lstm_out_x2 = lstm_reader(x2)

# concatenate the 2 layers and stack a dense layer on top
x = keras.layers.concatenate([lstm_out_x1, lstm_out_x2])
x = Dense(64, activation='relu')(x)
x = Dense(32, activation='relu')(x)
# generate intermediate output
# Comment Manngo: This is created as a dead-end
# It will not be used as an input of any layers below
auxiliary_output = Dense(1, activation='sigmoid', name='aux_output')(x)

# add auxiliary input - auxiliary inputs contains 25 features for each document pair
# Comment Manngo: Dense branch on the comparison features
auxiliary_input = Input(shape=(25,), name='aux_input')
auxiliary_input = Dense(64, activation='relu')(auxiliary_input)
auxiliary_input = Dense(32, activation='relu')(auxiliary_input)

# OLD: merge aux output with aux input and stack dense layer on top
# Comment Manngo: actually this is merging the aux output preparation dense with the aux input processing dense
main_input = keras.layers.concatenate([x, auxiliary_input])
main = Dense(64, activation='relu')(main_input)
main = Dense(64, activation='relu')(main)

# finally add the main output layer
main_output = Dense(1, activation='sigmoid', name='main_output')(main)

# Compile
# Comment Manngo: also define weighting of outputs, main as 1, auxiliary as 0.5
model.compile(optimizer=adam,
              loss={'main_output': 'w_binary_crossentropy', 'aux_output': 'binary_crossentropy'},
              loss_weights={'main_output': 1.,'auxiliary_output': 0.5},
              metrics=['accuracy'])

# Train model on main_output and on auxiliary_output as a support
# Comment Manngo: Unknown information marked with placeholders ____
# We have 3 inputs: x1 and x2: the 2 strings
# aux_in: the 25 features
# We have 2 outputs: main and auxiliary; both have the same targets -> (binary)y


model.fit({'main_input1': __x1__, 'main_input2': __x2__, 'auxiliary_input' : __aux_in__}, {'main_output': __y__, 'auxiliary_output': __y__}, 
              epochs=1000, 
              batch_size=__, 
              validation_split=0.1, 
              callbacks=[____])

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

person Manngo    schedule 31.01.2018
comment
Я работаю над продольными медицинскими данными и пытаюсь понять, что вы сделали. Два объединенных слоя lstm получают два разных набора входных данных. Я прав ? - person Naveen Gabriel; 28.12.2019
comment
Да, х1 и х2 в моей редакции. - person Manngo; 03.01.2020
comment
@Manngo привет, мне также нужно объединить временные ряды с нерядовыми данными, чтобы предсказать метеорологическую переменную в разных местах (дифференцированных нерядовыми данными). Не могли бы вы поделиться тем, что вы сделали в этом отношении? в моем случае длина данных временных рядов различается в разных местах. - person Basilique; 03.08.2020
comment
@Basilique Вы имеете в виду несколько прогнозов из 1 модели, по одному для каждого местоположения? Для временных рядов разной длины вы можете, возможно, заглянуть в PLSTM, который поддерживает переменную выборку, но в том же временном окне. - person Manngo; 11.08.2020
comment
@Manngo У меня есть две функции, зависящие от времени, T, P и две переменные, не зависящие от времени, S и D. Целью также является переменная, зависящая от времени Q. Я хотел бы иметь глобальную модель, которая обучается на основе информации от всех мои 500 станций вместо обучения 500 местных индивидуальных моделей. Я хотел бы, чтобы глобальная модель имела две ветви: восходящую ветвь, в которую я передаю переменные, не относящиеся к временным рядам, а затем нисходящую ветвь, в которую я передаю временные ряды 500 местоположений. Я использовал generator для своих локальных моделей. Я не знаю, как совместить генераторы с embedding слоями. - person Basilique; 12.08.2020
comment
@Basilique, я рад продолжить обсуждение, но не могли бы вы открыть для этого новую тему. Не здесь, а на Cross Validated, чтобы мы могли продолжить обсуждение в нужном месте? После открытия новой темы, пожалуйста, добавьте комментарий и процитируйте меня там, чтобы я получил уведомление по электронной почте. - person Manngo; 14.08.2020
comment
@Manngo очень благодарен, я сделаю это. - person Basilique; 14.08.2020
comment
@Manngo По твоему совету я открыл тему на Cross Validated. Я понял, что мой комментарий под открытой темой был удален. Заголовок stats.stackexchange.com/questions/483230/ - person Basilique; 16.08.2020

Я нашел ответы на https://datascience.stackexchange.com/questions/17099/adding-features-to-time-series-model-lstm Г-н Филипп Реми написал библиотеку для обработки вспомогательных входных данных. Я использовал его библиотеку, и это очень полезно.

# 10 stations
# 365 days
# 3 continuous variables A and B => C is target.
# 2 conditions dim=5 and dim=1. First cond is one-hot. Second is continuous.
import numpy as np
from tensorflow.keras.layers import Dense
from tensorflow.keras.models import Sequential

from cond_rnn import ConditionalRNN

stations = 10  # 10 stations.
time_steps = 365  # 365 days.
continuous_variables_per_station = 3  # A,B,C where C is the target.
condition_variables_per_station = 2  # 2 variables of dim 5 and 1.
condition_dim_1 = 5
condition_dim_2 = 1

np.random.seed(123)
continuous_data = np.random.uniform(size=(stations, time_steps, continuous_variables_per_station))
condition_data_1 = np.zeros(shape=(stations, condition_dim_1))
condition_data_1[:, 0] = 1  # dummy.
condition_data_2 = np.random.uniform(size=(stations, condition_dim_2))

window = 50  # we split series in 50 days (look-back window)

x, y, c1, c2 = [], [], [], []
for i in range(window, continuous_data.shape[1]):
    x.append(continuous_data[:, i - window:i])
    y.append(continuous_data[:, i])
    c1.append(condition_data_1)  # just replicate.
    c2.append(condition_data_2)  # just replicate.

# now we have (batch_dim, station_dim, time_steps, input_dim).
x = np.array(x)
y = np.array(y)
c1 = np.array(c1)
c2 = np.array(c2)

print(x.shape, y.shape, c1.shape, c2.shape)

# let's collapse the station_dim in the batch_dim.
x = np.reshape(x, [-1, window, x.shape[-1]])
y = np.reshape(y, [-1, y.shape[-1]])
c1 = np.reshape(c1, [-1, c1.shape[-1]])
c2 = np.reshape(c2, [-1, c2.shape[-1]])

print(x.shape, y.shape, c1.shape, c2.shape)

model = Sequential(layers=[
    ConditionalRNN(10, cell='GRU'),  # num_cells = 10
    Dense(units=1, activation='linear')  # regression problem.
])

model.compile(optimizer='adam', loss='mse')
model.fit(x=[x, c1, c2], y=y, epochs=2, validation_split=0.2)
person Arj184cm    schedule 09.07.2021