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)으로 다운 그레이드했습니다. 문제가 더 이상 존재하지 않을뿐만 아니라 "정상"예측 시간도 크게 개선되었습니다! 테스트를 반복 할 때 (적어도 같은 지수는 아니고 선형 적으로 증가 할 때) 나타나지 않았고 첫 번째 플롯에서만큼 크지 않은 두 스파이크는 문제가되지 않습니다. 여기에 이미지 설명을 입력하십시오

따라서 이것은 @OverLordGoldDragon이 언급 한 것처럼 다른 상황에서도 유사한 동작을 나타내는 tensorflow 2.0 고유의 문제인 것으로 판단 할 수 있습니다.


그 행동은 예측 가능하게 들립니다 ... 증가는 일종의 선형입니다. 시간 계산에이 동작을 포함 시키면 동작하지 않습니까? --- 나는 무슨 일이 일어나고 있는지 모르겠지만 ... predict_on_batch대신에 시도하면 어떻게됩니까 ?
Daniel Möller

와 무슨 다른 시도 y_pred = model(sample).numpy()와 함께 y_pred = model(sample, training=False).numpy()?
Daniel Möller

결과를 추가했습니다. numpy 버전은 동작을 보이지 않는 것 같습니다.
ga97dil

그러나 predict_classes여전히 가장 빠릅니다 ..... 그냥 predict어때?
Daniel Möller

1
나는 이것이 일종의 메모리 청소 일 것이라고 생각한다 ....
Daniel Möller

답변:


10

간단한 설명 - TF2는 일반적으로 몇 가지 내가 만난 경우에 가난하고 버그 등의 메모리 관리를 전시 여기여기 . 특히 예측을 통해 가장 성능이 좋은 사료 공급 방법은 여기 를 통해 model(x)직접 참조 하고 관련 토론을 통해 이루어집니다.

요컨대 : model(x)그것의 작용을 통해 __call__(이 상속되는 메소드 base_layer.Layer반면) predict(), predict_classes()등을 통해 전용의 루프 기능을 포함한다 _select_training_loop(); 각각은 서로 다른 사용 사례에 적합한 서로 다른 데이터 전처리 및 사후 처리 방법을 사용 model(x)하며 2.1에서 가장 빠른 소형 모델 / 작은 배치 (아마 크기에 관계없이) 성능을 제공하도록 설계되었습니다 (아직도 2.0에서 가장 빠름).

연결된 토론에서 텐서 플로우 개발자 인용 :

모델 예측이 아닌 모델 호출을 사용하여 출력을 예측할 수 있습니다. 즉, model(x)"데이터 세트로의 변환"부분이 없기 때문에 호출 하면이 작업이 훨씬 빨라지고 캐시 된 직접 호출 tf.function됩니다.

참고 : 이것은 2.1, 특히 2.2에서는 문제가되지 않지만 각 방법을 테스트하십시오. 또한 이것이 시간 급상승에 대한 귀하의 질문에 직접 대답하지는 않는다는 것을 알고 있습니다. 나는 그것이 Eager 캐싱 메커니즘과 관련이 있다고 생각하지만, 결정하는 가장 확실한 방법은 via TF Profiler이며, 2.1에서 깨졌습니다 .


업데이트 : 스파이크 증가 , 가능한 GPU 조절; ~ 1000 회 반복을 수행하고 대신 10,000을 시도하십시오. 결국 증가가 멈춰야합니다. 귀하의 의견에서 언급했듯이, 이것은 model(x); GPU 단계가 하나도 덜 필요하기 때문에 의미가 있습니다 ( "데이터 세트로의 변환").

Update2 : 이 문제에 직면하면 여기 에 개발자를 버그로 만들 수 있습니다. 그것은 주로 내가 거기 노래


이것은 한 방법이 왜 느린 지에 대한 좋은 해답이지만 여러 번의 실행에서 증가하는 런타임을 설명하지는 않습니다.
LLSv2.0

1
@ LLSv2.0 완전히 확신 할 수는 없지만 업데이트 된 답변-이 문제를 여기에서
OverLordGoldDragon

1
@ ga97dil 예, 설명이 잘못되었습니다. 응답 시간이 길어질 수 있지만 Github에 문의하십시오.
OverLordGoldDragon

1
@ ga97dil 실제로, TF1은 TF2보다 훨씬 빠를 수 있지만, TF 2.1은 벤치마킹에서 가장 빠른 훈련이기 때문에 작은 모델 및 데이터 세트에 시도해 볼 가치가 있습니다 (예측하지 않았 음). 더 중요한 것은 TF2를 사용한다면 Graph vs. 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 초였습니다.

아래의 클래스는 모델을 변환하고 사용하는 방법을 보여 주며 predictKeras 모델과 같은 방법을 제공합니다 . 단일 1D 입력 및 단일 1D 출력이없는 모델과 함께 사용하려면 수정해야합니다.

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.