web-dev-qa-db-fra.com

Comment changer la forme d'entrée dans le modèle séquentiel dans Keras

J'ai un modèle séquentiel que j'ai construit à Keras. J'essaie de comprendre comment changer la forme de l'entrée. Dans l'exemple suivant

model = Sequential()
model.add(Dense(32, input_shape=(500,)))
model.add(Dense(10, activation='softmax'))
model.compile(optimizer='rmsprop',
      loss='categorical_crossentropy',
      metrics=['accuracy'])

disons que je veux construire un nouveau modèle avec différentes formes d'entrée, conceptuel cela devrait ressembler à ceci:

model1 = model
model1.layers[0] = Dense(32, input_shape=(250,))

existe-t-il un moyen de modifier la forme d'entrée du modèle?

9
itamar kanter

Réfléchissez à ce que signifierait changer la forme d'entrée dans cette situation.

Votre premier modèle

model.add(Dense(32, input_shape=(500,)))

A une couche dense qui est vraiment une matrice 500x32.

Si vous modifiez votre entrée à 250 éléments, la matrice et la dimension d'entrée de vos calques ne correspondent pas.

Si, cependant, ce que vous tentiez de réaliser était de réutiliser les paramètres entraînés de votre dernière couche à partir de votre premier modèle d'entrée à 500 éléments, vous pourriez obtenir ces poids par get_weights. Ensuite, vous pouvez reconstruire un nouveau modèle et définir des valeurs sur le nouveau modèle avec set_weights.

model1 = Sequential()
model1.add(Dense(32, input_shape=(250,)))
model1.add(Dense(10, activation='softmax'))
model1.layers[1].set_weights(model1.layers[1].get_weights())

Gardez à l'esprit que la première couche de model1 (aka model1.layers [0]) ne serait toujours pas formée

1
maz

Quelque peu lié, alors j'espère que quelqu'un trouvera cela utile: si vous avez un modèle existant où l'entrée est un espace réservé qui ressemble à (Aucun, Aucun, Aucun, 3) par exemple, vous pouvez charger le modèle, remplacer le premier calque par un entrée de forme concrète. Une transformation de ce type est très utile lorsque, par exemple, vous souhaitez utiliser votre modèle dans iOS CoreML (dans mon cas, l'entrée du modèle était un MLMultiArray au lieu de CVPixelBuffer, et la compilation du modèle a échoué)

from keras.models import load_model
from keras import backend as K
from keras.engine import InputLayer
import coremltools

model = load_model('your_model.h5')

# Create a new input layer to replace the (None,None,None,3) input layer :
input_layer = InputLayer(input_shape=(272, 480, 3), name="input_1")

# Save and convert :
model.layers[0] = input_layer
model.save("reshaped_model.h5")    
coreml_model = coremltools.converters.keras.convert('reshaped_model.h5')    
coreml_model.save('MyPredictor.mlmodel')
11
ohad serfaty

Voici une autre solution sans définir chaque couche du modèle à partir de zéro. La clé pour moi était d'utiliser "_layers" au lieu de "couches". Ce dernier ne semble renvoyer qu'une copie.

import keras
import numpy as np

def get_model():
    old_input_shape = (20, 20, 3)
    model = keras.models.Sequential()
    model.add(keras.layers.Conv2D(9, (3, 3), padding="same", input_shape=old_input_shape))
    model.add(keras.layers.MaxPooling2D((2, 2)))
    model.add(keras.layers.Flatten())
    model.add(keras.layers.Dense(1, activation="sigmoid"))
    model.compile(loss='binary_crossentropy', optimizer=keras.optimizers.Adam(lr=0.0001), metrics=['acc'], )
    model.summary()
    return model

def change_model(model, new_input_shape=(None, 40, 40, 3)):
    # replace input shape of first layer
    model._layers[1].batch_input_shape = new_input_shape

    # feel free to modify additional parameters of other layers, for example...
    model._layers[2].pool_size = (8, 8)
    model._layers[2].strides = (8, 8)

    # rebuild model architecture by exporting and importing via json
    new_model = keras.models.model_from_json(model.to_json())
    new_model.summary()

    # copy weights from old model to new one
    for layer in new_model.layers:
        try:
            layer.set_weights(model.get_layer(name=layer.name).get_weights())
        except:
            print("Could not transfer weights for layer {}".format(layer.name))

    # test new model on a random input image
    X = np.random.Rand(10, 40, 40, 3)
    y_pred = new_model.predict(X)
    print(y_pred)

    return new_model

if __name__ == '__main__':
    model = get_model()
    new_model = change_model(model)
0
gebbissimo