Waktu prediksi yang keras dan tidak konsisten

17

Saya mencoba mendapatkan perkiraan waktu prediksi model keras saya dan menyadari sesuatu yang aneh. Terlepas dari menjadi cukup cepat secara normal, sesekali model membutuhkan waktu yang cukup lama untuk menghasilkan prediksi. Dan tidak hanya itu, saat-saat itu juga meningkatkan semakin lama model berjalan. Saya menambahkan contoh kerja minimal untuk mereproduksi kesalahan.

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

Waktu tidak tergantung pada sampel (dipilih secara acak). Jika tes diulangi, indeks dalam for loop tempat prediksi membutuhkan waktu lebih lama akan (hampir) sama lagi.

masukkan deskripsi gambar di sini

Saya menggunakan:

tensorflow 2.0.0
python 3.7.4

Untuk aplikasi saya, saya perlu menjamin eksekusi dalam waktu tertentu. Namun ini tidak mungkin mengingat perilaku itu. Apa yang salah? Apakah itu bug di Keras atau bug di backend tensorflow?

EDIT: predict_on_batchmenunjukkan perilaku yang sama, namun lebih jarang: masukkan deskripsi gambar di sini

y_pred = model(sample, training=False).numpy() menunjukkan beberapa outlier berat juga, namun, mereka tidak meningkat. masukkan deskripsi gambar di sini

EDIT 2: Saya diturunkan ke versi tensorflow 1 terbaru (1.15). Tidak hanya masalahnya tidak ada lagi, juga waktu prediksi "normal" meningkat secara signifikan! Saya tidak melihat kedua paku sebagai masalah, karena mereka tidak muncul ketika saya mengulangi tes (setidaknya tidak pada indeks yang sama dan meningkat secara linear) dan persentasi tidak sebesar seperti pada plot pertama. masukkan deskripsi gambar di sini

Dengan demikian kita dapat menyimpulkan bahwa ini tampaknya menjadi masalah yang melekat pada tensorflow 2.0, yang menunjukkan perilaku serupa dalam situasi lain seperti yang disebutkan @OverLordGoldDragon.

ga97dil
sumber
Perilaku itu kedengarannya dapat diprediksi .... peningkatannya linear. Jika Anda memasukkan perilaku ini dalam perhitungan waktu Anda, apakah itu tidak akan hilang? --- Saya tidak tahu apa yang terjadi di sana .... tetapi apa yang terjadi jika Anda mencobanya predict_on_batch?
Daniel Möller
Upaya lain, apa yang terjadi dengan y_pred = model(sample).numpy()dan dengan y_pred = model(sample, training=False).numpy()?
Daniel Möller
Saya menambahkan temuan saya. Versi numpy sepertinya tidak menunjukkan perilaku.
ga97dil
Tapi predict_classestetap saja yang tercepat .... sepertinya. Bagaimana dengan adil predict?
Daniel Möller
1
Saya berasumsi ini mungkin beberapa jenis pembersihan memori ....
Daniel Möller

Jawaban:

10

TF2 umumnya menunjukkan manajemen memori yang buruk dan seperti bug dalam beberapa kasus yang saya temui - deskripsi singkat di sini dan di sini . Dengan prediksi pada khususnya, metode pemberian makan yang paling berkinerja adalah melalui model(x)langsung - lihat di sini , dan diskusi terkait.

Singkatnya: model(x)bertindak melalui nya nya __call__metode (yang mewarisi dari base_layer.Layer), sedangkan predict(), predict_classes(), dll melibatkan fungsi loop dedicated via _select_training_loop(); masing-masing menggunakan metode pra-dan pasca-pemrosesan data yang berbeda yang cocok untuk berbagai kasus penggunaan, dan model(x)pada 2.1 dirancang khusus untuk menghasilkan kinerja model-kecil / batch-kecil tercepat (dan mungkin ukuran apa saja) (dan masih tercepat di 2.0).

Mengutip seorang pengembang TensorFlow dari diskusi terkait:

Anda dapat memprediksi output menggunakan pemanggilan model, bukan pemodelan prediksi, yaitu, panggilan model(x)akan membuat ini lebih cepat karena tidak ada bagian "konversi ke dataset", dan juga langsung memanggil cache tf.function.

Catatan : ini seharusnya tidak terlalu menjadi masalah di 2.1, dan terutama 2.2 - tetapi tetap uji setiap metode. Saya juga menyadari ini tidak langsung menjawab pertanyaan Anda tentang lonjakan waktu; Saya menduga itu terkait dengan mekanisme caching Eager, tetapi cara paling pasti untuk menentukan adalah melalui TF Profiler, yang rusak di 2.1.


Pembaruan : terkait peningkatan lonjakan, kemungkinan pelambatan GPU; Anda sudah melakukan ~ 1000 iters, coba 10.000 sebagai gantinya - akhirnya, peningkatan akan berhenti. Seperti yang Anda catat dalam komentar Anda, ini tidak terjadi dengan model(x); masuk akal karena satu langkah GPU lebih sedikit terlibat ("konversi ke dataset").

Update2 : Anda bisa bug devs di sini tentang hal itu jika Anda menghadapi masalah ini; kebanyakan saya bernyanyi di sana

OverLordGoldDragon
sumber
Ini adalah jawaban yang bagus untuk mengapa satu metode lebih lambat, tetapi itu tidak menjelaskan peningkatan waktu berjalan lebih dari beberapa berjalan.
LLSv2.0
1
@ LLSv2.0 Tidak sepenuhnya yakin, tetapi jawaban yang diperbarui - Saya masih menunggu tanggapan dari devs ketika saya mengangkat masalah ini sendiri di sini
OverLordGoldDragon
1
@ ga97dil Ya, maka saya kehabisan penjelasan - coba tanyakan pada Github, meskipun Anda mungkin menghadapi waktu respons yang panjang.
OverLordGoldDragon
1
@ ga97dil Memang, TF1 bisa jauh lebih cepat daripada TF2 - meskipun TF 2.1 patut dicoba untuk model & set data kecil, karena ini adalah yang tercepat dalam pelatihan benchmark saya (tidak melakukan prediksi). Lebih penting lagi, jika Anda pernah menggunakan TF2, saya sangat menyarankan Anda menguji reproduktifitas dalam Grafik vs Eager; hasilnya dapat sangat berbeda dalam TF 2.1.
OverLordGoldDragon
1
Saya telah menambahkan posting Anda ke thread Git , dan TF2 vs TF1 saya. Terima kasih telah memberi tahu saya bahwa masalahnya hilang pada TF 1.
OverLordGoldDragon
2

Meskipun saya tidak dapat menjelaskan ketidakkonsistenan dalam waktu eksekusi, saya dapat merekomendasikan agar Anda mencoba mengubah model Anda menjadi TensorFlow Lite untuk mempercepat prediksi pada catatan data tunggal atau batch kecil.

Saya menjalankan tolok ukur pada model ini:

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

Waktu prediksi untuk catatan tunggal adalah:

  1. model.predict(input): 18ms
  2. model(input): 1.3ms
  3. Model dikonversi ke TensorFlow Lite: 43us

Waktu untuk mengonversi model adalah 2 detik.

Kelas di bawah ini menunjukkan cara mengkonversi dan menggunakan model dan menyediakan predictmetode seperti model Keras. Perhatikan bahwa itu perlu dimodifikasi untuk digunakan dengan model yang tidak hanya memiliki input 1-D tunggal dan output 1-D tunggal.

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]

Kode benchmark lengkap dan plot dapat ditemukan di sini: https://medium.com/@micwurm/using-tensorflow-lite-to-speed-up-predictions-a3954886eb98

Michael
sumber
Keren, tidak pernah mencobanya sebelumnya tapi mungkin itu layak dicoba. Terima kasih atas petunjuknya!
ga97dil