Keras tutarsız tahmin süresi


17

Keras modelimin tahmin süresini tahmin etmeye çalıştım ve garip bir şey fark ettim. Normalde oldukça hızlı olmanın yanı sıra, her seferinde modelin bir tahmin bulmak için oldukça uzun sürmesi gerekir. Ve sadece bu değil, o zamanlar modelin daha uzun süre çalışmasını da artırır. Hatayı yeniden oluşturmak için minimal bir çalışma örneği ekledim.

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

Zaman numuneye bağlı değildir (rastgele seçilmektedir). Test tekrarlanırsa, for döngüsünde tahminin daha uzun sürdüğü indeksler (neredeyse) tekrar aynı olacaktır.

resim açıklamasını buraya girin

Kullanıyorum:

tensorflow 2.0.0
python 3.7.4

Başvurum için, belirli bir zamanda uygulamayı garanti etmem gerekiyor. Ancak bu davranış göz önüne alındığında bu imkansızdır. Neler yanlış gidiyor? Keras'ta bir hata mı yoksa tensorflow arka ucunda bir hata mı?

EDIT: predict_on_batchaynı davranışı gösterir, ancak daha seyrek: resim açıklamasını buraya girin

y_pred = model(sample, training=False).numpy() bazı ağır aykırı değerleri de gösterir, ancak artmazlar. resim açıklamasını buraya girin

EDIT 2: En son tensorflow 1 sürümüne (1.15) geri döndüm. Artık sorun sadece mevcut değil, aynı zamanda "normal" tahmin süresi de önemli ölçüde iyileşti! Testi tekrarladığımda (en azından aynı indekslerde değil ve doğrusal olarak arttığında) ortaya çıkmadıkları ve ilk arsadaki kadar büyük olmadığı için iki ani problemli görmüyorum. resim açıklamasını buraya girin

Bu nedenle, bunun tensorflow 2.0'a özgü bir sorun gibi göründüğü sonucuna varabiliriz;


Bu davranış kestirilebilir geliyor .... artış biraz doğrusal. Bu davranışı zaman hesaplamanıza dahil ederseniz gitmez mi? --- Orada neler olduğunu bilmiyorum .... ama predict_on_batchbunun yerine denerseniz ne olur ?
Daniel Möller

İle ne başka girişim, y_pred = model(sample).numpy()ve birlikte y_pred = model(sample, training=False).numpy()?
Daniel Möller

Bulgularımı ekledim. Numpy sürümleri davranışı göstermiyor gibi görünüyor.
ga97dil

Ama predict_classeshala en hızlı ... öyle görünüyor. Sadece ne olacak predict?
Daniel Möller

1
Bunun bir çeşit bellek temizliği olabileceğini varsayıyorum ....
Daniel Möller

Yanıtlar:


10

TF2 genellikle karşılaştığım birçok durumda zayıf ve hata benzeri bellek yönetimi sergiler - burada ve burada kısa açıklama . Özellikle tahmin ile, en performanslı besleme yöntemi model(x)doğrudan - buraya bakın ve bağlantılı tartışmalar.

Özetle: model(x)onun da üzerinden hareket __call__(bu devralan olan yöntem base_layer.Layerise) predict(), predict_classes()vb ile özel bir devre fonksiyonunu içerir _select_training_loop(); her biri farklı kullanım durumları için uygun olan farklı veri öncesi ve sonrası işleme yöntemlerini kullanır ve model(x)2.1'de özel olarak en hızlı küçük model / küçük parti (ve belki de herhangi bir boyutta) performans (ve yine de 2.0'da en hızlı) performansı elde etmek için tasarlanmıştır.

Bağlantılı tartışmalardan bir TensorFlow geliştiricisinden alıntı yapmak :

Model tahminini değil, model çağrısını kullanarak çıktıyı tahmin edebilirsiniz, yani, model(x)"veri kümesine dönüşüm" bölümü olmadığından çağrı yapmak çok daha hızlı olur ve ayrıca doğrudan önbellek çağırır tf.function.

Not : Bu 2.1 ve özellikle 2.2 daha az bir sorun olmalıdır - ama yine de her yöntemi test. Ayrıca bunun doğrudan ani artışlarla ilgili sorunuza cevap vermediğinin farkındayım; Bunun Hevesli önbelleğe alma mekanizmaları alakalı şüpheli ama belirlemek için en kesin yolu üzerinden gerçekleştirilir TF Profilerolan, kırık 2.1'de.


Güncelleme : artan artışlar, olası GPU azaltma ile ilgili; ~ 1000 yineleme yaptınız, bunun yerine 10.000 deneyin - sonuçta artış durmalıdır. Yorumlarınızda belirttiğiniz gibi, bununla gerçekleşmez model(x); daha az GPU adımı söz konusu olduğunda mantıklıdır ("veri kümesine dönüşüm").

Güncelleme2 : Bu sorunla karşılaşırsanız geliştiricileri burada hatalandırabilirsiniz ; çoğunlukla orada şarkı söylüyorum


Bu, bir yöntemin neden daha yavaş olduğuna iyi bir cevaptır, ancak birden fazla çalıştırmada artan çalışma süresini açıklamaz.
LLSv2.0

1
@ LLSv2.0 Kendimden tam olarak emin değilim, ama güncellenmiş cevap - Bu sorunu burada
OverLordGoldDragon

1
@ ga97dil Evet, o zaman açıklamaların dışındayım - Github'a sormayı deneyin, ancak uzun tepki süreleriyle karşılaşabilirsiniz.
OverLordGoldDragon

1
@ ga97dil Gerçekten, TF1, TF2'den çok daha hızlı olabilir - TF 2.1, küçük modeller ve veri kümeleri için denemeye değer, çünkü karşılaştırmalı değerlendirmelerimdeki eğitimde en hızlı (tahmin yapmadı). Daha da önemlisi, TF2'yi kullanırsanız, Grafikte Eager'a karşı tekrarlanabilirliği test etmenizi şiddetle tavsiye ederim ; TF 2.1'de sonuçlar son derece farklı olabilir .
OverLordGoldDragon

1
Mesajınızı Git iş parçacığına ve TF2 ile TF1 yayınım arasına ekledim . TF 1'de sorunun kaybolduğunu bildirdiğiniz için teşekkür ederiz.
OverLordGoldDragon

2

Yürütme süresindeki tutarsızlıkları açıklayamasam da, tek veri kayıtları veya küçük gruplar hakkındaki tahminleri hızlandırmak için modelinizi TensorFlow Lite'a dönüştürmeyi denemenizi tavsiye edebilirim.

Bu model üzerinde bir kıyaslama yaptım:

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

Tek kayıtlar için tahmin süreleri:

  1. model.predict(input): 18 ms
  2. model(input): 1,3 ms
  3. Model TensorFlow Lite'a dönüştürüldü: 43us

Modeli dönüştürme süresi 2 saniyeydi.

Aşağıdaki sınıf, modelin nasıl dönüştürüleceğini ve kullanılacağını gösterir predictve Keras modeli gibi bir yöntem sağlar . Yalnızca tek bir 1-D girişi ve tek bir 1-D çıkışı olmayan modellerle kullanım için değiştirilmesi gerekeceğini unutmayın.

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]

Karşılaştırma kodunun tamamı ve bir çizim burada bulunabilir: https://medium.com/@micwurm/using-tensorflow-lite-to-speed-up-predictions-a3954886eb98


Harika, daha önce hiç denemedim ama belki de denemeye değer. İpucu için teşekkürler!
ga97dil
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.