3 votes

l'avant-dernière caractéristique du réseau pour l'intégration ne fonctionne pas

J'aimerais disposer d'une image intégrée pour comprendre quelles sont les images que le réseau considère comme plus proches et quelles sont celles qui semblent être très différentes pour lui. Tout d'abord, j'ai voulu utiliser les callbacks de Tensorboard dans Keras, mais la documentation n'est pas assez claire pour moi, et je n'ai pas pu trouver d'exemples utiles pour le reproduire. Par conséquent, pour être sûr de comprendre ce que je fais, j'ai préféré faire l'intégration moi-même.

Pour ce faire, j'ai prévu de télécharger le modèle déjà entraîné sur mes données, d'enlever les dernières couches (dernier dropout et couche dense), et de prédire sur les images de validation pour obtenir les caractéristiques associées à chaque image. Ensuite, je ferais simplement une ACP sur ces caractéristiques et je tracerais les images en fonction de leurs trois premières valeurs de composantes principales.

Mais je pense que j'ai mal compris quelque chose, car lorsque j'enlève les dernières couches, les prédictions du modèle sont toujours de la taille du nombre de classes, mais pour moi, elles devraient être de la taille de la dernière couche, qui est de 128 dans mon cas.

Ci-dessous se trouve le code pour clarification (où j'ai juste mis les lignes qui semblent utiles pour répondre à la question, mais n'hésitez pas à demander plus de détails) :

#model creation
base_model = applications.inception_v3.InceptionV3(include_top=False, 
                                                   weights='imagenet',
                                                   pooling='avg', 
                                                   input_shape=(img_rows, img_cols, img_channel))
#Adding custom Layers
add_model = Sequential()
add_model.add(Dense(128, activation='relu',input_shape=base_model.output_shape[1:],
                    kernel_regularizer=regularizers.l2(0.001)))
add_model.add(Dropout(0.60))
add_model.add(Dense(2, activation='sigmoid'))   
# creating the final model
model = Model(inputs=base_model.input, outputs=add_model(base_model.output))

J'ai ensuite entraîné le modèle sur un ensemble de données comportant deux classes, et j'ai utilisé le modèle et son poids pour produire des caractéristiques :

model = load_model(os.path.join(ROOT_DIR,'model_1','model_cervigrams_all.h5'))
#remove the last two layers
#remove dense_2
model.layers[-1].pop()
#remove dropout_1
model.layers[-1].pop()
model.summary() # last alyer output shape is : (None, 128), so the removal worked
#predict
model.predict(np.reshape(image,[1,image.shape[0],image.shape[1],3])) #output only two values

Où ai-je tort ? Avez-vous des recommandations à faire ?

1voto

today Points 7336

Solution lorsque vous ajoutez des couches personnalisées à l'aide de l'API fonctionnelle Keras :

Si vous utilisez API fonctionnelle Keras pour ajouter vos couches personnalisées, les solutions suivantes fonctionnent correctement :

# base model creation
base_model = applications.inception_v3.InceptionV3(include_top=False, 
                                                   weights='imagenet',
                                                   pooling='avg', 
                                                   input_shape=(150, 150, 3))
# adding custom Layers
x = Dense(128, activation='relu',input_shape=base_model.output_shape[1:],
                    kernel_regularizer=regularizers.l2(0.001))(base_model.output)
x = Dropout(0.60)(x)
out = Dense(2, activation='sigmoid')(x)

# creating the final model
model = Model(inputs=base_model.input, outputs=out)
model.compile(loss='categorical_crossentropy', optimizer='adam')

Voici comment extraire les activations des couches personnalisées en définissant un nouveau modèle :

# construct a new model to get the activations of custom layers
new_model = Model(model.inputs, [model.layers[-3].output,
                                 model.layers[-2].output,
                                 model.layers[-1].output])

# predict one one random input sample
inp = np.random.rand(1, 150, 150, 3)
output = new_model.predict([inp])

# verify that's what we want
print(output[0].shape)  # shape of first dense layer output, prints: (1, 128) 
print(output[1].shape)  # shape of dropout layer output, prints: (1, 128)
print(output[2].shape)  # shape of second dense layer output, prints: (1, 2)

Vous pouvez également définir une fonction Keras :

from keras import backend as K

func = K.function(inputs=model.inputs + [K.learning_phase()],
                  outputs=[model.layers[-3].output,
                           model.layers[-2].output, 
                           model.layers[-1].output])

# usage of the defined function: 
#     the inputs should be a *list* of input arrays
#     plus 1 or 0 for the train/test mode
sample_input = np.random.rand(1, 150, 150, 3)

# train mode
output = func([sample_input, 1])

# test mode
ouput = func([sample_input, 0])

Il convient de noter que vous devez utilice K.learning_phase() puisque le modèle contient des couches telles que BatchNormalization y Dropout qui se comportent différemment en mode test et en mode train.


REMARQUE : Les solutions ci-dessus ne fonctionnent pas correctement si vous utilisez Sequential pour ajouter vos couches personnalisées. En effet, lors de l'utilisation de add_model(base_model.output) dans la construction de model , l'ensemble add_model est stocké en tant que couche du model . Vous pouvez le vérifier en exécutant model.summary() o print(model.layers[-1]) . Et il n'y a aucun moyen d'accéder à la sortie des couches intermédiaires de ce modèle séquentiel. Bien sûr, vous pouvez utiliser model.layers[-1].layers[1].output (qui est la couche d'abandon) :

new_model = Model(model.inputs, model.layers[-1].layers[1].output)
new_model.predict(...)

Cependant, il se plaindrait que le graphe est déconnecté puisque l'entrée originale du modèle séquentiel n'a pas été alimentée :

ValueError: Graph disconnected: cannot obtain value for tensor Tensor("dense_7_input:0", shape=(?, 2048), dtype=float32) at layer "dense_7_input". The following previous layers were accessed without issue: []

En fait, je m'attendais à ce que les couches internes du modèle séquentiel (c.-à-d. model.layers[-1].layer[1:] ) ont des nœuds entrants et sortants supplémentaires, mais il semble que ce ne soit pas le cas. Je ne sais pas si j'ai raté quelque chose ou s'il s'agit d'un bug ou d'une impossibilité dans Keras.


Note complémentaire : En fait, l'utilisation de pop() en layers attribut de l'objet modèle ne fonctionne pas car vous devez mettre à jour certains attributs internes du modèle (bien que, uniquement pour les modèles séquentiels, une fonction intégrée pop() a été mise en œuvre).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X