Comment sauvegarder le modèle Scikit-Learn-Keras dans un fichier de persistance (pickle / hd5/json / yaml)
j'ai le code suivant, en utilisant 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()
Comme indiqué dans le code là, il échoue à cette ligne:
pickle.dump(model_tt, open(filename, 'wb'))
Avec cette erreur:
pickle.PicklingError: Can't pickle <function create_model at 0x101c09320>: it's not found as __main__.create_model
comment le contourner?
3 réponses
Edit 1: réponse originale à propos de la sauvegarde du modèle
Avec 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')
Edit 2 : code exemple avec iris dataset
# 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])
veuillez noter que J'ai utilisé des Keras seulement, pas l'emballage. Ça ne fait qu'ajouter de la complexité à quelque chose de simple. Le code est volontaire, pas pris en compte, donc vous pouvez avoir une vue d'ensemble.
aussi, vous avez dit que vous voulez sortir 1 ou 0. Il n'est pas possible dans cet ensemble de données parce que vous avez 3 sortie dims et classes (Iris-setosa, Iris-versicolor, Iris-virginica). Si vous aviez seulement 2 classes, alors votre dim de sortie et les classes seraient 0 ou 1 en utilisant la fonction de sortie sigmoid.
juste ajouter à la réponse de gaarv-si vous n'avez pas besoin de la séparation entre la structure du modèle (model.to_json()
) et le poids (model.save_weights()
), vous pouvez utiliser une des méthodes suivantes:
- Utiliser
keras.models.save_model
et " keras.modèle.load_model` que de stocker le tout dans un hdf5 fichier. - utilisez pickle pour sérialiser L'objet Model (ou toute classe qui contient des références à celui-ci) dans file/network/whatever..
Malheureusement, Keras ne supporte pas pickle. par défaut. Vous pouvez utiliser ma solution qui ajoute Cette caractéristique manquante. Le code de travail est ici: http://zachmoshe.com/2017/04/03/pickling-keras-models.html
une autre excellente alternative est d'utiliser rappels si vous fit
votre modèle. Plus précisément l' ModelCheckpoint
rappel, comme ceci:
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)
Cela permettra d'économiser votre formation chaque époquemyModel.h5
fichier. Cela offre de grands avantages, car vous êtes en mesure d'arrêter votre formation lorsque vous le souhaitez (comme lorsque vous voyez qu'il a commencé à s'adapter), et encore conserver la formation précédente.
notez que ceci sauve à la fois les structure et poids dans le même hdf5
fichier (comme montré par Zach), de sorte que vous pouvez ensuite charger votre modèle en utilisant keras.models.load_model
.
Si vous souhaitez sauvegarder uniquement votre poids séparément, vous pouvez alors utiliser le save_weights_only=True
argument lors de l'instanciation de votre ModelCheckpoint
, vous permettant de charger votre modèle comme expliqué par Gaarv. L'extraction de l' docs:
save_weights_ only: si vrai, alors seuls les poids du modèle seront sauvegardés (modèle.save_weights (filepath)), sinon le modèle complet est sauvegardé (model.enregistrer(filepath)).