为什么TensorFlow 2比TensorFlow 1慢得多?

发布于 2021-01-29 15:14:54

许多用户都将其作为切换到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))
关注者
0
被浏览
223
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    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-产生火车速度显着差异的因素包括:

    1. TF2与TF1
    2. 渴望与图表模式
    3. kerastf.keras
    4. numpyvs. tf.data.Datasetvs ....
    5. train_on_batch()fit()
    6. GPU与CPU
    7. model(x)vs. model.predict(x)vs ....

    不幸的是,以上几乎没有一个是彼此独立的,并且每个相对于另一个可以至少使执行时间加倍。幸运的是,您可以确定哪些是系统上最有效的方法,并提供一些捷径-
    如我所展示的。


    我该怎么办? 当前,唯一的方法是-针对您的特定模型,数据和硬件进行实验。没有任何单一的配置总是最好的工作-但也 做的,并没有对简化搜索:

    > >做:

    • train_on_batch()++ numpy+ tf.kerasTF1 +热切/图
    • train_on_batch()+ numpy+ tf.keras+ + TF2图
    • fit()++ numpy+ tf.kerasTF1 / TF2 +图表+大型模型和数据

    > >不要:

    • fit()+ numpy+keras用于中小型模型和数据

    • fit()++ numpy+ tf.kerasTF1 / TF2 +渴望

    • train_on_batch()+ numpy+ keras+ + TF1伊格

    • [主要] tf.python.keras;它的运行速度可以降低10到100倍,并且带有许多错误;更多信息

      • 这包括layersmodelsoptimizers,和相关的“乱用”的使用进口; ops,utils和相关的“私有”导入都可以-但可以肯定的是,请检查alt以及它们是否用于tf.keras

    请参阅我的其他答案底部的代码,以获取基准测试设置示例。上面的列表主要基于其他答案中的“ BENCHMARKS”表。


    *上述注意事项的 *局限性

    • 这个问题的标题是“为什么TF2比TF1慢得多?”,尽管它的主体明确地涉及训练,但问题不仅仅限于此。 即使 在相同的TF版本,导入,数据格式等中, 推理 也将受到主要速度差异的影响-参见此答案。 __
    • RNN在TF2中已得到改进,因此很可能会明显改变另一个答案中的数据网格。
    • 模型主要用于Conv1DDense-不RNNs,稀疏数据/目标,4 / 5D输入,和其他CONFIGS
    • 输入数据限制为numpytf.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开发人员的说法,他们仍然使用较慢的实现方式,但 不是故意的 -即必须解决。有关详细信息,请参见其他答案。

    张力流需求

    1. 请修复train_on_batch(),以及fit()迭代调用的性能方面;定制火车循环对许多人尤其是我来说很重要。
    2. 添加有关这些性能差异的文档/文档字符串,以供用户了解。
    3. 提高总体执行速度,以防止窥视现象跳入Pytorch。

    致谢 :感谢


    更新

    • 19/11/14- 找到了一个模型(在我的实际应用程序中),该模型在带有Numpy输入数据的 _所有配置_ 上的TF2上运行速度较慢。差异范围为13-19%,平均为17%。但是,keras和之间的tf.keras差异更为明显:平均 18-40% 。32%(TF1和2)。(-渴望者(TF2 OOM’d除外))

    • 11/17/19 -devson_batch()最近的一次提交中更新了方法,指出已提高了速度-将在TF 2.1中发布,或现在作为tf-nightly。由于我无法让后者运行,因此将替补席推迟到2.1。

    • 2/20/20- 预测性能也值得借鉴;例如,在TF2中,CPU预测时间可能涉及周期性的峰值



知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看