python - gridsearchcv - kerasclassifier
Cómo guardar el modelo Scikit-Learn-Keras en un archivo de persistencia(pickle/hd5/json/yaml) (4)
Tengo el siguiente código, usando Keras Scikit-Learn Wrapper :
from keras.models import Sequential
from sklearn import datasets
from keras.layers import Dense
from sklearn.model_selection import train_test_split
from keras.wrappers.scikit_learn import KerasClassifier
from sklearn.model_selection import StratifiedKFold
from sklearn.model_selection import cross_val_score
from sklearn import preprocessing
import pickle
import numpy as np
import json
def classifier(X, y):
"""
Description of classifier
"""
NOF_ROW, NOF_COL = X.shape
def create_model():
# create model
model = Sequential()
model.add(Dense(12, input_dim=NOF_COL, init=''uniform'', activation=''relu''))
model.add(Dense(6, init=''uniform'', activation=''relu''))
model.add(Dense(1, init=''uniform'', activation=''sigmoid''))
# Compile model
model.compile(loss=''binary_crossentropy'', optimizer=''adam'', metrics=[''accuracy''])
return model
# evaluate using 10-fold cross validation
seed = 7
np.random.seed(seed)
model = KerasClassifier(build_fn=create_model, nb_epoch=150, batch_size=10, verbose=0)
return model
def main():
"""
Description of main
"""
iris = datasets.load_iris()
X, y = iris.data, iris.target
X = preprocessing.scale(X)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.4, random_state=0)
model_tt = classifier(X_train, y_train)
model_tt.fit(X_train,y_train)
#--------------------------------------------------
# This fail
#--------------------------------------------------
filename = ''finalized_model.sav''
pickle.dump(model_tt, open(filename, ''wb''))
# load the model from disk
loaded_model = pickle.load(open(filename, ''rb''))
result = loaded_model.score(X_test, Y_test)
print(result)
#--------------------------------------------------
# This also fail
#--------------------------------------------------
# from keras.models import load_model
# model_tt.save(''test_model.h5'')
#--------------------------------------------------
# This works OK
#--------------------------------------------------
# print model_tt.score(X_test, y_test)
# print model_tt.predict_proba(X_test)
# print model_tt.predict(X_test)
# Output of predict_proba
# 2nd column is the probability that the prediction is 1
# this value is used as final score, which can be used
# with other method as comparison
# [ [ 0.25311464 0.74688536]
# [ 0.84401423 0.15598579]
# [ 0.96047372 0.03952631]
# ...,
# [ 0.25518912 0.74481088]
# [ 0.91467732 0.08532269]
# [ 0.25473493 0.74526507]]
# Output of predict
# [[1]
# [0]
# [0]
# ...,
# [1]
# [0]
# [1]]
if __name__ == ''__main__'':
main()
Como se indica en el código, falla en esta línea:
pickle.dump(model_tt, open(filename, ''wb''))
Con este error:
pickle.PicklingError: Can''t pickle <function create_model at 0x101c09320>: it''s not found as __main__.create_model
¿Cómo puedo evitarlo?
La respuesta aceptada es demasiado complicada. Puede guardar y restaurar completamente todos los aspectos de su modelo en un archivo .h5
. Directamente de las preguntas frecuentes de Keras :
Puede usar model.save (filepath) para guardar un modelo Keras en un solo archivo HDF5 que contendrá:
- La arquitectura del modelo, permitiendo recrear el modelo.
- los pesos del modelo
- La configuración de entrenamiento (pérdida, optimizador).
- El estado del optimizador, que permite reanudar el entrenamiento exactamente donde lo dejó.
Luego puede usar keras.models.load_model (filepath) para volver a establecer su modelo. load_model también se encargará de compilar el modelo utilizando la configuración de entrenamiento guardada (a menos que el modelo nunca se compiló en primer lugar).
Y el código correspondiente:
from keras.models import load_model
model.save(''my_model.h5'') # creates a HDF5 file ''my_model.h5''
del model # deletes the existing model
# returns a compiled model
# identical to the previous one
model = load_model(''my_model.h5'')
Otra excelente alternativa es utilizar callbacks cuando se fit
su modelo. Específicamente la ModelCheckpoint
llamada ModelCheckpoint
, como esta:
from keras.callbacks import ModelCheckpoint
#Create instance of ModelCheckpoint
chk = ModelCheckpoint("myModel.h5", monitor=''val_loss'', save_best_only=False)
#add that callback to the list of callbacks to pass
callbacks_list = [chk]
#create your model
model_tt = KerasClassifier(build_fn=create_model, nb_epoch=150, batch_size=10)
#fit your model with your data. Pass the callback(s) here
model_tt.fit(X_train,y_train, callbacks=callbacks_list)
Esto guardará su entrenamiento cada época en el archivo myModel.h5
. Esto proporciona grandes beneficios, ya que puede detener su entrenamiento cuando lo desee (como cuando ve que ha comenzado a adaptarse en exceso), y aún retener el entrenamiento anterior.
Tenga en cuenta que esto guarda la estructura y los pesos en el mismo archivo hdf5
(como lo mostró Zach), por lo que puede cargar su modelo utilizando keras.models.load_model
.
Si desea guardar solo sus pesos por separado, puede usar el argumento save_weights_only=True
al crear una instancia de su ModelCheckpoint
, lo que le permite cargar su modelo como lo explica Gaarv. Extraer de la callbacks :
save_weights_only: si es Verdadero, solo se guardarán los pesos del modelo (model.save_weights (filepath)), de lo contrario se guardará el modelo completo (model.save (filepath)).
Solo agregando a la respuesta de gaarv: si no necesita la separación entre la estructura del modelo ( model.to_json()
) y los pesos ( model.save_weights()
), puede usar uno de los siguientes:
- Use los
keras.models.save_model
y ''keras.models.load_model` que almacenan todo junto en un archivo hdf5. - Use pickle para serializar el objeto Modelo (o cualquier clase que contenga referencias a él) en el archivo / red / lo que sea ..
Desafortunadamente, Keras no admite pickles por defecto. Puedes usar mi solución parcheada que agrega esta característica faltante. El código de trabajo está aquí: http://zachmoshe.com/2017/04/03/pickling-keras-models.html
Edición 1 : Respuesta original sobre guardar modelo.
Con HDF5:
# saving model
json_model = model_tt.model.to_json()
open(''model_architecture.json'', ''w'').write(json_model)
# saving weights
model_tt.model.save_weights(''model_weights.h5'', overwrite=True)
# loading model
from keras.models import model_from_json
model = model_from_json(open(''model_architecture.json'').read())
model.load_weights(''model_weights.h5'')
# dont forget to compile your model
model.compile(loss=''binary_crossentropy'', optimizer=''adam'')
Edición 2 : ejemplo de código completo con dataset de iris
# Train model and make predictions
import numpy
import pandas
from keras.models import Sequential, model_from_json
from keras.layers import Dense
from keras.utils import np_utils
from sklearn import datasets
from sklearn import preprocessing
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
# fix random seed for reproducibility
seed = 7
numpy.random.seed(seed)
# load dataset
iris = datasets.load_iris()
X, Y, labels = iris.data, iris.target, iris.target_names
X = preprocessing.scale(X)
# encode class values as integers
encoder = LabelEncoder()
encoder.fit(Y)
encoded_Y = encoder.transform(Y)
# convert integers to dummy variables (i.e. one hot encoded)
y = np_utils.to_categorical(encoded_Y)
def build_model():
# create model
model = Sequential()
model.add(Dense(4, input_dim=4, init=''normal'', activation=''relu''))
model.add(Dense(3, init=''normal'', activation=''sigmoid''))
model.compile(loss=''categorical_crossentropy'', optimizer=''adam'', metrics=[''accuracy''])
return model
def save_model(model):
# saving model
json_model = model.to_json()
open(''model_architecture.json'', ''w'').write(json_model)
# saving weights
model.save_weights(''model_weights.h5'', overwrite=True)
def load_model():
# loading model
model = model_from_json(open(''model_architecture.json'').read())
model.load_weights(''model_weights.h5'')
model.compile(loss=''categorical_crossentropy'', optimizer=''adam'')
return model
X_train, X_test, Y_train, Y_test = train_test_split(X, y, test_size=0.3, random_state=seed)
# build
model = build_model()
model.fit(X_train, Y_train, nb_epoch=200, batch_size=5, verbose=0)
# save
save_model(model)
# load
model = load_model()
# predictions
predictions = model.predict_classes(X_test, verbose=0)
print(predictions)
# reverse encoding
for pred in predictions:
print(labels[pred])
Tenga en cuenta que solo usé Keras, no el envoltorio. Solo agrega algo de complejidad en algo simple. Además, el código es voluntario, no factorizado, por lo que puede tener la imagen completa.
Además, dijo que desea generar 1 o 0. No es posible en este conjunto de datos porque tiene 3 dims y clases de salida (Iris-setosa, Iris-versicolor, Iris-virginica). Si solo tuviera 2 clases, su salida dim y las clases serían 0 o 1 usando la función de salida sigmoidea.