Keras 不一致的预测时间

ga9*_*dil 19 python performance keras tensorflow tensorflow2.0

我试图估计我的 keras 模型的预测时间并意识到一些奇怪的事情。除了正常情况下相当快之外,模型每隔一段时间需要很长时间才能做出预测。不仅如此,这些时间也会随着模型运行的时间而增加。我添加了一个最小的工作示例来重现错误。

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))
Run Code Online (Sandbox Code Playgroud)

时间不取决于样本(它是随机挑选的)。如果重复测试,for 循环中预测需要更长时间的索引将(几乎)再次相同。

在此处输入图片说明

我正在使用:

tensorflow 2.0.0
python 3.7.4
Run Code Online (Sandbox Code Playgroud)

对于我的应用程序,我需要保证在特定时间内执行。然而,考虑到这种行为,这是不可能的。出了什么问题?是 Keras 中的错误还是 tensorflow 后端中的错误?

编辑: predict_on_batch显示相同的行为,但是,更稀疏: 在此处输入图片说明

y_pred = model(sample, training=False).numpy() 也显示了一些严重的异常值,但是,它们并没有增加。 在此处输入图片说明

编辑 2:我降级到最新的 tensorflow 1 版本 (1.15)。不仅问题不再存在,“正常”的预测时间也显着提高!我不认为这两个尖峰有问题,因为当我重复测试时它们没有出现(至少不是在相同的指数和线性增加)并且百分比没有第一个图中那么大。 在此处输入图片说明

因此我们可以得出结论,这似乎是 tensorflow 2.0 固有的问题,它在其他情况下表现出与@OverLordGoldDragon 提到的类似的行为。

Ove*_*gon 10

在我遇到的几个实例中,TF2 通常表现出糟糕和类似错误的内存管理 -此处此处的简要说明。特别是预测,最高效的喂养方法是通过model(x)直接 - 请参阅此处及其相关讨论。

概括地说:model(x)通过其它的作用__call__方法(其从继承base_layer.Layer),而predict()predict_classes()等经由涉及专用回路功能_select_training_loop(); 每个都使用适合不同用例的不同数据预处理和后处理方法,并且model(x)在 2.1 中专门设计用于产生最快的小模型/小批量(可能是任意大小)性能(并且在 2.0 中仍然是最快的)。

从相关讨论中引用TensorFlow 开发人员:

您可以使用模型调用而不是模型预测来预测输出,即调用model(x)会使这个更快,因为没有“转换为数据集”部分,而且它直接调用缓存的tf.function.

注意:这在 2.1 中应该不是问题,尤其是 2.2 - 但无论如何都要测试每种方法。我也意识到这并不能直接回答你关于时间峰值的问题;我怀疑它与 Eager 缓存机制有关,但最可靠的确定方法是 via TF Profiler,它在 2.1中被破坏了。


更新:关于增加峰值,可能的 GPU 节流;你已经完成了大约 1000 次迭代,请尝试 10,000 次 - 最终,增加应该停止。正如您在评论中指出的,这不会发生在model(x); 有意义,因为少了一个 GPU 步骤(“转换为数据集”)。

更新 2:如果您遇到此问题,您可以在这里向开发人员提出问题;主要是我在那里唱歌