web-dev-qa-db-ja.com

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 Executionを無効にすると、not助けて。ただし、動作は一貫性がありません。グラフモードで実行すると、Eagerに対してslowerを実行する場合にかなり役立つことがあります。

TF開発者はどこにも現れないので、私はこの問題を自分で調査します-リンクされたGithubの問題の進行状況を追跡できます。

UPDATE 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))
126

UPDATE 2/18/2020:私は2.1と2.1を毎晩ベンチに入れました;結果はまちまちです。 1つを除くすべての設定(モデルとデータサイズ)は、TF2とTF1の最高の設定と同じかそれよりはるかに高速です。より遅く、劇的に遅くなるのは、大-大-特にです。グラフの実行(1.6xから2.5x低速).

さらに、私がテストした大規模なモデルでは、グラフとEagerの間にextreme再現性の違いがあります-ランダム性/計算並列性では説明できません。現在、これらのクレームごとの時間制限に関する再現可能なコードを提示することはできません。そのため、独自のモデルでこれをテストすることを強くお勧めします。

これらについてはまだGitの問題を公開していませんが、 original -まだ応答していません。進捗が確認されたら、回答を更新します。


[〜#〜] verdict [〜#〜]:it is n't、あなたが何をしているのか知っているなら。しかし、do n'tの場合、平均していくつかのGPUのアップグレードによって、最悪の場合は複数のGPUによって、多くのコストがかかる可能性があります。


この回答:問題の高レベルの説明と、ニーズに固有のトレーニング構成を決定する方法のガイドラインを提供することを目的としています。すべてのベンチマーク結果と使用コードを含む詳細な低レベルの説明については、他の回答を参照してください。

答えを更新します。何か情報があれば追加情報を追加します。この質問を参照用にブックマーク/「スター」することができます。


問題の概要:as 確認済み TensorFlow開発者、Q。Scott Zhu、TF2はEager Executionと緊密な統合に重点を置いた開発w /グラフレベルを含む、TFソースの抜本的な変更を伴うKeras。利点:処理、配布、デバッグ、および展開の機能が大幅に拡張されました。ただし、これらの一部のコストは速度です。

ただし、問題はかなり複雑です。 TF1とTF2だけではありません。列車の速度に大きな違いをもたらす要因には次のものがあります。

  1. TF2対TF1
  2. Eager vs. Graphモード
  3. keras vs. _tf.keras_
  4. numpy vs. _tf.data.Dataset_ vs. ...
  5. train_on_batch() vs. fit()
  6. GPU対CPU
  7. model(x) vs. model.predict(x) vs. ...

残念ながら、上記のほとんどは互いに独立しておらず、それぞれが少なくとも別の実行時間に比べて実行時間を2倍にすることができます。幸いなことに、ここで示すように、いくつかのショートカットを使用して、何が体系的に最適に機能するかを決定できます。


何をすべきか?現在、唯一の方法は-特定のモデル、データ、ハードウェアを試すことです。常に最適な単一の構成はありませんが、検索を簡素化するためにareすることとしないことはあります。

>> DO:

  • train_on_batch() + numpy + _tf.keras_ + TF1 + Eager/Graph
  • train_on_batch() + numpy + _tf.keras_ + TF2 +グラフ
  • fit() + numpy + _tf.keras_ + TF1/TF2 +グラフ+ラージモデルとデータ

>>しない:

  • fit() + numpy + keras小規模および中規模モデルとデータ用
  • fit() + numpy + _tf.keras_ + TF1/TF2 + Eager
  • train_on_batch() + numpy + keras + TF1 + Eager

  • [メジャー]_tf.python.keras_;実行速度は10〜100倍遅く、多くのバグがあります。 詳細

    • これには、layersmodelsoptimizers、および関連する「すぐに使用できる」使用状況インポートが含まれます。 ops、utils、および関連する「プライベート」インポートは問題ありません-しかし、確実に、altをチェックし、_tf.keras_で使用されているかどうかを確認してください

ベンチマークのセットアップ例については、他の回答の最後にあるコードを参照してください。上記のリストは、主に他の回答の「ベンチマーク」テーブルに基づいています。


[〜#〜] limitations [〜#〜]上記のDOおよび禁止事項:

  • この質問のタイトルは「なぜTF2はTF1よりもはるかに遅いのですか?」であり、その本文は明示的にトレーニングに関するものですが、問題はそれに限定されません。 inferenceも大きな速度差の影響を受けます。even同じTFバージョン、インポート、データ形式などでは- この回答 を参照してください。
  • RNNは、TF2で改善されたため、他の回答のデータグリッドを著しく変更する可能性が高い
  • 主に使用されるモデル_Conv1D_およびDense-RNNなし、スパースデータ/ターゲット、4/5D入力、およびその他の構成
  • 入力データはnumpyおよび_tf.data.Dataset_に制限されていますが、他の多くの形式が存在します。他の答えを見る
  • GPUが使用されました。結果will CPUによって異なります。実際、質問をしたとき、CUDAは適切に構成されておらず、結果の一部はCPUベースでした。

TF2が熱心な実行のために最も実用的な品質、速度を犠牲にしたのはなぜですか?明確ではありません-グラフはまだ利用可能です。しかし、質問が「なぜ熱心なのか」の場合:

  • 優れたデバッグ:「中間層の出力を取得する方法」または「重みを検査する方法」を尋ねる質問に遭遇する可能性があります。熱心で、それは(ほぼ)_.__dict___と同じくらい簡単です。対照的に、グラフは特別なバックエンド機能に精通している必要があり、デバッグとイントロスペクションのプロセス全体を非常に複雑にします。
  • より高速なプロトタイピング:上記と同様のアイデアごと。より速く理解する=実際のDLのためにより多くの時間が残ります。

Egerを有効/無効にする方法は?

_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()メソッドに注意してください。 TF devによると、彼らはまだ遅い実装を使用していますが、意図的ではない-つまり修正する必要があります。詳細については、他の回答をご覧ください。

テンソルフローの開発の要求

  1. train_on_batch()と、fit()を繰り返し呼び出したときのパフォーマンスの側面を修正してください。カスタムトレインループは多くの人にとって、特に私にとって重要です。
  2. ユーザーの知識のために、これらのパフォーマンスの違いに関するドキュメント/ドキュメント文字列の言及を追加します。
  3. 一般的な実行速度を改善して、覗き見がPytorchにホッピングしないようにします。

[〜#〜]謝辞[〜#〜]:ありがとう


[〜#〜] updates [〜#〜]

  • 11/14/19-TF2で実行速度が遅いモデル(私の実際のアプリケーション)が見つかりましたすべての構成の場合 wumpy入力データ付き。差は13〜19%で、平均17%です。ただし、kerasと_tf.keras_の違いはより劇的でした:18-40%、平均32%(TF1と2の両方)。 (*-TF2がOOMしたEagerを除く)

  • 11/17/19-開発者はon_batch()メソッドを 最近のコミット で更新し、速度が向上したことを示している-TF 2.1でリリース、または利用可能現在は_tf-nightly_として。私は後者を実行することができないので、2.1までベンチ処理を遅らせます。

  • 2/20/2-予測パフォーマンスもベンチングに値します。たとえば、TF2では、CPUの予測時間には 周期的なスパイク
69