2017-05-07 5 views
8

J'ai un jeu de données avec 2 colonnes - Chaque colonne contient un ensemble de documents. Je dois faire correspondre le document de la colonne A avec les documents fournis dans la colonne B. Il s'agit d'un problème de classification supervisé. Ainsi, mes données d'apprentissage contiennent une colonne d'étiquette indiquant si les documents correspondent ou non.Modèle LSTM en Keras avec entrées auxiliaires

Pour résoudre le problème, j'ai créé un ensemble de fonctionnalités, disons f1-f25 (en comparant les 2 documents) et ensuite formé un classificateur binaire sur ces fonctionnalités. Cette approche fonctionne raisonnablement bien, mais maintenant je voudrais évaluer les modèles Deep Learning sur ce problème (en particulier, les modèles LSTM). J'utilise la bibliothèque keras en Python. Après avoir traversé la documentation keras et d'autres tutoriels disponibles en ligne, je suis parvenu à faire ce qui suit:

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) 

Cependant, quand je marque cela sur les données de formation, je reçois le même prob. marquer pour tous les cas. Le problème semble provenir de la manière dont l'entrée auxiliaire est introduite (car elle génère une sortie significative lorsque je supprime l'entrée auxiliaire). J'ai également essayé d'insérer l'entrée auxiliaire à différents endroits du réseau. Mais d'une manière ou d'une autre, je ne pouvais pas le faire fonctionner.

Des pointeurs?

+0

Vous ne savez pas si cela est prévu, mais le paramètre auxiliary_output est seulement (1,). Est-ce vraiment ce que vous attendez? Fusionner 25 entrées auxiliaires avec un seul résultat? - Le modèle avant la sortie auxiliaire est-il conçu pour être «non formable» alors que vous ne formez que la partie finale? –

+0

Eh bien oui.C'est un modèle de classification binaire donc la sortie finale est (1,). La sortie auxiliaire doit-elle être différente? Je suis simplement en train de nourrir dans l'ensemble additionnel de 25 caractéristiques comme l'entrée auxiliaire et par conséquent la forme (25,) – Dataminer

+0

Avez-vous essayé plus d'époques? –

Répondre

0

Eh bien, cela est ouvert depuis plusieurs mois et les gens votent.
J'ai fait quelque chose de très similaire récemment en utilisant this dataset qui peut être utilisé pour prévoir les défauts de cartes de crédit et il contient des données catégoriques des clients (sexe, niveau d'éducation, statut matrimonial etc.) ainsi que l'historique des paiements en séries chronologiques. J'ai donc dû fusionner des séries temporelles avec des données autres que des séries. Ma solution était très similaire à la vôtre en combinant LSTM avec un dense, j'essaie d'adopter l'approche de votre problème. Ce qui a fonctionné pour moi est la couche dense (s) sur l'entrée auxiliaire.

De plus, dans votre cas, une couche partagée aurait du sens, de sorte que les mêmes poids sont utilisés pour "lire" les deux documents. Ma proposition de test sur vos données:

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=[____]) 

Je ne sais pas combien cela peut aider puisque je n'ai pas vos données, donc je ne peux pas essayer. Néanmoins c'est mon meilleur coup.
Je n'ai pas exécuté le code ci-dessus pour des raisons évidentes.