Python >> Tutoriel Python >  >> Python Tag >> Keras

Temps de prédiction incohérent de Keras

TF2 présente généralement une gestion de la mémoire médiocre et semblable à un bogue dans plusieurs cas que j'ai rencontrés - brève description ici et ici. Avec la prédiction en particulier, la méthode d'alimentation la plus performante est via model(x) directement - voir ici, et ses discussions liées.

En bref :model(x) agit via son son __call__ méthode (dont elle hérite de base_layer.Layer ), alors que predict() , predict_classes() , etc. impliquent une fonction de boucle dédiée via _select_training_loop(); chacun utilise différentes méthodes de prétraitement et de post-traitement des données adaptées à différents cas d'utilisation, et model(x) en 2.1 a été conçu spécifiquement pour offrir les performances les plus rapides pour les petits modèles/petits lots (et peut-être toutes les tailles) (et toujours les plus rapides en 2.0).

Citation d'un développeur TensorFlow à partir de discussions liées :

Vous pouvez prédire la sortie en utilisant l'appel du modèle, et non la prédiction du modèle, c'est-à-dire en appelant model(x) rendrait cela beaucoup plus rapide car il n'y a pas de partie "conversion en jeu de données", et il appelle également directement un tf.function en cache .

Remarque :cela devrait être moins un problème dans 2.1, et surtout 2.2 - mais testez quand même chaque méthode. De plus, je me rends compte que cela ne répond pas directement à votre question sur les pointes de temps ; Je soupçonne que cela est lié aux mécanismes de mise en cache Eager, mais le moyen le plus sûr de le déterminer est via TF Profiler , qui est cassé en 2.1.

Mettre à jour :concernant l'augmentation pointes, étranglement possible du GPU ; vous avez fait ~ 1000 iters, essayez plutôt 10 000 - éventuellement, l'augmentation devrait s'arrêter. Comme vous l'avez noté dans vos commentaires, cela ne se produit pas avec model(x); est logique car une étape GPU de moins est impliquée ("conversion en jeu de données").

Mise à jour2 :vous pourriez embêter les développeurs ici à ce sujet si vous rencontrez ce problème ; c'est surtout moi qui chante là


Bien que je ne puisse pas expliquer les incohérences dans le temps d'exécution, je peux vous recommander d'essayer de convertir votre modèle en TensorFlow Lite pour accélérer les prédictions sur des enregistrements de données uniques ou de petits lots.

J'ai exécuté un benchmark sur ce modèle :

model = tf.keras.models.Sequential([
    tf.keras.layers.Dense(384, activation='elu', input_shape=(256,)),
    tf.keras.layers.Dense(384, activation='elu'),
    tf.keras.layers.Dense(256, activation='elu'),
    tf.keras.layers.Dense(128, activation='elu'),
    tf.keras.layers.Dense(32, activation='tanh')
])

Les temps de prédiction pour les enregistrements uniques étaient :

  1. model.predict(input) :18ms
  2. model(input) :1.3ms
  3. Modèle converti en TensorFlow Lite :43us

Le temps de conversion du modèle était de 2 secondes.

La classe ci-dessous montre comment convertir et utiliser le modèle et fournit un predict méthode comme le modèle de Keras. Notez qu'il devrait être modifié pour être utilisé avec des modèles qui n'ont pas qu'une seule entrée 1-D et une seule sortie 1-D.

class LiteModel:

    @classmethod
    def from_file(cls, model_path):
        return LiteModel(tf.lite.Interpreter(model_path=model_path))

    @classmethod
    def from_keras_model(cls, kmodel):
        converter = tf.lite.TFLiteConverter.from_keras_model(kmodel)
        tflite_model = converter.convert()
        return LiteModel(tf.lite.Interpreter(model_content=tflite_model))

    def __init__(self, interpreter):
        self.interpreter = interpreter
        self.interpreter.allocate_tensors()
        input_det = self.interpreter.get_input_details()[0]
        output_det = self.interpreter.get_output_details()[0]
        self.input_index = input_det["index"]
        self.output_index = output_det["index"]
        self.input_shape = input_det["shape"]
        self.output_shape = output_det["shape"]
        self.input_dtype = input_det["dtype"]
        self.output_dtype = output_det["dtype"]

    def predict(self, inp):
        inp = inp.astype(self.input_dtype)
        count = inp.shape[0]
        out = np.zeros((count, self.output_shape[1]), dtype=self.output_dtype)
        for i in range(count):
            self.interpreter.set_tensor(self.input_index, inp[i:i+1])
            self.interpreter.invoke()
            out[i] = self.interpreter.get_tensor(self.output_index)[0]
        return out

    def predict_single(self, inp):
        """ Like predict(), but only for a single record. The input data can be a Python list. """
        inp = np.array([inp], dtype=self.input_dtype)
        self.interpreter.set_tensor(self.input_index, inp)
        self.interpreter.invoke()
        out = self.interpreter.get_tensor(self.output_index)
        return out[0]

Le code de référence complet et un graphique peuvent être trouvés ici :https://medium.com/@micwurm/using-tensorflow-lite-to-speed-up-predictions-a3954886eb98