为什么 keras 模型预测编译后会更慢?

共2个回答,已解决, 标签: python tensorflow keras jupyter-notebook jupyter-lab

prediction speed keras

理论上,预测应该是恒定的,因为权重的大小是固定的。如何在编译后恢复速度 (不需要删除优化器)?

参见相关实验:Https://nbviewer.jupyter.org/github/off99555/TensorFlowExperiments/blob/master/test-prediction-speed-after-compile.ipynb?Flush_cache = true

第1个答案(采用)

终极罪魁祸首:self._experimental_run_tf_function = True。它的实验。但实际上并不坏。

任何 TensorFlow 开发者阅读:清理你的代码_。太乱了。它违反了重要的编码实践,如一个函数做一件事;_process_inputs does a _lot more than "process inputs", same for _standardize_user_data。“我工资不够” -- 但是你付费,花额外的时间理解你自己的东西,用户用更清晰的代码更容易解决你的问题页面。


摘要: 这只是一个慢与compile()

compile() sets an internal flag which assigns a different prediction function to predict。此功能构建一个新的图每次调用时,相对于未编译速度减慢。然而,只有在火车时间比数据处理时间短得多。如果我们增加模型尺寸至少到中等大小,两者变得相等。请参见底部的代码。

数据处理时间的这种轻微增加比放大图的能力更能补偿。因为只保留一个模型图更有效,所以一个预编译被丢弃。尽管如此,: 如果你的模型相对于数据很小,你最好不用compile()用于模型推断。见我的另一个答案的解决方法。


我该怎么办?

比较编译和未编译的模型性能,因为我在底部的代码中。

  • 编译速度更快: 运行predict在编译的模型上。
  • 编译速度较慢: 运行predict在未编译的模型上。

是的两者都是可能的,这将取决于 (1) 数据大小; (2) 模型大小; (3) 硬件。底部的代码实际上显示编译模型更快,但 10 次迭代是一个小样本。在我的另一个答案中,请参见 “解决方法”。


细节:

这需要一段时间来调试,但很有趣。下面我描述了我发现的关键罪魁祸首,引用了一些相关的文档,并展示了导致最终瓶颈的探查器结果。

(FLAG == self.experimental_run_tf_function,为了简洁)

  1. Model by default instantiates with FLAG=False. compile() sets it to True
  2. predict() involves acquiring the prediction function, func = self._select_training_loop(x)
  3. 没有任何特殊的 kwargs 传递给predict and compile,所有其他标志都是这样的:
    • (一)FLAG==True --> func = training_v2.Loop()
    • (B)FLAG==False --> func = training_arrays.ArrayLikeTrainingLoop()
  4. 源代码文档字符串, (一)严重依赖图形,使用更多的分发策略,并且 ops 容易创建和销毁图形元素,这 “可能” (确实) 影响性能。

真正的罪魁祸首:_process_inputs(), accounting for 81% of runtime. Its major component? _create_graph_function(), 72% of runtime. This method does not even exist for (B). Using a mid-sized model, however, _process_inputs包括运行时间不到 1%。底部的代码,教授

第2个答案

更新: 请参见作为单独答案发布的实际答案; 这篇文章包含补充信息


.compile()设置 TF/Keras 图的大部分,包括损失、指标、梯度,部分优化器及其权重 -- 这保证了显著的放缓。

什么出乎意料的是,我自己的实验放缓了 10 倍,对于predict(),它不会更新任何权重。查看 tf2 的源代码,图形元素看起来紧密交织在一起,资源不一定被 “公平” 分配。

开发人员可能忽略predict未编译模型的性能,因为模型通常用于编译-但是在实践中,这是一个不可接受的差异。这也可能是一个 “必要的邪恶”,因为有一个简单的解决方法 (见下文)。

这不是一个完整的答案,我希望有人能在这里提供它 -- 如果没有,我建议在 TensorFlow 上打开一个 Github 问题。(OP 有;在这里)


解决方法: 训练一个模型,保存它权重,在不编译的情况下重新构建模型,加载权重。做保存整个模型 (例如model.save()), as it'll load compiled - instead use model.save_weights() and model.load_weights()

解决方法 2: 以上,但使用load_model(path, compile=False); 建议信用:D.M ö ller


更新: 为了澄清,优化器是完全实例化compile, including its weights and updates tensors - this is done when the first call to a fitting function is made (fit, train_on_batch, etc), via model._make_train_function()

因此,观察到的行为更加奇怪。更糟糕的是,构建优化器引发任何进一步的减速 (见下文) -- 暗示 “图形大小” 不是这里的主要解释。


编辑: 在一些模型上,a30 倍减速。TensorFlow,你做了什么。下面的例子:

从 tensorflow.keras.layers 导入输入,密集
从 tensorflow.keras.models 导入 Model
将 numpy 作为 np 导入
从时间导入时间

Def 时间 (func,arg,迭代):
T0 = 时间 ()
对于 _ in 范围 (迭代):
Func (arg)
打印 ("%.4f sec" % (时间 ()-t0))

Ipt = 输入 (形状 = (4,))
X = 密集 (2,激活 = “剩余”) (ipt)
Out = Dense (1,激活 = 'sigmoid') (x)
模型 = 模型 (ipt,out)

X = np.random.randn (32,4)

Timeit (model.predict,X,1000)
Model.compile ('adam',loss = 'binary _ crossentropy')
Timeit (model.predict,X,1000)
Model._ make_train_function () # 构建优化器
Timeit (model.predict,X,1000)

输出:

0.9891 秒
29.785 秒
29.521 秒

相关问题

通过随机抽样其他列数据创建新列 如何使用熊猫获得包括每一个组合的计数 如何有效地展开矩阵的值与小块? 使用 Tensorflow 2.0 在 MNIST 上定制神经网络实现? “不推荐使用类型的同义词; 在 numpy 的未来版本中,它将被理解为 (类型,(1,)/(1,) 类型。 烧瓶和 Keras 模型错误 ''_ thread._ local '对象没有属性' value' '? 为什么 keras 模型预测编译后会更慢? 为什么 TensorFlow 2 比 TensorFlow 1 慢得多? 如何将字典中的值与字符串中的多个元素相加? 如何再次在元组键值列表中转换它?