Keras model.predict() медленнее на первой итерации, затем становится быстрее

Я пытаюсь запустить model.predict() в цикле for несколько раз и определить, сколько времени это занимает одно и то же изображение. Данные будут использоваться для получения среднего времени, необходимого для запуска прогноза.

Если я запущу прогноз в отдельном скрипте, на моем MacBook он будет выполняться примерно за 300 мс. Если я затем запускаю его итеративно в цикле for, время, затраченное на первую итерацию, начнется примерно с 300 мс, а затем упадет до 80 мс для остальных итераций.

Это потому, что первое предсказание осталось в памяти, а Керас делает что-то за кулисами, чтобы сократить время предсказания?

Любая идея, почему это может происходить? Код здесь:

#!/usr/bin/env python3

import argparse
import keras
from keras.applications.imagenet_utils import decode_predictions
from keras.applications.inception_v3 import preprocess_input
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' # Suppress CPU warnings
import time
from timeit import default_timer as timer
import datetime
import csv
import numpy as np

"""Define all model permutations for MobileNetsV1 and MobileNetsV2"""
# Define all V1 model permutations
# V1_MODELS = [(128,0.25)]
V1_MODELS = [(128, 0.25), (128, 0.5), (128, 0.75), (128, 1)]#,
#              (160, 0.25), (160, 0.5), (160, 0.75), (160, 1),
#              (192, 0.25), (192, 0.5), (192, 0.75), (192, 1),
#              (224, 0.25), (224, 0.5), (224, 0.75), (224, 1)]
# Define all V2 model permutations
V2_MODELS = [(96, 0.35), (96, 0.5), (96, 0.75), (96, 1), (96, 1.3), (96, 1.4),
             (128, 0.35), (128, 0.5), (128, 0.75), (128, 1), (128, 1.3), (128, 1.4),
             (160, 0.35), (160, 0.5), (160, 0.75), (160, 1), (160, 1.3), (160, 1.4),
             (192, 0.35), (192, 0.5), (192, 0.75), (192, 1), (192, 1.3), (192, 1.4),
             (224, 0.35), (224, 0.5), (224, 0.75), (224, 1), (224, 1.3), (224, 1.4)]


def save_result(model, time):
    with open(RESULTS_FILE_NAME, 'a', newline='') as csvfile:
        csv_writer = csv.writer(csvfile)
        csv_writer.writerow([model, time])

    # file = open(RESULTS_FILE_NAME, 'a')
    # file.write(text + '\n')
    # file.close()

if __name__ == "__main__":
    # Set up command line argument parser
    parser = argparse.ArgumentParser()
    parser.add_argument('--image', type=str, help='Path to the image to be tested', default='images/cheetah.jpg')
    parser.add_argument('--model', type=int, help='Specify model architecture as an integer V1: 1, V2: 2', default=1)
    parser.add_argument('--test', type=int, help='Specify the number of tests per model to perform', default=5)
    args = parser.parse_args()

    RESULTS_FILE_NAME = "results/MobileNetV{0}_result_{1}.csv".format(args.model, datetime.datetime.now().strftime("%Y%m%d%H%M%S"))

    # Holds total run time (each individual model time added to this variable)
    total_time = 0

    # Select model parameter list based on command line arguments (default = V1)
    if args.model == 1:
        MODEL_LIST = V1_MODELS
    elif args.model == 2:
        MODEL_LIST = V2_MODELS

    for model_params in MODEL_LIST:
        size = model_params[0]
        alpha = model_params[1]
        # Select MobileNet model based on command line arguments (default = V1)
        if args.model == 1:
            model = keras.applications.mobilenet.MobileNet(input_shape=(size, size, 3),
                                                           alpha=alpha,
                                                           depth_multiplier=1,
                                                           dropout=1e-3,
                                                           include_top=True,
                                                           weights='imagenet',
                                                           input_tensor=None,
                                                           pooling=None,
                                                           classes=1000)
        elif args.model == 2:
            model = keras.applications.mobilenet_v2.MobileNetV2(input_shape=(size, size, 3),
                                                               alpha=1.0,
                                                               depth_multiplier=1,
                                                               include_top=True,
                                                               weights='imagenet',
                                                               input_tensor=None,
                                                               pooling=None,
                                                               classes=1000)



        # model.summary()
        for num in range(args.test):

            # Start timing
            start_time = timer()

            # Preprocess the image TODO: should this be included in timing?
            img = keras.preprocessing.image.load_img(args.image, target_size=(size, size))
            x = keras.preprocessing.image.img_to_array(img)
            x = np.expand_dims(x, axis=0)
            x = preprocess_input(x)

            # Predict the category of the input image
            predictions = model.predict(x, verbose=1)

            # Print predictions
            #print('Predicted:', decode_predictions(predictions, top=3))

            # End timing
            end_time = timer()

            # Print total run time
            print("Size: {0}  Alpha: {1}".format(size, alpha))
            print("Time Taken: {} seconds".format(end_time-start_time))
            # save_result(str(model_params), str(end_time-start_time))
            total_time = total_time + (end_time-start_time)

    print("######################")
    print("Total Time: {} seconds".format(total_time))

В какой-то момент модель должна быть загружена в память, которая оказывается в первой классификации изображений.

Chris 08.04.2019 18:25

@Chris, так что он загружает модель в память, когда я вызываю прогнозирование? Я предположил, что модель загружается в память при определении model = MobileNet(...). (обратите внимание, что таймер запускается позже, до и после вызова прогноза)

Cov 08.04.2019 18:28
github.com/keras-team/keras/issues/8724
Chris 08.04.2019 18:30

Спасибо @Chris, не знаю, как я это пропустил!

Cov 08.04.2019 18:36
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
9
4
3 584
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

предсказать функцию создается во время первого (и только первого) вызова predict или predict_on_batch. Это одна из причин, по которой первый звонок занимает больше времени.

Для получения дополнительной информации см. исходный код. В частности, обратите внимание, когда вызывается _make_predict_function и как это работает.

Спасибо за ответ. Я переместил модель = MobileNet(...) в цикл тестирования for, чтобы он каждый раз вызывался/определялся повторно. Теперь проблема в том, что время, затрачиваемое на каждую итерацию, УВЕЛИЧИВАЕТСЯ с каждой итерацией. Первая итерация была 3,62 с, следующая была 4,09 с, 4,52 с и т. д. Есть идеи?

Cov 08.04.2019 18:39

@ Sithling понятия не имеет об этом, но чтобы получить стабильные результаты, вы можете вызвать predict один раз непосредственно перед циклом тестирования for.

Soroush 08.04.2019 18:49

Другие вопросы по теме