Tengo problemas para ajustar un modelo Inception con Keras.
Logré usar tutoriales y documentación para generar un modelo de capas superiores completamente conectadas que clasifique mi conjunto de datos en sus categorías apropiadas con una precisión de más del 99% usando las funciones de cuello de botella desde el inicio.
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()
Época 50/50 1424/1424 [==============================] – 17s 12ms / step – pérdida: 0.0398 – acc : 0.9909
También he podido astackr este modelo sobre el principio para crear mi modelo completo y usar ese modelo completo para clasificar con éxito mi conjunto de entrenamiento.
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))
La inspección de los resultados del procesamiento en este modelo completo coincide con la precisión del modelo totalmente conectado generado cuello de botella.
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)))])
Aquí está el problema: cuando tomo este modelo completo e bash entrenarlo, la precisión cae a 0, aunque la validación permanece por encima del 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)
Época 1/50 89/89 [===============================] – 388s 4s / step – pérdida: 13.5787 – acc : 0.0000e + 00 – val_loss: 0.0353 – val_acc: 0.9937
y empeora a medida que las cosas progresan.
Época 21/50 89/89 [===============================] – 372s 4s / step – pérdida: 7.3850 – acc : 0.0035 – val_loss: 0.5813 – val_acc: 0.8272
Lo único en lo que pude pensar es que de alguna manera las tags de entrenamiento se asignan incorrectamente en este último tren, pero lo he hecho con éxito con un código similar utilizando VGG16 anteriormente.
He buscado en el código tratando de encontrar una discrepancia para explicar por qué un modelo que realiza predicciones precisas más del 99% del tiempo disminuye su precisión de entrenamiento mientras mantiene la precisión de validación durante el ajuste fino, pero no puedo entenderlo. Cualquier ayuda sería apreciada.
Información sobre el código y el entorno:
Las cosas que van a excel como extrañas, pero están destinadas a ser así:
Estoy usando:
He comprobado:
pero aparecen sin relación.
Nota: debido a que su problema es un poco extraño y difícil de depurar sin tener su modelo y conjunto de datos entrenados, esta respuesta es solo una (la mejor) estimación después de considerar muchas cosas que pueden salir mal. Por favor envíe sus comentarios y eliminaré esta respuesta si no funciona.
Dado que el BatchNormalization
contiene capas BatchNormalization
, tal vez el problema se deba al comportamiento (de alguna manera ambiguo o inesperado) de esta capa cuando establece un parámetro trainable
en False
( 1 , 2 , 3 , 4 ).
Ahora, veamos si esta es la raíz del problema: como lo sugiere @fchollet , establezca la fase de aprendizaje al definir el modelo para el ajuste fino:
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 # #####################################################################
Nota al top_model(base_model.output)
: Esto no causa ningún problema en su caso, pero tenga en cuenta que cuando usa top_model(base_model.output)
todo el modelo secuencial (es decir, top_model
) se almacena como una capa de fullModel
. Puede verificar esto usando fullModel.summary()
o print(fullModel.layers[-1])
. De ahí que cuando usaste:
for layer in model2.layers[:-2]: layer.trainable = False
En realidad, tampoco estás congelando la última capa de base_model
. Sin embargo, dado que es una capa de Concatenate
y, por lo tanto, no tiene parámetros entrenables, no se produce ningún problema y se comportaría como usted quería.
Al igual que en la respuesta anterior, intentaré compartir algunos pensamientos para ver si ayuda.
Hay un par de cosas que llamaron mi atención (y tal vez vale la pena revisarlas). Nota: algunos de ellos también deberían haberle dado problemas con los modelos separados.
sparse_categorical_crossentropy
para el primer entrenamiento mientras que sparse_categorical_crossentropy
categorical_crossentropy
para el segundo. ¿Es correcto? Porque creo que asumen las tags de manera diferente (sparse asume enteros y el otro asume uno-hot). trainable = True
? Sé que ya has configurado a los demás en trainable = False
, pero tal vez eso también valga la pena. Espero que eso ayude.