¿Puedo enviar devoluciones de llamada a un KerasClassifier?

Quiero que el clasificador se ejecute más rápido y se detenga antes si la paciencia alcanza el número que establecí. En el siguiente código hace 10 iteraciones de ajuste del modelo.

import numpy import pandas from keras.models import Sequential from keras.layers import Dense from keras.layers import Dropout from keras.wrappers.scikit_learn import KerasClassifier from keras.callbacks import EarlyStopping, ModelCheckpoint from keras.constraints import maxnorm from keras.optimizers import SGD from sklearn.model_selection import cross_val_score from sklearn.preprocessing import LabelEncoder from sklearn.model_selection import StratifiedKFold from sklearn.preprocessing import StandardScaler from sklearn.pipeline import Pipeline # fix random seed for reproducibility seed = 7 numpy.random.seed(seed) # load dataset dataframe = pandas.read_csv("sonar.csv", header=None) dataset = dataframe.values # split into input (X) and output (Y) variables X = dataset[:,0:60].astype(float) Y = dataset[:,60] # encode class values as integers encoder = LabelEncoder() encoder.fit(Y) encoded_Y = encoder.transform(Y) calls=[EarlyStopping(monitor='acc', patience=10), ModelCheckpoint('C:/Users/Nick/Data Science/model', monitor='acc', save_best_only=True, mode='auto', period=1)] def create_baseline(): # create model model = Sequential() model.add(Dropout(0.2, input_shape=(33,))) model.add(Dense(33, init='normal', activation='relu', W_constraint=maxnorm(3))) model.add(Dense(16, init='normal', activation='relu', W_constraint=maxnorm(3))) model.add(Dense(122, init='normal', activation='softmax')) # Compile model sgd = SGD(lr=0.1, momentum=0.8, decay=0.0, nesterov=False) model.compile(loss='categorical_crossentropy', optimizer=sgd, metrics=['accuracy']) return model numpy.random.seed(seed) estimators = [] estimators.append(('standardize', StandardScaler())) estimators.append(('mlp', KerasClassifier(build_fn=create_baseline, nb_epoch=300, batch_size=16, verbose=0, callbacks=calls))) pipeline = Pipeline(estimators) kfold = StratifiedKFold(n_splits=10, shuffle=True, random_state=seed) results = cross_val_score(pipeline, X, encoded_Y, cv=kfold) print("Baseline: %.2f%% (%.2f%%)" % (results.mean()*100, results.std()*100)) 

Aquí está el error resultante

 RuntimeError: Cannot clone object , as the constructor does not seem to set parameter callbacks 

Cambié el cross_val_score en el siguiente

 numpy.random.seed(seed) estimators = [] estimators.append(('standardize', StandardScaler())) estimators.append(('mlp', KerasClassifier(build_fn=create_baseline, nb_epoch=300, batch_size=16, verbose=0, callbacks=calls))) pipeline = Pipeline(estimators) kfold = StratifiedKFold(n_splits=10, shuffle=True, random_state=seed) results = cross_val_score(pipeline, X, encoded_Y, cv=kfold, fit_params={'callbacks':calls}) print("Baseline: %.2f%% (%.2f%%)" % (results.mean()*100, results.std()*100)) 

y ahora me sale este error-

 ValueError: need more than 1 value to unpack 

Este código vino de aquí . El código es, con mucho, el más preciso que he usado hasta ahora. El problema es que no hay un model.fit() definido en model.fit() parte del código. También lleva una eternidad para adaptarse. La operación de fit() ocurre en los results = cross_val_score(...) y no hay parámetros para lanzar una callback allí.

¿Cómo voy a hacer esto? Además, ¿cómo ejecuto el modelo entrenado en un conjunto de prueba?

Necesito poder guardar el modelo entrenado para su uso posterior …

Leyendo desde aquí , que es el código fuente de KerasClassifier, puede pasarle los argumentos de ajuste y deberían usarse. No tengo su conjunto de datos, así que no puedo probarlo, pero puede decirme si esto funciona y si no, intentaré adaptar la solución. Cambia esta línea:

 estimators.append(('mlp', KerasClassifier(build_fn=create_baseline, nb_epoch=300, batch_size=16, verbose=0, callbacks=[...your_callbacks...]))) 

Una pequeña explicación de lo que está sucediendo: KerasClassifier está tomando todos los argumentos posibles para fit , predict , score y usarlos en consecuencia cuando se llama a cada método. Hicieron una función que filtra los argumentos que deben ir a cada una de las funciones anteriores que se pueden llamar en la tubería. Supongo que hay varias fit y predict dentro del paso StratifiedKFold para entrenar en diferentes splits cada vez.

La razón por la que se tarda una eternidad en adaptarse y en que se ajusta 10 veces es porque una adaptación es hacer 300 épocas, como pediste. Así que KFold está repitiendo este paso sobre los diferentes pliegues:

  • las llamadas fit con todos los parámetros dados a KerasClassifier (300 épocas y tamaño de lote = 16). Se entrena en 9/10 de sus datos y se usa 1/10 como validación.

EDITAR:

Ok, así que me tomé el tiempo para descargar el conjunto de datos y probar su código … En primer lugar, necesita corregir “algunas” cosas en su red:

  • su entrada tiene un 60 características. Usted lo muestra claramente en su preparación de datos:

     X = dataset[:,:60].astype(float) 

    Entonces, ¿por qué tendrías esto?

     model.add(Dropout(0.2, input_shape=(33,))) 

    por favor cambie a

     model.add(Dropout(0.2, input_shape=(60,))) 
  • Sobre tus objectives / tags. Cambió el objective del código original ( binary_crossentropy ) a categorical_crossentropy . Pero no cambiaste tu matriz Y. Entonces, haz esto en tu preparación de datos:

     from keras.utils.np_utils import to_categorical encoded_Y = to_categorical(encoder.transform(Y)) 

    o cambia tu objective de nuevo a binary_crossentropy .

  • Ahora el tamaño de salida de la red: ¿122 en la última capa densa? su conjunto de datos obviamente tiene 2 categorías, ¿por qué intenta generar 122 clases? no coincidirá con el objective. Por favor, vuelva a cambiar su última capa a:

     model.add(Dense(2, init='normal', activation='softmax')) 

    si elige utilizar categorical_crossentropy , o

     model.add(Dense(1, init='normal', activation='sigmoid')) 

    Si vuelves a binary_crossentropy .

Así que ahora que tu red se comstack, podría comenzar a solucionar problemas.

Aquí está tu solución

Así que ahora podría obtener el mensaje de error real. Resulta que cuando alimenta fit_params=whatever en la función cross_val_score() , está suministrando esos parámetros a una tubería. Para saber a qué parte de la canalización desea enviar esos parámetros, debe especificarlos así:

 fit_params={'mlp__callbacks':calls} 

Su error decía que el proceso no pudo desempaquetar 'callbacks'.split('__', 1) en 2 valores. En realidad estaba buscando el nombre del paso del oleoducto para aplicar esto.

Debería estar funcionando ahora 🙂

 results = cross_val_score(pipeline, X, encoded_Y, cv=kfold, fit_params={'mlp__callbacks':calls}) 

PERO, debe ser consciente de lo que está sucediendo aquí … la validación cruzada en realidad llama a la función create_baseline() para recrear el modelo desde cero 10 veces y lo entrena 10 veces en diferentes partes del conjunto de datos. Así que no hace épocas como decías, hace 300 épocas 10 veces. Lo que también está sucediendo como consecuencia de usar esta herramienta: dado que los modelos siempre son diferentes, significa que el método fit() se aplica 10 veces en diferentes modelos, por lo tanto, las devoluciones de llamada también se aplican 10 veces diferentes y los archivos guardados por ModelCheckpoint() se anula y te encuentras solo con el mejor modelo de la última carrera.

Esto es intrínseco a las herramientas que usa, no veo ninguna manera de evitar esto. Esto se debe al uso de diferentes herramientas generales que no se pensaron especialmente para usarse junto con todas las configuraciones posibles.

Tratar:

 estimators.append(('mlp', KerasClassifier(build_fn=create_model2, nb_epoch=300, batch_size=16, verbose=0, callbacks=[list_of_callbacks]))) 

donde list_of_callbacks es una lista de devoluciones de llamada que desea aplicar. Podrías encontrar detalles aquí . Se menciona allí que los parámetros suministrados a KerasClassifier podrían ser parámetros de ajuste legales.

También vale la pena mencionar que si está utilizando varias ejecuciones con GPU, puede haber un problema debido a varias pérdidas de memoria reportadas, especialmente cuando está utilizando theano. También me di cuenta de que ejecutar múltiples ajustes en consecuencia puede mostrar resultados que parecen no ser independientes cuando se usa la API sklearn .

Editar:

Prueba también:

 results = cross_val_score(pipeline, X, encoded_Y, cv=kfold, fit_params = {'mlp__callbacks': calls}) 

En lugar de poner la lista de devoluciones de llamada en una instancia de contenedor.

Esto es lo que he hecho.

 results = cross_val_score(estimator, X, Y, cv=kfold, fit_params = {'callbacks': [checkpointer,plateau]}) 

y ha trabajado hasta ahora