Tengo varias preguntas que voy a tratar de agrupar en una sola aquí. Actualmente estoy tratando de implementar el entrenamiento de redes neuronales convolucionales en un conjunto de datos de imágenes públicas. Estoy tratando de probar y comparar varias arquitecturas CNN diferentes, por ejemplo, InceptionV3, ResNet, DenseNet, y algunos otros. Para ello, estoy tratando de mantener todo lo demás en el código y el enfoque constante, sólo cambiando la arquitectura. Estoy utilizando una validación cruzada de 5 veces con un conjunto de pruebas de retención del 20%.
Sin embargo, me encuentro con el reto de implementar el ajuste automatizado de los hiperparámetros. Mi código está diseñado de la siguiente manera.
- Dividir los datos en entrenamiento (80%) y prueba (20%)
- Crear KFolds (n=5) a partir de los datos del tren (80% tren, 20% val para cada pliegue).
- Bucle For que itera a través de cada pliegue.
- Dentro del bucle for, estoy usando una función personalizada de data_aumentation que toma los datos X_train, X_val, y_train, y_val, y aumenta los datos de entrenamiento usando ImageDataGenerator().
- Ajustar el modelo en cada pliegue, guardar el modelo con mejor rendimiento por val_loss.
- Ensamblar los modelos y evaluarlos en el conjunto de pruebas (retención inicial del 20%).
Estoy utilizando la API funcional de Keras para la creación de mi modelo. Actualmente estoy estableciendo los hiperparámetros manualmente antes de los pasos de ajuste del modelo + CV.
Así que a mis preguntas:
-
Mi pregunta principal es ¿cuál es el mejor enfoque a partir de aquí para implementar el ajuste automatizado de los hiperparámetros? He encontrado algunas APIs diferentes como hype-tune, pero todas parecen a) no funcionar bien con la API funcional de Keras, o b) tener validación cruzada incorporada, por lo que no puedo usar mi propia función de validación cruzada que he construido.
-
Además, quiero comprobar lo que entiendo que debería ocurrir con el ajuste automatizado: ¿es tan sencillo como que los pasos 2-5 anteriores se repitan para cada conjunto de hiperparámetros candidatos, y luego se tome el rendimiento medio (val_loss) de todos los pliegues y se seleccione el conjunto de hiperparámetros con el menor val_loss medio?
-
Para cualquiera que responda a la pregunta 1), ¿hay alguna forma de hacer el ajuste de hiperparámetros más sofisticado (bayesiano, descenso de gradiente, algoritmos evolutivos)?
-
¿Es éste, en general, un enfoque razonable del problema? ¿Hay algún mérito en reconsiderar CV+holdout, en lugar de hacer algo como la validación cruzada anidada?
Mi código correspondiente:
Función de aumento de datos:
def data_aug(X_train,X_test,y_train,y_test,train_batch_size,test_batch_size):
train_datagen = ImageDataGenerator(
rotation_range=60,
# rescale=1.0/255,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
vertical_flip=True,
fill_mode='nearest')
test_datagen = ImageDataGenerator() # nothing applied to test dataset
train_batch = train_datagen.flow(X_train,y_train,batch_size=train_batch_size, seed=33)
test_batch = test_datagen.flow(X_test,y_test,batch_size=test_batch_size, seed=33)
return (train_batch,test_batch)
Función de validación cruzada
kfold = KFold(n_splits=5, shuffle=True, random_state=33)
cvscores = []
Fold = 1
for train, val in kfold.split(X_train_all, y_train_all):
gc.collect()
K.clear_session()
print ('Fold: ',Fold)
X_train = X_train_all[train]
X_val = X_train_all[val]
X_train = X_train.astype('float32')
X_val = X_val.astype('float32')
y_train = y_train_all[train]
y_val = y_train_all[val]
# Data Augmentation and Normalization
train_batch, val_batch = data_aug(X_train,X_val,y_train,y_val, batch_size, batch_size)
# If model checkpoint is used UNCOMMENT THIS
model_name = 'cnn_keras_Fold_'+str(Fold)+'.h5'
cb = callback()
# create model
model = create_model() # CUSTOM ARCHITECTURE
# Fit generator for Data Augmentation - UNCOMMENT THIS FOR DATA AUGMENTATION
model.fit(train_batch,
validation_data=val_batch,
epochs=epochs,
validation_steps= X_val.shape[0] // batch_size,
steps_per_epoch= X_train.shape[0] // batch_size,
callbacks=cb,
verbose=2)
# evaluate the model
scores = model.evaluate(X_val, y_val, verbose=0)
print("%s: %.2f%%" % (model.metrics_names[1], scores[1]*100))
cvscores.append(scores[1] * 100)
Fold += 1
print("%s: %.2f%%" % ("Mean Accuracy: ",np.mean(cvscores)))
print("%s: %.2f%%" % ("Standard Deviation: +/-", np.std(cvscores)))