Keras模型预测(model.predict())在第一次迭代时较慢,然后变得更快。

9
我正在尝试在for循环中多次运行model.predict(),并计时相同图像的运行时间。这些数据将用于计算运行预测所需时间的平均值。
如果我在一个单独的脚本中运行预测,它在我的MacBook上大约需要300毫秒的时间。但如果我在for循环中迭代运行,则第一次迭代需要大约300毫秒的时间,而剩余的迭代只需要80毫秒的时间。
这是因为第一次预测仍留在内存中,Keras正在做一些事情来缩短预测时间吗?
有任何想法是为什么会发生这种情况?代码在此处:
#!/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))

1
它必须在某个时刻将模型加载到内存中,这恰好发生在第一次图像分类时。 - Chris
@Chris 那么当我调用 predict 时,它会将模型加载到内存中吗?我认为在定义 model = MobileNet(...) 时已经将模型加载到内存中了。(请注意,计时器直到预测调用之前和之后才开始) - Cov
1
https://github.com/keras-team/keras/issues/8724 - Chris
谢谢@Chris,不确定我是怎么错过那个的! - Cov
1个回答

6

predict function 是在第一次调用 predictpredict_on_batch 时创建的(仅限于第一次),这也是第一次调用需要更多时间的一个原因。

有关详细信息,请参见源代码。特别是要注意什么时候调用了 _make_predict_function 并且它的工作方式。


谢谢您的回复。我把模型 = MobileNet(...) 移动到了测试循环中,这样就可以在每次迭代时重新调用/定义它。现在的问题是每次迭代所需的时间都会增加。第一次迭代需要3.62秒,下一次需要4.09秒,4.52秒等等……有什么想法吗? - Cov
1
@Sithling 没有关于那个的想法,但为了获得一致的结果,您可以在测试“for”循环之前调用predict一次。 - Soroush

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接