J'ai du mal à mettre au point un modèle Inception avec Keras.
J'ai réussi à utiliser des tutoriels et de la documentation pour générer un modèle de couches supérieures entièrement connectées qui classe mon jeu de données dans les catégories appropriées avec une précision de plus de 99% à l'aide des fonctionnalités de goulot d'étranglement de Inception.
import numpy as np
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers import Dropout, Flatten, Dense
from keras import applications
# dimensions of our images.
img_width, img_height = 150, 150
#paths for saving weights and finding datasets
top_model_weights_path = 'Inception_fc_model_v0.h5'
train_data_dir = '../data/train2'
validation_data_dir = '../data/train2'
#training related parameters?
inclusive_images = 1424
nb_train_samples = 1424
nb_validation_samples = 1424
epochs = 50
batch_size = 16
def save_bottlebeck_features():
datagen = ImageDataGenerator(rescale=1. / 255)
# build bottleneck features
model = applications.inception_v3.InceptionV3(include_top=False, weights='imagenet', input_shape=(img_width,img_height,3))
generator = datagen.flow_from_directory(
train_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode='categorical',
shuffle=False)
bottleneck_features_train = model.predict_generator(
generator, nb_train_samples // batch_size)
np.save('bottleneck_features_train', bottleneck_features_train)
generator = datagen.flow_from_directory(
validation_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode='categorical',
shuffle=False)
bottleneck_features_validation = model.predict_generator(
generator, nb_validation_samples // batch_size)
np.save('bottleneck_features_validation', bottleneck_features_validation)
def train_top_model():
train_data = np.load('bottleneck_features_train.npy')
train_labels = np.array(range(inclusive_images))
validation_data = np.load('bottleneck_features_validation.npy')
validation_labels = np.array(range(inclusive_images))
print('base size ', train_data.shape[1:])
model = Sequential()
model.add(Flatten(input_shape=train_data.shape[1:]))
model.add(Dense(1000, activation='relu'))
model.add(Dense(inclusive_images, activation='softmax'))
model.compile(loss='sparse_categorical_crossentropy',
optimizer='Adam',
metrics=['accuracy'])
proceed = True
#model.load_weights(top_model_weights_path)
while proceed:
history = model.fit(train_data, train_labels,
epochs=epochs,
batch_size=batch_size)#,
#validation_data=(validation_data, validation_labels), verbose=1)
if history.history['acc'][-1] > .99:
proceed = False
model.save_weights(top_model_weights_path)
save_bottlebeck_features()
train_top_model()
Epoque 50/50 1424/1424 [============================] - 17s 12ms/étape - perte: 0.0398 - acc: 0.9909
J'ai également pu empiler ce modèle sur le début pour créer mon modèle complet et utiliser ce modèle complet pour classifier avec succès mon ensemble d'entraînement.
from keras import Model
from keras import optimizers
from keras.callbacks import EarlyStopping
img_width, img_height = 150, 150
top_model_weights_path = 'Inception_fc_model_v0.h5'
train_data_dir = '../data/train2'
validation_data_dir = '../data/train2'
#how many inclusive examples do we have?
inclusive_images = 1424
nb_train_samples = 1424
nb_validation_samples = 1424
epochs = 50
batch_size = 16
# build the complete network for evaluation
base_model = applications.inception_v3.InceptionV3(weights='imagenet', include_top=False, input_shape=(img_width,img_height,3))
top_model = Sequential()
top_model.add(Flatten(input_shape=base_model.output_shape[1:]))
top_model.add(Dense(1000, activation='relu'))
top_model.add(Dense(inclusive_images, activation='softmax'))
top_model.load_weights(top_model_weights_path)
#combine base and top model
fullModel = Model(input= base_model.input, output= top_model(base_model.output))
#predict with the full training dataset
results = fullModel.predict_generator(ImageDataGenerator(rescale=1. / 255).flow_from_directory(
train_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode='categorical',
shuffle=False))
l'inspection des résultats du traitement sur ce modèle complet correspond à la précision du modèle entièrement connecté généré par le goulot d'étranglement.
import matplotlib.pyplot as plt
import operator
#retrieve what the softmax based class assignments would be from results
resultMaxClassIDs = [ max(enumerate(result), key=operator.itemgetter(1))[0] for result in results]
#resultMaxClassIDs should be equal to range(inclusive_images) so we subtract the two and plot the log of the absolute value
#looking for spikes that indicate the values aren't equal
plt.plot([np.log(np.abs(x)+10) for x in (np.array(resultMaxClassIDs) - np.array(range(inclusive_images)))])
Voici le problème: Lorsque je prends ce modèle complet pour tenter de le former, la précision tombe à 0 même si la validation reste supérieure à 99%.
model2 = fullModel
for layer in model2.layers[:-2]:
layer.trainable = False
# compile the model with a SGD/momentum optimizer
# and a very slow learning rate.
#model.compile(loss='binary_crossentropy', optimizer=optimizers.SGD(lr=1e-4, momentum=0.9), metrics=['accuracy'])
model2.compile(loss='categorical_crossentropy',
optimizer=optimizers.SGD(lr=1e-4, momentum=0.9),
metrics=['accuracy'])
train_datagen = ImageDataGenerator(rescale=1. / 255)
test_datagen = ImageDataGenerator(rescale=1. / 255)
train_generator = train_datagen.flow_from_directory(
train_data_dir,
target_size=(img_height, img_width),
batch_size=batch_size,
class_mode='categorical')
validation_generator = test_datagen.flow_from_directory(
validation_data_dir,
target_size=(img_height, img_width),
batch_size=batch_size,
class_mode='categorical')
callback = [EarlyStopping(monitor='acc', min_delta=0, patience=3, verbose=0, mode='auto', baseline=None)]
# fine-tune the model
model2.fit_generator(
#train_generator,
validation_generator,
steps_per_Epoch=nb_train_samples//batch_size,
validation_steps = nb_validation_samples//batch_size,
epochs=epochs,
validation_data=validation_generator)
Epoque 1/50 89/89 [============================] - 388s 4s/step - perte: 13.5787 - acc: 0.0000e + 00 - val_loss: 0.0353 - val_acc: 0.9937
et ça empire à mesure que les choses avancent
Epoque 21/50 89/89 [============================] - 372s 4s/step - perte: 7.3850 - acc: 0.0035 - val_loss : 0.5813 - val_acc: 0.8272
La seule chose à laquelle je pouvais penser, c’est que les étiquettes d’entraînement ont été mal assignées dans ce dernier train, mais j’ai réussi à le faire avec un code similaire en utilisant VGG16 auparavant.
J'ai parcouru le code en essayant de trouver une incohérence pour expliquer pourquoi un modèle qui fait des prédictions précises 99% du temps laisse tomber la précision de son entraînement tout en maintenant la précision de la validation lors du réglage, mais je ne peux pas le comprendre. Toute aide serait appréciée.
Informations sur le code et l'environnement:
Les choses qui vont paraître étranges, mais qui sont censées l'être:
J'utilise:
J'ai vérifié:
mais ils semblent sans rapport.
Remarque: Étant donné que votre problème est un peu étrange et difficile à déboguer sans votre modèle et votre jeu de données formés, cette réponse est juste une (meilleure) hypothèse, après avoir examiné de nombreux problèmes qui pourraient se produire. S'il vous plaît fournir vos commentaires et je vais supprimer cette réponse si cela ne fonctionne pas.
Puisque inception_V3 contient des couches BatchNormalization
, le problème est peut-être dû au comportement (quelque peu ambigu ou inattendu) de cette couche lorsque vous définissez le paramètre trainable
sur False
( 1 , 2 , 3 , 4 ).
Voyons maintenant s’il s’agit de la racine du problème: comme suggéré par @fchollet , définissez la phase d’apprentissage lors de la définition du modèle à ajuster:
from keras import backend as K
K.set_learning_phase(0)
base_model = applications.inception_v3.InceptionV3(weights='imagenet', include_top=False, input_shape=(img_width,img_height,3))
for layer in base_model.layers:
layer.trainable = False
K.set_learning_phase(1)
top_model = Sequential()
top_model.add(Flatten(input_shape=base_model.output_shape[1:]))
top_model.add(Dense(1000, activation='relu'))
top_model.add(Dense(inclusive_images, activation='softmax'))
top_model.load_weights(top_model_weights_path)
#combine base and top model
fullModel = Model(input= base_model.input, output= top_model(base_model.output))
fullModel.compile(loss='categorical_crossentropy',
optimizer=optimizers.SGD(lr=1e-4, momentum=0.9),
metrics=['accuracy'])
#####################################################################
# Here, define the generators and then fit the model same as before #
#####################################################################
Côté Remarque: Cela ne pose aucun problème dans votre cas, mais n'oubliez pas que lorsque vous utilisez top_model(base_model.output)
, le modèle séquentiel complet (c'est-à-dire top_model
) est stocké sous la forme d'une couche de fullModel
. Vous pouvez le vérifier en utilisant fullModel.summary()
ou print(fullModel.layers[-1])
. D'où quand vous avez utilisé:
for layer in model2.layers[:-2]:
layer.trainable = False
vous ne gèlez pas non plus la dernière couche de base_model
. Toutefois, comme il s'agit d'une couche Concatenate
et que, par conséquent, aucun paramètre ne peut être défini, aucun problème ne se produit et il se comporterait comme prévu.
Comme la réponse précédente, je vais essayer de partager quelques réflexions pour voir si cela aide.
Il y a un certain nombre de choses qui ont attiré mon attention (et qui méritent d’être passées en revue). Remarque: certains d’entre eux auraient également dû vous donner des problèmes avec les différents modèles.
sparse_categorical_crossentropy
pour le premier entraînement, alors que vous avez utilisé categorical_crossentropy
pour le second. Est-ce correct? Parce que je pense qu'ils assument les étiquettes différemment (rares supposent des entiers et l'autre suppose un chaud).trainable = True
? Je sais que vous avez déjà paramétré les autres sur trainable = False
, mais c'est peut-être aussi une chose à vérifier.J'espère que ça aide.