Ce message semble indiquer que ce que je veux accomplir n'est pas possible. Cependant, je ne suis pas convaincu de cela - compte tenu de ce que j'ai déjà fait, je ne vois pas pourquoi ce que je veux faire ne peut pas être réalisé ...
J'ai deux jeux de données d'images où l'un a des images de forme (480, 720, 3) tandis que l'autre a des images de forme (540, 960, 3).
J'ai initialisé un modèle en utilisant le code suivant:
input = Input(shape=(480, 720, 3), name='image_input')
initial_model = VGG16(weights='imagenet', include_top=False)
for layer in initial_model.layers:
layer.trainable = False
x = Flatten()(initial_model(input))
x = Dense(1000, activation='relu')(x)
x = BatchNormalization()(x)
x = Dropout(0.5)(x)
x = Dense(1000, activation='relu')(x)
x = BatchNormalization()(x)
x = Dropout(0.5)(x)
x = Dense(14, activation='linear')(x)
model = Model(inputs=input, outputs=x)
model.compile(loss='mse', optimizer='adam', metrics=['mae'])
Maintenant que j'ai formé ce modèle sur l'ancien jeu de données, j'aimerais supprimer la couche de tenseur d'entrée et ajouter le modèle avec un nouveau tenseur d'entrée avec une forme qui correspond aux dimensions de l'image de ce dernier jeu de données.
model = load_model('path/to/my/trained/model.h5')
old_input = model.pop(0)
new_input = Input(shape=(540, 960, 3), name='image_input')
x = model(new_input)
m = Model(inputs=new_input, outputs=x)
m.save('transfer_model.h5')
ce qui donne cette erreur:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/aicg2/.local/lib/python2.7/site-packages/keras/engine/topology.py", line 2506, in save
save_model(self, filepath, overwrite, include_optimizer)
File "/home/aicg2/.local/lib/python2.7/site-packages/keras/models.py", line 106, in save_model
'config': model.get_config()
File "/home/aicg2/.local/lib/python2.7/site-packages/keras/engine/topology.py", line 2322, in get_config
layer_config = layer.get_config()
File "/home/aicg2/.local/lib/python2.7/site-packages/keras/engine/topology.py", line 2370, in get_config
new_node_index = node_conversion_map[node_key]
KeyError: u'image_input_ib-0'
Dans le message que j'ai lié, maz indique qu'il existe une incompatibilité de dimension qui empêche de changer la couche d'entrée d'un modèle - si tel était le cas, comment se fait-il que je mette une couche d'entrée (480, 720, 3) devant du modèle VGG16 qui attend (224, 224, 3) des images?
Je pense qu'un problème plus probable est que la sortie de mon ancien modèle attend quelque chose de différent de ce que je lui donne en fonction de ce que fchollet dit dans ce post . Je suis confus syntaxiquement, mais je crois que le x = Layer()(x)
segment entier construit le calque morceau par morceau à partir de l'entrée-> sortie et simplement jeter une entrée différente devant le casse.
Je n'en ai vraiment aucune idée cependant ...
Quelqu'un peut-il m'éclairer sur la façon d'accomplir ce que j'essaie de faire ou, si ce n'est pas possible, m'expliquer pourquoi?
Réponses:
Pour ce faire, créez une nouvelle instance de modèle VGG16 avec la nouvelle forme d'entrée
new_shape
et copiez tous les poids de calque. Le code est à peu prèsla source
Traceback (most recent call last): File "predict_video11.py", line 67, in <module> new_layer.set_weights(layer.get_weights()) File "/usr/local/lib/python2.7/dist-packages/keras/engine/base_layer.py", line 1057, in set_weights 'provided weight shape ' + str(w.shape)) ValueError: Layer weight shape (3, 3, 33, 64) not compatible with provided weight shape (3, 3, 9, 64)
et c'est la couche d'entrée alors utilisez[2:]
?La largeur et la hauteur de sortie des dimensions de sortie du VGGnet sont une partie fixe de la largeur et de la hauteur d'entrée car les seules couches qui modifient ces dimensions sont les couches de regroupement. Le nombre de canaux dans la sortie est fixé au nombre de filtres dans la dernière couche convolutionnelle. La couche aplatie la remodèlera pour obtenir une dimension avec la forme:
((input_width * x) * (input_height * x) * channels)
où x est un nombre décimal <1.
Le point principal est que la forme de l'entrée des couches Denses dépend de la largeur et de la hauteur de l'entrée de l'ensemble du modèle. L'entrée de forme dans la couche dense ne peut pas changer car cela signifierait ajouter ou supprimer des nœuds du réseau neuronal.
Une façon d'éviter cela est d'utiliser une couche de mise en commun globale plutôt qu'une couche aplatie (généralement GlobalAveragePooling2D), cela trouvera la moyenne par canal provoquant la forme de l'entrée des couches Denses
(channels,)
qui ne dépend pas de la forme d'entrée. l'ensemble du modèle.Une fois cela fait, aucune des couches du réseau ne dépend de la largeur et de la hauteur de l'entrée, de sorte que la couche d'entrée peut être modifiée avec quelque chose comme
la source
model.layers[0] = input_layer
ne fonctionne pas pour moi dans TF 2.1. Il n'y a pas d'erreur, mais le calque n'est pas réellement remplacé. Il semble que la copie des poids peut être plus robuste (voir les autres réponses).Voici une autre solution, non spécifique au modèle VGG.
Notez que les poids de la couche dense ne peuvent pas être copiés (et seront donc nouvellement initialisés). Cela a du sens, car la forme des poids diffère dans l'ancien et le nouveau modèle.
la source
Cela devrait être assez facile avec
kerassurgeon
. Vous devez d'abord installer la bibliothèque; selon que vous utilisez Keras via TensorFlow (avec tf 2.0 et supérieur) ou Keras en tant que bibliothèque distincte, il doit être installé de différentes manières.Pour Keras dans TF:
pip install tfkerassurgeon
( https://github.com/Raukk/tf-keras-surgeon ). Pour Keras autonome:pip install kerassurgeon
( https://github.com/BenWhetton/keras-surgeon )Pour remplacer l'entrée (exemple avec TF 2.0; code actuellement non testé):
la source
@gebbissimo answer a fonctionné pour moi dans TF2 avec seulement de petites adaptations que je partage ci-dessous dans une seule fonction:
la source
C'est ainsi que je modifie la taille d'entrée dans le modèle Keras. J'ai deux modèles CNN, l'un avec une taille d'entrée [Aucun, Aucun, 3] tandis que l'autre a une taille d'entrée [512 512,3]. Les deux modèles ont les mêmes poids. En utilisant set_weights (model.get_weights ()), les poids du modèle 1 peuvent être transférés vers le modèle 2
la source