Je déploie un modèle keras et envoie les données de test au modèle via une API de flacon. J'ai deux fichiers:
Tout d'abord: Mon application Flask:
# Let's startup the Flask application
app = Flask(__name__)
# Model reload from jSON:
print('Load model...')
json_file = open('models/model_temp.json', 'r')
loaded_model_json = json_file.read()
json_file.close()
keras_model_loaded = model_from_json(loaded_model_json)
print('Model loaded...')
# Weights reloaded from .h5 inside the model
print('Load weights...')
keras_model_loaded.load_weights("models/Model_temp.h5")
print('Weights loaded...')
# URL that we'll use to make predictions using get and post
@app.route('/predict',methods=['GET','POST'])
def predict():
data = request.get_json(force=True)
predict_request = [data["month"],data["day"],data["hour"]]
predict_request = np.array(predict_request)
predict_request = predict_request.reshape(1,-1)
y_hat = keras_model_loaded.predict(predict_request, batch_size=1, verbose=1)
return jsonify({'prediction': str(y_hat)})
if __== "__main__":
# Choose the port
port = int(os.environ.get('PORT', 9000))
# Run locally
app.run(Host='127.0.0.1', port=port)
Deuxièmement: le fichier que j'utilise pour envoyer les données JSON envoyées au point de terminaison api:
response = rq.get('api url has been removed')
data=response.json()
currentDT = datetime.datetime.now()
Month = currentDT.month
Day = currentDT.day
Hour = currentDT.hour
url= "http://127.0.0.1:9000/predict"
post_data = json.dumps({'month': month, 'day': day, 'hour': hour,})
r = rq.post(url,post_data)
Je reçois cette réponse de Flask concernant Tensorflow:
ValueError: Tenseur Tenseur ("dense_6/BiasAdd: 0", shape = (?, 1), dtype = float32) n'est pas un élément de ce graphique.
Mon modèle keras est un modèle simple à 6 couches denses et s'entraîne sans erreur.
Des idées?
Flask utilise plusieurs threads. Le problème que vous rencontrez est dû au fait que le modèle tensorflow n'est pas chargé et utilisé dans le même thread. Une solution de contournement consiste à forcer tensorflow à utiliser le graphe par défaut global.
Ajoutez ceci après avoir chargé votre modèle
global graph
graph = tf.get_default_graph()
Et à l'intérieur de votre prédiction
with graph.as_default():
y_hat = keras_model_loaded.predict(predict_request, batch_size=1, verbose=1)
Il s'avère que cette manière n'a pas besoin d'un appel clear_session et est en même temps conviviale pour la configuration, en utilisant l'objet graphique de la session configurée session = tf.Session(config=_config); self.graph = session.graph
et la prédiction par le graphique créé en tant que valeur par défaut with self.graph.as_default():
offre une approche propre
from keras.backend.tensorflow_backend import set_session
...
def __init__(self):
config = self.keras_resource()
self.init_model(config)
def init_model(self, _config, *args):
session = tf.Session(config=_config)
self.graph = session.graph
#set configured session
set_session(session)
self.model = load_model(file_path)
def keras_resource(self):
config = tf.ConfigProto()
config.gpu_options.allow_growth = True
return config
def predict_target(self, to_predict):
with self.graph.as_default():
predict = self.model.predict(to_predict)
return predict
Juste après le chargement du modèle, ajoutez model._make_predict_function()
`
# Model reload from jSON:
print('Load model...')
json_file = open('models/model_temp.json', 'r')
loaded_model_json = json_file.read()
json_file.close()
keras_model_loaded = model_from_json(loaded_model_json)
print('Model loaded...')
# Weights reloaded from .h5 inside the model
print('Load weights...')
keras_model_loaded.load_weights("models/Model_temp.h5")
print('Weights loaded...')
keras_model_loaded._make_predict_function()
C'est tellement plus simple d'envelopper votre modèle keras dans une classe et cette classe peut garder une trace de son propre graphique et de sa session. Cela évite les problèmes pouvant être causés par plusieurs threads/processus/modèles, ce qui est très certainement la cause de votre problème. Tandis que d’autres solutions fonctionneront, c’est de loin la solution la plus générale, la plus évolutive et la plus complète. Utilisez celui-ci:
import os
from keras.models import model_from_json
from keras import backend as K
import tensorflow as tf
import logging
logger = logging.getLogger('root')
class NeuralNetwork:
def __init__(self):
self.session = tf.Session()
self.graph = tf.get_default_graph()
# the folder in which the model and weights are stored
self.model_folder = os.path.join(os.path.abspath("src"), "static")
self.model = None
# for some reason in a flask app the graph/session needs to be used in the init else it hangs on other threads
with self.graph.as_default():
with self.session.as_default():
logging.info("neural network initialised")
def load(self, file_name=None):
"""
:param file_name: [model_file_name, weights_file_name]
:return:
"""
with self.graph.as_default():
with self.session.as_default():
try:
model_name = file_name[0]
weights_name = file_name[1]
if model_name is not None:
# load the model
json_file_path = os.path.join(self.model_folder, model_name)
json_file = open(json_file_path, 'r')
loaded_model_json = json_file.read()
json_file.close()
self.model = model_from_json(loaded_model_json)
if weights_name is not None:
# load the weights
weights_path = os.path.join(self.model_folder, weights_name)
self.model.load_weights(weights_path)
logging.info("Neural Network loaded: ")
logging.info('\t' + "Neural Network model: " + model_name)
logging.info('\t' + "Neural Network weights: " + weights_name)
return True
except Exception as e:
logging.exception(e)
return False
def predict(self, x):
with self.graph.as_default():
with self.session.as_default():
y = self.model.predict(x)
return y