J'essaie de fusionner 2 modèles séquentiels en keras. Voici le code:
model1 = Sequential(layers=[
# input layers and convolutional layers
Conv1D(128, kernel_size=12, strides=4, padding='valid', activation='relu', input_shape=input_shape),
MaxPooling1D(pool_size=6),
Conv1D(256, kernel_size=12, strides=4, padding='valid', activation='relu'),
MaxPooling1D(pool_size=6),
Dropout(.5),
])
model2 = Sequential(layers=[
# input layers and convolutional layers
Conv1D(128, kernel_size=20, strides=5, padding='valid', activation='relu', input_shape=input_shape),
MaxPooling1D(pool_size=5),
Conv1D(256, kernel_size=20, strides=5, padding='valid', activation='relu'),
MaxPooling1D(pool_size=5),
Dropout(.5),
])
model = merge([model1, model2], mode = 'sum')
Flatten(),
Dense(256, activation='relu'),
Dropout(.5),
Dense(128, activation='relu'),
Dropout(.35),
# output layer
Dense(5, activation='softmax')
return model
Voici le journal des erreurs:
Fichier "/nics/d/home/dsawant/anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py", ligne 392, dans is_keras_tensor lever ValueError ('Une instance de type
' + str(type(x)) + '
. 'ValueError: a trouvé de manière inattendue une instance de type<class 'keras.models.Sequential'>
. Attendu une instance de tenseur symbolique.
Un peu plus de journal:
ValueError: Layer merge_1 a été appelé avec une entrée qui n'est pas un tenseur symbolique. Type reçu: classe 'keras.models.Sequential'. Entrée complète: [objet keras.models.Sequential à 0x2b32d518a780, objet keras.models.Sequential à 0x2b32d521ee80]. Toutes les entrées de la couche doivent être des tenseurs.
Comment puis-je fusionner ces 2 modèles séquentiels qui utilisent différentes tailles de fenêtre et leur appliquent des fonctions telles que "max", "somme", etc.?
L'utilisation de API fonctionnelle vous offre toutes les possibilités.
Lorsque vous utilisez l'API fonctionnelle, vous devez garder une trace des entrées et des sorties, au lieu de simplement définir des couches.
Vous définissez un calque, puis vous appelez le calque avec un tenseur d'entrée pour obtenir le tenseur de sortie. Les modèles et les couches peuvent être appelés exactement de la même manière.
Pour la couche de fusion, je préfère utiliser d'autres couches de fusion plus intuitives, telles que Add()
, Multiply()
et Concatenate()
par exemple.
from keras.layers import *
mergedOut = Add()([model1.output,model2.output])
#Add() -> creates a merge layer that sums the inputs
#The second parentheses "calls" the layer with the output tensors of the two models
#it will demand that both model1 and model2 have the same output shape
Cette même idée s'applique à tous les calques suivants. Nous continuons à mettre à jour le tenseur de sortie en le donnant à chaque couche et en obtenant une nouvelle sortie (si nous étions intéressés par la création de branches, nous utiliserions un var différent pour chaque sortie d'intérêt pour en garder la trace):
mergedOut = Flatten()(mergedOut)
mergedOut = Dense(256, activation='relu')(mergedOut)
mergedOut = Dropout(.5)(mergedOut)
mergedOut = Dense(128, activation='relu')(mergedOut)
mergedOut = Dropout(.35)(mergedOut)
# output layer
mergedOut = Dense(5, activation='softmax')(mergedOut)
Maintenant que nous avons créé le "chemin", il est temps de créer le Model
. Créer le modèle revient à dire à quels tenseurs d'entrée il commence et où il se termine:
from keras.models import Model
newModel = Model([model1.input,model2.input], mergedOut)
#use lists if you want more than one input or output
Notez que puisque ce modèle a deux entrées, vous devez le former avec deux X_training
vars dans une liste:
newModel.fit([X_train_1, X_train_2], Y_train, ....)
Supposons maintenant que vous vouliez une seule entrée et que model1 et model2 prennent la même entrée.
L'API fonctionnelle permet cela assez facilement en créant un tenseur d'entrée et en l'alimentant aux modèles (nous appelons les modèles comme s'ils étaient des couches):
commonInput = Input(input_shape)
out1 = model1(commonInput)
out2 = model2(commonInput)
mergedOut = Add()([out1,out2])
Dans ce cas, le modèle prendrait en compte cette entrée:
oneInputModel = Model(commonInput,mergedOut)