web-dev-qa-db-ja.com

Kerasの不整合な予測時間

私のケラスモデルの予測時間の見積もりを取得しようとしたところ、奇妙なことがわかりました。通常はかなり高速であることは別にして、モデルは予測を出すのにかなり長い時間が必要です。それだけでなく、それらの時間はモデルの実行時間が長くなるほど増加します。エラーを再現するための最小限の実例を追加しました。

_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))
_

時間はサンプルに依存しません(ランダムに選択されます)。テストが繰り返される場合、予測に時間がかかるforループのインデックスは(ほぼ)再び同じになります。

enter image description here

私が使用しています:

_tensorflow 2.0.0
python 3.7.4
_

私のアプリケーションでは、特定の時間での実行を保証する必要があります。ただし、これはその動作を考えると不可能です。何が問題になっていますか? Kerasのバグですか、それともtensorflowバックエンドのバグですか?

編集:_predict_on_batch_は同じ動作を示しますが、よりまばらです: enter image description here

y_pred = model(sample, training=False).numpy()もいくつかの大きな外れ値を示していますが、それらは増加していません。 enter image description here

編集2:私は最新のtensorflow 1バージョン(1.15)にダウングレードしました。問題が存在しなくなっただけでなく、「通常の」予測時間も大幅に改善されました。 2つのスパイクに問題があるとは思われません。テストを繰り返したときに表示されなかったため(少なくとも同じインデックスではなく、線形に増加している)、最初のプロットほど大きくはありません。 enter image description here

したがって、これは、@ OverLordGoldDragonが言及するように、他の状況でも同様の動作を示すtensorflow 2.0に固有の問題であると結論付けることができます。

18
ga97dil

実行時間の不一致については説明できませんが、モデルをTensorFlow Liteに変換して、単一のデータレコードまたは小さなバッチでの予測を高速化することをお勧めします。

このモデルでベンチマークを実行しました。

_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')
])
_

単一レコードの予測時間は次のとおりです。

  1. model.predict(input):18ミリ秒
  2. model(input):1.3ms
  3. TensorFlow Liteに変換されたモデル:43us

モデルを変換する時間は2秒でした。

以下のクラスは、モデルを変換して使用する方法を示し、Kerasモデルのようなpredictメソッドを提供します。単一の1-D入力と単一の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]
_

完全なベンチマークコードとプロットは、次の場所にあります。 https://medium.com/@micwurm/using-tensorflow-lite-to-speed-up-predictions-a3954886eb98

2
Michael