为什么TensorFlow 2比TensorFlow 1慢得多?
许多用户都将其作为切换到Pytorch的原因,但我还没有找到牺牲/最渴望的实用质量,速度和执行力的理由/解释。
以下是代码基准测试性能,TF1与TF2的对比-TF1的运行 速度提高了47%至276% 。
我的问题是: 在图形或硬件级别上,什么导致如此显着的下降?
寻找详细的答案-
已经熟悉广泛的概念。相关的Git
规格 :CUDA 10.0.130,cuDNN 7.4.2,Python 3.7.4,Windows 10,GTX 1070
基准测试结果 :
UPDATE :禁用每下面的代码不会急于执行 没有 帮助。但是,该行为是不一致的:有时以图形方式运行会有所帮助,而其他时候其运行 速度要比
Eager 慢 。
由于TF开发人员没有出现在任何地方,因此我将自己进行调查-可以跟踪相关的Github问题的进展。
更新2 :分享大量实验结果,并附有解释;应该在今天完成。
基准代码 :
# use tensorflow.keras... to benchmark tf.keras; used GPU for all above benchmarks
from keras.layers import Input, Dense, LSTM, Bidirectional, Conv1D
from keras.layers import Flatten, Dropout
from keras.models import Model
from keras.optimizers import Adam
import keras.backend as K
import numpy as np
from time import time
batch_shape = (32, 400, 16)
X, y = make_data(batch_shape)
model_small = make_small_model(batch_shape)
model_small.train_on_batch(X, y) # skip first iteration which builds graph
timeit(model_small.train_on_batch, 200, X, y)
K.clear_session() # in my testing, kernel was restarted instead
model_medium = make_medium_model(batch_shape)
model_medium.train_on_batch(X, y) # skip first iteration which builds graph
timeit(model_medium.train_on_batch, 10, X, y)
使用的功能 :
def timeit(func, iterations, *args):
t0 = time()
for _ in range(iterations):
func(*args)
print("Time/iter: %.4f sec" % ((time() - t0) / iterations))
def make_small_model(batch_shape):
ipt = Input(batch_shape=batch_shape)
x = Conv1D(128, 400, strides=4, padding='same')(ipt)
x = Flatten()(x)
x = Dropout(0.5)(x)
x = Dense(64, activation='relu')(x)
out = Dense(1, activation='sigmoid')(x)
model = Model(ipt, out)
model.compile(Adam(lr=1e-4), 'binary_crossentropy')
return model
def make_medium_model(batch_shape):
ipt = Input(batch_shape=batch_shape)
x = Bidirectional(LSTM(512, activation='relu', return_sequences=True))(ipt)
x = LSTM(512, activation='relu', return_sequences=True)(x)
x = Conv1D(128, 400, strides=4, padding='same')(x)
x = Flatten()(x)
x = Dense(256, activation='relu')(x)
x = Dropout(0.5)(x)
x = Dense(128, activation='relu')(x)
x = Dense(64, activation='relu')(x)
out = Dense(1, activation='sigmoid')(x)
model = Model(ipt, out)
model.compile(Adam(lr=1e-4), 'binary_crossentropy')
return model
def make_data(batch_shape):
return np.random.randn(*batch_shape), np.random.randint(0, 2, (batch_shape[0], 1))
-
UPDATE 8/
17二千○二十〇分之三十零:TF 2.3终于做到了:所有的情况下跑得快,或者尤其快,比以前任何版本。此外,我之前的更新对TF不公平;我的GPU值得指责,最近一直过热。如果您看到迭代时间的上升趋势图,这是一个可靠的症状。最后,请参阅有关Eager vs
Graph的开发者说明。这可能是我对此答案的最新更新。 您 只能在设备上找到模型速度的真实统计信息。
更新5/19/2020 :TF 2.2,使用相同的测试: 急速
仅稍有改善。对于train_on_batch
下面的大块体情况,x轴是连续拟合迭代;我的GPU尚未达到满负荷运行,因此怀疑它是否在节流,但是随着时间的推移,迭代速度确实会变慢。按照上述方法,Graph和Eager分别比其TF1慢 1.56倍 和 1.97 倍
。不确定我是否会进一步调试,因为我正在考虑根据TensorFlow对自定义/底层功能的不良支持切换到Pytorch。但是,我确实打开了一个Issue,以获取开发人员的反馈。
2020年2月18日更新 :我每晚 排练
2.1和2.1;结果好坏参半。除了一个配置(模型和数据大小)外,其他配置的运行速度都快于TF2和TF1的最佳配置。速度较慢且急剧下降的是大型-
尤其是。在图形执行中( 慢1.6倍至2.5倍 )。此外,对于我测试的大型模型,Graph和Eager之间存在 极大的可 重复性差异-
无法通过随机性/计算并行性来解释这一差异。我目前无法按时间限制显示这些声明的可重现代码,因此我强烈建议您针对自己的模型进行测试。尚未针对这些问题打开Git问题,但我确实对原始内容发表了评论-
尚未回复。取得进展后,我将更新答案。
VERDICT :它 是不是 ,如果你知道自己在做什么。但是,如果 不这样做
,平均要进行几次GPU升级,而在最坏的情况下要使用多个GPU,则可能会花费大量成本。
解答
:旨在提供对该问题的高级描述,以及有关如何根据您的需求决定培训配置的指导原则。有关详细的低级描述(包括所有基准测试结果和所使用的代码),请参阅我的其他答案。如果我学到更多信息,我将更新我的答案,并提供更多信息-可以为该问题添加书签/“加注星标”以供参考。
问题摘要 :正如TensorFlow开发人员Q. Scott
Zhu所证实的那样,TF2专注于Eager执行和带有Keras的紧密集成的开发,这涉及到TF源的全面更改-
包括图形级。好处:大大扩展了处理,分发,调试和部署功能。但是,其中一些的成本是速度。但是,这个问题要复杂得多。不仅仅是TF1与TF2-产生火车速度显着差异的因素包括:
- TF2与TF1
- 渴望与图表模式
keras
与tf.keras
numpy
vs.tf.data.Dataset
vs ....train_on_batch()
与fit()
- GPU与CPU
model(x)
vs.model.predict(x)
vs ....
不幸的是,以上几乎没有一个是彼此独立的,并且每个相对于另一个可以至少使执行时间加倍。幸运的是,您可以确定哪些是系统上最有效的方法,并提供一些捷径-
如我所展示的。
我该怎么办? 当前,唯一的方法是-针对您的特定模型,数据和硬件进行实验。没有任何单一的配置总是最好的工作-但也 有 做的,并没有对简化搜索:
> >做:
train_on_batch()
++numpy
+tf.keras
TF1 +热切/图train_on_batch()
+numpy
+tf.keras
+ + TF2图fit()
++numpy
+tf.keras
TF1 / TF2 +图表+大型模型和数据
> >不要:
-
fit()
+numpy
+keras
用于中小型模型和数据 -
fit()
++numpy
+tf.keras
TF1 / TF2 +渴望 -
train_on_batch()
+numpy
+keras
+ + TF1伊格 -
[主要]
tf.python.keras
;它的运行速度可以降低10到100倍,并且带有许多错误;更多信息- 这包括
layers
,models
,optimizers
,和相关的“乱用”的使用进口; ops,utils和相关的“私有”导入都可以-但可以肯定的是,请检查alt以及它们是否用于tf.keras
- 这包括
请参阅我的其他答案底部的代码,以获取基准测试设置示例。上面的列表主要基于其他答案中的“ BENCHMARKS”表。
*上述注意事项的 *局限性 :
- 这个问题的标题是“为什么TF2比TF1慢得多?”,尽管它的主体明确地涉及训练,但问题不仅仅限于此。 即使 在相同的TF版本,导入,数据格式等中, 推理 也将受到主要速度差异的影响-参见此答案。 __
- RNN在TF2中已得到改进,因此很可能会明显改变另一个答案中的数据网格。
- 模型主要用于
Conv1D
和Dense
-不RNNs,稀疏数据/目标,4 / 5D输入,和其他CONFIGS - 输入数据限制为
numpy
和tf.data.Dataset
,同时存在许多其他格式;查看其他答案 - 使用了GPU;结果在CPU上 会 有所不同。实际上,当我问这个问题时,我的CUDA配置不正确,并且某些结果是基于CPU的。
为什么TF2为了急切执行而牺牲了最实用的质量,速度? 显然,它还没有-图形仍然可用。但是如果问题是“为什么要渴望”:
- 出色的调试 :您可能会遇到许多问题,询问“如何获得中间层输出”或“如何检查权重”;渴望,它(几乎)很简单
.__dict__
。相比之下,Graph需要熟悉特殊的后端功能-极大地增加了调试和自省的整个过程。 - 更快的原型制作 :根据与上述类似的想法;更快的理解=剩下更多的时间用于实际DL。
如何启用/禁用EAGER?
tf.enable_eager_execution() # TF1; must be done before any model/tensor creation tf.compat.v1.disable_eager_execution() # TF2; above holds
__在TF2中产生 误导
;看这里。
附加信息 :
- 仔细
_on_batch()
研究TF2中的方法;根据TF开发人员的说法,他们仍然使用较慢的实现方式,但 不是故意的 -即必须解决。有关详细信息,请参见其他答案。
张力流需求 :
请修复train_on_batch()
,以及fit()
迭代调用的性能方面;定制火车循环对许多人尤其是我来说很重要。添加有关这些性能差异的文档/文档字符串,以供用户了解。提高总体执行速度,以防止窥视现象跳入Pytorch。
致谢 :感谢
更新 :
-
19/11/14- 找到了一个模型(在我的实际应用程序中),该模型在带有Numpy输入数据的 _所有配置_ 上的TF2上运行速度较慢。差异范围为13-19%,平均为17%。但是,
keras
和之间的tf.keras
差异更为明显:平均 18-40% 。32%(TF1和2)。(-渴望者(TF2 OOM’d除外)) -
11/17/19 -devs
on_batch()
在最近的一次提交中更新了方法,指出已提高了速度-将在TF 2.1中发布,或现在作为tf-nightly
。由于我无法让后者运行,因此将替补席推迟到2.1。 -
2/20/20- 预测性能也值得借鉴;例如,在TF2中,CPU预测时间可能涉及周期性的峰值