Keras thời gian dự đoán không nhất quán


17

Tôi đã cố gắng để có được ước tính về thời gian dự đoán của mô hình máy ảnh của tôi và nhận ra một điều kỳ lạ. Ngoài việc khá nhanh bình thường, thỉnh thoảng người mẫu cần khá lâu để đưa ra dự đoán. Và không chỉ vậy, những lần đó cũng tăng thời gian chạy mô hình. Tôi đã thêm một ví dụ làm việc tối thiểu để tái tạo lỗi.

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

Thời gian không phụ thuộc vào mẫu (nó đang được chọn ngẫu nhiên). Nếu thử nghiệm được lặp lại, các chỉ số trong vòng lặp for nơi dự đoán sẽ mất nhiều thời gian hơn (gần như) một lần nữa.

nhập mô tả hình ảnh ở đây

Tôi đang sử dụng:

tensorflow 2.0.0
python 3.7.4

Đối với ứng dụng của tôi, tôi cần đảm bảo thực hiện trong một thời gian nhất định. Điều này tuy nhiên không thể xem xét hành vi đó. Điều gì đang xảy ra? Đây có phải là một lỗi trong Keras hay là một lỗi trong phần phụ trợ kéo căng?

EDIT: predict_on_batchhiển thị cùng một hành vi, tuy nhiên, thưa thớt hơn: nhập mô tả hình ảnh ở đây

y_pred = model(sample, training=False).numpy() cho thấy một số ngoại lệ nặng, tuy nhiên, chúng không tăng. nhập mô tả hình ảnh ở đây

EDIT 2: Tôi đã hạ cấp xuống phiên bản tenorflow 1 mới nhất (1.15). Không chỉ là vấn đề không còn tồn tại nữa, thời gian dự đoán "bình thường" cũng được cải thiện đáng kể! Tôi không thấy hai đột biến này có vấn đề, vì chúng không xuất hiện khi tôi lặp lại thử nghiệm (ít nhất là không ở cùng chỉ số và tăng tuyến tính) và phần trăm không lớn như trong âm mưu đầu tiên. nhập mô tả hình ảnh ở đây

Do đó, chúng tôi có thể kết luận rằng đây dường như là một vấn đề cố hữu đối với tenorflow 2.0, cho thấy hành vi tương tự trong các tình huống khác như @OverLordGoldDragon đề cập.


Hành vi đó nghe có vẻ dự đoán được .... sự gia tăng là loại tuyến tính. Nếu bạn bao gồm hành vi này trong tính toán thời gian của bạn, nó sẽ không đi? --- Tôi không biết chuyện gì đang xảy ra ở đó .... nhưng điều gì xảy ra nếu bạn cố gắng predict_on_batchthay thế?
Daniel Möller

Một nỗ lực khác, những gì xảy ra với y_pred = model(sample).numpy()và với y_pred = model(sample, training=False).numpy()?
Daniel Möller

Tôi đã thêm những phát hiện của tôi. Các phiên bản numpy dường như không hiển thị hành vi.
ga97dil

Nhưng predict_classesvẫn là nhanh nhất .... có vẻ như. Thế còn predict?
Daniel Möller

1
Tôi cho rằng đây có thể là một kiểu làm sạch bộ nhớ ....
Daniel Möller

Câu trả lời:


10

TF2 thường thể hiện quản lý bộ nhớ kém và giống như lỗi trong một số trường hợp tôi gặp phải - mô tả ngắn gọn ở đâyđây . Với dự đoán cụ thể, phương pháp cho ăn hiệu quả nhất là thông qua model(x)trực tiếp - xem tại đây và các cuộc thảo luận được liên kết của nó.

Tóm lại: model(x)hoạt động thông qua của nó của nó __call__phương pháp (mà nó được thừa hưởng từ base_layer.Layer), trong khi đó predict(), predict_classes()vv liên quan đến một chức năng loop chuyên dụng thông qua _select_training_loop(); mỗi phương pháp sử dụng các phương pháp xử lý trước và sau xử lý dữ liệu khác nhau phù hợp cho các trường hợp sử dụng khác nhau và model(x)trong 2.1 được thiết kế đặc biệt để mang lại hiệu suất mô hình nhỏ / lô nhỏ (và có thể là bất kỳ kích thước nào) nhanh nhất (và vẫn nhanh nhất trong 2.0).

Trích dẫn một nhà phát triển TenorFlow từ các cuộc thảo luận được liên kết:

Bạn có thể dự đoán đầu ra bằng cách sử dụng cuộc gọi mô hình, không phải dự đoán mô hình, tức là, cuộc gọi model(x)sẽ giúp việc này nhanh hơn nhiều vì không có phần "chuyển đổi thành tập dữ liệu" và cũng gọi trực tiếp bộ nhớ cache tf.function.

Lưu ý : đây không phải là vấn đề trong 2.1 và đặc biệt là 2.2 - nhưng hãy kiểm tra từng phương thức. Ngoài ra tôi nhận ra điều này không trực tiếp trả lời câu hỏi của bạn về thời gian tăng đột biến; Tôi nghi ngờ nó có liên quan đến các cơ chế bộ nhớ đệm Eager, nhưng cách chắc chắn nhất để xác định là thông qua TF Profiler, nó đã bị hỏng trong 2.1.


Cập nhật : liên quan đến việc tăng đột biến, điều chỉnh GPU có thể; bạn đã thực hiện ~ 1000 iters, thay vào đó hãy thử 10.000 - cuối cùng, việc tăng sẽ dừng lại. Như bạn đã lưu ý trong các bình luận của mình, điều này không xảy ra với model(x); có ý nghĩa khi một bước GPU ít hơn có liên quan ("chuyển đổi thành tập dữ liệu").

Update2 : bạn có thể sửa lỗi các nhà phát triển ở đây về nó nếu bạn gặp phải vấn đề này; chủ yếu là tôi hát ở đó


Đây là một câu trả lời tốt cho lý do tại sao một phương pháp chậm hơn, nhưng nó không giải thích được thời gian chạy tăng dần qua nhiều lần chạy.
LLSv2.0

1
@ LLSv2.0 Không hoàn toàn chắc chắn về bản thân mình, nhưng câu trả lời được cập nhật - Tôi vẫn đang chờ phản hồi từ các nhà phát triển khi tôi tự nêu ra vấn đề này tại đây
OverLordGoldDragon

1
@ ga97dil Vâng, sau đó tôi sẽ giải thích - hãy thử hỏi trên Github, mặc dù bạn có thể phải đối mặt với thời gian trả lời dài.
OverLordGoldDragon

1
@ ga97dil Thật vậy, TF1 có thể nhanh hơn nhiều so với TF2 - mặc dù TF 2.1 đáng để thử các mô hình và bộ dữ liệu nhỏ, vì nó nhanh nhất trong việc đào tạo các điểm chuẩn của tôi (không dự đoán được). Quan trọng hơn, nếu bạn đã từng sử dụng TF2, tôi thực sự khuyên bạn nên kiểm tra độ tái lập trong Biểu đồ so với Eager; kết quả có thể khác nhau rất nhiều trong TF 2.1.
OverLordGoldDragon

1
Tôi đã thêm bài viết của bạn vào chuỗi Git và bài viết TF2 so với TF1 của tôi. Cảm ơn đã thông báo cho tôi rằng sự cố đã biến mất trong TF 1.
OverLordGoldDragon

2

Mặc dù tôi không thể giải thích sự không nhất quán trong thời gian thực hiện, tôi có thể khuyên bạn nên thử chuyển đổi mô hình của mình sang TensorFlow Lite để tăng tốc dự đoán trên các bản ghi dữ liệu đơn lẻ hoặc các lô nhỏ.

Tôi đã chạy một điểm chuẩn trên mô hình này:

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

Thời gian dự đoán cho các hồ sơ duy nhất là:

  1. model.predict(input): 18ms
  2. model(input): 1,3ms
  3. Mô hình được chuyển đổi thành TensorFlow Lite: 43us

Thời gian để chuyển đổi mô hình là 2 giây.

Lớp dưới đây cho thấy cách chuyển đổi và sử dụng mô hình và cung cấp một predictphương thức như mô hình Keras. Lưu ý rằng nó sẽ cần được sửa đổi để sử dụng với các mô hình không chỉ có đầu vào 1-D và đầu ra 1-D duy nhất.

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]

Mã điểm chuẩn hoàn chỉnh và một âm mưu có thể được tìm thấy ở đây: https://medium.com/@micwurm/USE-tensorflow-lite-to-speed-up-predictions-a3954886eb98


Thật tuyệt, chưa bao giờ thử nó trước đây nhưng có lẽ nó sẽ đáng để thử. Cảm ơn các gợi ý!
ga97dil
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.