许多用户都将其作为切换到Pytorch的原因,但我还没有找到牺牲/最渴望的实用质量,速度和执行力的理由/解释。
以下是TF1与TF2的代码基准测试性能-TF1在上的运行速度从快47%到276%。
我的问题是:在图形或硬件级别上,什么导致如此显着的下降?
寻找详细的答案-已经熟悉广泛的概念。 Relevant Git
规格:CUDA 10.0.130,cuDNN 7.4.2,Python 3.7.4,Windows 10,GTX 1070
基准测试结果:
更新:根据以下代码禁用急切执行无济于事。但是,该行为是不一致的:有时以图形方式运行会有所帮助,而其他时候其运行速度要比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))
最佳答案
更新8/1730/2020 :TF 2.3终于做到了:所有情况下的运行速度都比以前的任何版本都快,或者明显更快。
此外,我之前的更新对TF不公平;我的GPU值得指责,最近一直过热。如果您看到迭代时间的上升趋势图,这是一个可靠的症状。最后,查看关于Eager vs Graph的开发者说明。
这可能是我对此答案的最新更新。您只能在设备上找到模型速度的真实统计信息。
更新2020年5月19日:TF 2.2,使用相同的测试:急切速度只有很小的提高。下面的大号Numpy train_on_batch
情况的图,x轴是连续拟合迭代;我的GPU尚未达到满负荷运行,因此怀疑它是否在节流,但是随着时间的推移,迭代速度确实会变慢。
按照上述方法,Graph和Eager的 1.56x 和 1.97x 分别比其TF1慢。不确定我是否会进一步调试,因为我正在考虑根据TensorFlow对自定义/底层功能的不良支持切换到Pytorch。但是,我确实打开了Issue以获取开发者的反馈。
更新2/18/2020 :我每晚排练2.1和2.1;结果好坏参半。除了一个配置(模型和数据大小)外,其他配置都快于或快于TF2和TF1的最佳配置。速度较慢且急剧下降的是大型-尤其是。在图形执行中( 1.6x到2.5x慢)。
此外,对于我测试的大型模型,Graph和Eager之间存在极大的可重复性差异-无法通过随机性/计算并行性来解释这一差异。我目前无法按时间限制显示这些声明的可重现代码,因此我强烈建议您针对自己的模型进行测试。
尚未针对这些问题打开Git问题,但我确实对original发表了评论-尚未回复。取得进展后,我将更新答案。
VERDICT :如果您知道自己在做什么,则不是。但是,如果您不这样做,则可能会花费大量成本-平均而言,需要进行几次GPU升级,而在最坏的情况下,则需要多个GPU。
答案:旨在提供对该问题的高级描述,以及有关如何根据您的需求决定培训配置的指南。有关详细的低级描述(包括所有基准测试结果和所使用的代码),请参阅我的其他答案。
如果我学到更多信息,我将更新我的答案,并提供更多信息-可以为该问题添加书签/“加注星标”以供引用。
问题摘要:作为TensorFlow开发人员Q.Scott Zhu的confirmed,TF2专注于Eager执行和带有Keras的紧密集成的开发,这涉及到TF源的全面更改-包括图形级。好处:大大扩展了处理,分发,调试和部署功能。但是,其中一些的成本是速度。
但是,这个问题要复杂得多。不仅仅是TF1和TF2-导致火车速度显着差异的因素包括:
keras
与tf.keras
numpy
与tf.data.Dataset
与... train_on_batch()
与fit()
model(x)
与model.predict(x)
与... 不幸的是,以上几乎没有一个是彼此独立的,并且每个相对于另一个可以至少使执行时间加倍。幸运的是,您可以确定哪些是系统上最有效的方法,并提供一些捷径-如我所展示的。
我应该怎么做? 当前,唯一的方法是-针对您的特定模型,数据和硬件进行实验。没有一个单一的配置总能达到最佳效果-但是有一个可以简化您的搜索的步骤:
>> DO:
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倍,并且带有许多错误; more infolayers
,models
,optimizers
和相关的“即用型”用法导入; ops,utils和相关的“私有(private)”导入都可以-但可以肯定的是,请检查alt,以及是否在tf.keras
请参阅我的其他答案底部的代码,以获取基准测试设置示例。上面的列表主要基于其他答案中的“BENCHMARKS”表。
上面的“可做与不可做”中的:
Conv1D
和Dense
-无RNN,稀疏数据/目标,4/5D输入和其他配置numpy
和tf.data.Dataset
,同时存在许多其他格式;例如,查看其他答案为什么TF2为了急切执行而牺牲了最实用的质量,速度? 显然没有,它仍然可用。但是如果问题是“为什么要渴望”:
.__dict__
一样简单。相比之下,Graph需要熟悉特殊的后端功能-极大地增加了调试和自省(introspection)的整个过程。 如何启用/禁用EAGER?
tf.enable_eager_execution() # TF1; must be done before any model/tensor creation
tf.compat.v1.disable_eager_execution() # TF2; above holds
在TF2中产生误导;参见here。其他信息:
_on_batch()
方法;根据TF开发人员的说法,他们仍然使用较慢的实现方式,但并非有意为之-即必须解决。有关详细信息,请参见其他答案。 请求张力转换:
train_on_batch()
,以及迭代调用fit()
的性能方面;定制火车循环对许多人尤其是我来说很重要。 致谢:感谢
更新:
keras
和tf.keras
之间的差异更为明显: 18-40%,平均。 32%(TF1和2)。 (*-渴望者(TF2 OOM'd除外))on_batch()
方法,指出速度有所提高-将在TF 2.1中发布,或者现在可以作为tf-nightly
使用。由于我无法让后者运行,因此将替补席推迟到2.1。关于python - 为什么TensorFlow 2比TensorFlow 1慢得多?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/58441514/