web-dev-qa-db-fra.com

Temps de prédiction incohérent Keras

J'ai essayé d'obtenir une estimation du temps de prédiction de mon modèle de keras et j'ai réalisé quelque chose d'étrange. En plus d'être assez rapide normalement, de temps en temps, le modèle a besoin de beaucoup de temps pour faire une prédiction. Et non seulement cela, ces temps augmentent également avec la durée du modèle. J'ai ajouté un exemple de travail minimal pour reproduire l'erreur.

import time
import numpy as np
from sklearn.datasets import make_classification
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Flatten

# Make a dummy classification problem
X, y = make_classification()

# Make a dummy model
model = Sequential()
model.add(Dense(10, activation='relu',name='input',input_shape=(X.shape[1],)))
model.add(Dense(2, activation='softmax',name='predictions'))
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])

model.fit(X, y, verbose=0, batch_size=20, epochs=100)

for i in range(1000):
    # Pick a random sample
    sample = np.expand_dims(X[np.random.randint(99), :], axis=0)
    # Record the prediction time 10x and then take the average
    start = time.time()
    for j in range(10):
        y_pred = model.predict_classes(sample)
    end = time.time()
    print('%d, %0.7f' % (i, (end-start)/10))

Le temps ne dépend pas de l'échantillon (il est choisi au hasard). Si le test est répété, les indices de la boucle for où la prédiction prend plus de temps seront à nouveau (presque) les mêmes.

enter image description here

J'utilise:

tensorflow 2.0.0
python 3.7.4

Pour ma candidature, je dois garantir l'exécution dans un certain temps. Ceci est cependant impossible compte tenu de ce comportement. Qu'est-ce qui ne va pas? Est-ce un bogue dans Keras ou un bogue dans le backend tensorflow?

EDIT: predict_on_batch Montre le même comportement, cependant, plus clairsemé: enter image description here

y_pred = model(sample, training=False).numpy() montre également des valeurs aberrantes importantes, mais elles n'augmentent pas. enter image description here

EDIT 2: Je suis passé à la dernière version de tensorflow 1 (1.15). Non seulement le problème n'existe plus, mais le temps de prédiction "normal" s'est également considérablement amélioré! Je ne vois pas les deux pics comme problématiques, car ils ne sont pas apparus lorsque j'ai répété le test (du moins pas aux mêmes indices et en augmentation linéaire) et sont en pourcentage pas aussi grands que dans le premier graphique. enter image description here

Nous pouvons donc conclure que cela semble être un problème inhérent à tensorflow 2.0, qui montre un comportement similaire dans d'autres situations comme le mentionne @OverLordGoldDragon.

18
ga97dil

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 fait 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,3 ms
  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 une méthode predict comme le modèle 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

2
Michael