Kerasの予測時間の矛盾


17

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

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ループのインデックスは再び(ほぼ)同じになります。

ここに画像の説明を入力してください

私が使用しています:

tensorflow 2.0.0
python 3.7.4

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

編集: predict_on_batch同じ動作を示しますが、よりまばらです: ここに画像の説明を入力してください

y_pred = model(sample, training=False).numpy() はいくつかの重い外れ値も示していますが、増加していません。 ここに画像の説明を入力してください

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

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


その振る舞いは予測可能に聞こえます...増加は一種の線形です。この動作を時間計算に含めると、うまくいきませんか?---何が起こっているのかはわかりませんが、predict_on_batch代わりに試してみるとどうなりますか?
DanielMöller

何が起こるか別の試み、y_pred = model(sample).numpy()としてy_pred = model(sample, training=False).numpy()
DanielMöller

調査結果を追加しました。numpyバージョンは動作を示していないようです。
ga97dil

しかしpredict_classes、それでも最速です...と思われます。ちょうどpredictどうですか?
DanielMöller

1
これはある種のメモリクリーニングかもしれないと思います...
DanielMöller

回答:


10

TF2は一般的に、私が遭遇したいくつかのインスタンスで貧弱でバグのようなメモリ管理を示します- ここここで簡単な説明。特に予測の場合、最も効果的な給餌方法はmodel(x)直接経由です。こことそのリンクされた説明を参照してください。

一言で言えば:model(x)そのその介して作用する__call__(それから継承する方法base_layer.Layerに対し、) predict()predict_classes()等を介して、専用のループ機能を含みます_select_training_loop()。それぞれが、さまざまなユースケースに適したさまざまなデータの前処理および後処理方法を利用します。2.1では、model(x)特に最速のスモールモデル/スモールバッチ(そしておそらく任意のサイズ)のパフォーマンス(さらに2.0では最速)を実現するように設計されました。

引用 リンクされたディスカッションからTensorFlow開発者を

モデルの予測ではなく、モデルの呼び出しを使用して出力を予測できます。つまり、model(x)「データセットへの変換」部分がないため、呼び出しはこれをはるかに高速化し、キャッシュされたキャッシュを直接呼び出します。tf.functionます。

:これは2.1、特に2.2ではそれほど問題にはなりませんが、いずれにしても各メソッドをテストしてください。また、これは時間の急上昇に関するあなたの質問に直接答えるものではないことも理解しています。私はそれは熱心なキャッシュ機構に近い関連疑うが、決定する最も確実な方法は、経由でTF Profilerされている、壊れました 2.1に。


更新増加についてスパイクの、GPUスロットリングの可能性 ; あなたは1000回のイテラーを実行しましたが、代わりに10,000回試してください-最終的に、増加は止まるはずです。あなたのコメントで述べたように、これはで発生しませんmodel(x)。GPUステップが1つ少ないため(「データセットへの変換」)、理にかなっています。

アップデート2:あなたはバグを開発者ができ、ここで、あなたがこの問題に直面した場合、それについて。主に私がそこで歌っています


これは、1つの方法が遅い理由に対する良い答えですが、複数の実行で実行時間が増加することを説明していません。
LLSv2.0

1
@ LLSv2.0私自身は完全には分かりませんが、更新された回答-この問題を自分
開発者

1
@ ga97dilええ、それでは説明ができません-長い応答時間に直面するかもしれませんが、Githubで質問してみてください。
OverLordGoldDragon

1
@ ga97dil確かに、TF1はTF2 よりはるかに高速です。ただし、TF 2.1は、ベンチマークでのトレーニングが最速(予測を行わなかったため)なので、小さなモデルやデータセットを試す価値があります。さらに重要なことに、TF2を使用する場合は、グラフとEagerで再現性をテストすることを強くお勧めします。TF 2.1では結果が極端に異なる場合があります。
OverLordGoldDragon

1
私はあなたの投稿をGitスレッドに追加し、私のTF2とTF1の投稿を追加しました。問題がTF 1でなくなることを知らせてくれてありがとう
OverLordGoldDragon

2

実行時間の不一致については説明できませんが、モデルを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):18ms
  2. model(input):1.3ms
  3. TensorFlow Liteに変換されたモデル:43us

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

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


かっこいい、これまで試したことはありませんが、試してみる価値はあるでしょう。ヒントをありがとう!
ga97dil
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.