このページは Cloud Translation API によって翻訳されました。
Switch to English

GrapplerによるTensorFlowグラフの最適化

TensorFlow.orgで見る Google Colabで実行 GitHubでソースを表示 ノートブックをダウンロード

概観

TensorFlowは、計算と熱心な実行の両方を使用して計算を実行します。 tf.Graphは、計算の単位を表すtf.Operationオブジェクト(ops)のセットと、 tf.Operation間を流れるデータの単位を表すtf.Tensorオブジェクトがtf.Tensorます。

Grapplerは、TensorFlowランタイムのデフォルトのグラフ最適化システムです。 Grapplerは、グラフモード( tf.function内)で最適化を適用して、グラフの簡略化や関数本体のインライン化などの高度な最適化を通じてTensorFlow計算のパフォーマンスを改善し、プロシージャ間の最適化を可能にします。 tf.Graph最適化すると、デバイスのピークメモリ使用量が削減され、グラフノードの計算リソースへのマッピングが最適化されるため、ハードウェアの使用率が向上します。

tf.Graph最適化をより細かく制御するには、 tf.config.optimizer.set_experimental_options()を使用します。

利用可能なグラフオプティマイザー

Grapplerは、 MetaOptimizerと呼ばれるトップレベルのドライバーを介してグラフの最適化を実行します。次のグラフオプティマイザーはTensorFlowで使用できます。

  • 定数折りたたみオプティマイザー-可能な場合、グラフの定数ノードを折りたたむことによりテンソルの値を静的に推測し、定数を使用して結果を具体化します。
  • 算術オプティマイザ-一般的な部分式を削除し、算術ステートメントを単純化することにより、算術演算を単純化します。
  • レイアウトオプティマイザー-テンソルレイアウトを最適化して、畳み込みなどのデータ形式に依存する演算をより効率的に実行します。
  • リマッパーオプティマイザー-一般的に発生するサブグラフを最適化された融合モノリシックカーネルに置き換えることにより、サブグラフをより効率的な実装に再マップします。
  • メモリオプティマイザー-グラフを分析して各操作のピークメモリ使用量を検査し、CPU-GPUメモリコピー操作を挿入して、GPUメモリをCPUにスワップしてピークメモリ使用量を減らします。
  • 依存関係オプティマイザー-コントロールの依存関係を削除または再配置して、モデルステップのクリティカルパスを短縮するか、他の最適化を有効にします。 Identityなど、実質的に何もしないノードも削除します。
  • プルーニングオプティマイザー-グラフからの出力に影響を与えないノードをプルーニングします。通常、最初に実行されて、グラフのサイズを縮小し、他のGrapplerパスでの処理を高速化します。
  • 関数オプティマイザー-TensorFlowプログラムの関数ライブラリを最適化し、関数本体をインライン化して、他の手続き間の最適化を可能にします。
  • 形状オプティマイザー-形状および形状関連情報を操作するサブグラフを最適化します。
  • 自動並列オプティマイザ-バッチディメンションに沿って分割することにより、グラフを自動的に並列します。このオプティマイザはデフォルトでオフになっています。
  • ループオプティマイザー-ループからループ不変のサブグラフを引き上げ、ループ内の冗長なスタック操作を削除することにより、グラフ制御フローを最適化します。また、静的に既知のトリップカウントを使用してループを最適化し、条件付きで静的に既知のデッドブランチを削除します。
  • スコープアロケーターオプティマイザー-データの移動を減らし、一部の操作を統合するスコープアロケーターを導入します。
  • ホストオプティマイザーに固定-小さな操作をCPUにスワップします。このオプティマイザはデフォルトでオフになっています。
  • 自動混合精度オプティマイザー-パフォーマンスを向上させるために、該当する場合はデータ型をfloat16に変換します。現在、GPUにのみ適用されます。
  • デバッグストリッパー tf.debugging.Asserttf.debugging.check_numericstf.debugging.Assertなどのデバッグ操作に関連するノードをグラフからtf.printします。このオプティマイザはデフォルトでオフになっています。

セットアップ

import numpy as np
import timeit
import traceback
import contextlib


import tensorflow as tf

オプティマイザの状態を簡単に切り替えるコンテキストマネージャを作成します。

@contextlib.contextmanager
def options(options):
  old_opts = tf.config.optimizer.get_experimental_options()
  tf.config.optimizer.set_experimental_options(options)
  try:
    yield
  finally:
    tf.config.optimizer.set_experimental_options(old_opts)

グラップラーの有無による実行パフォーマンスの比較

TensorFlow 2以降は、デフォルトで熱心に実行れます。 tf.functionを使用して、デフォルトの実行をグラフモードに切り替えます。 Grapplerはバックグラウンドで自動的に実行され、上記のグラフ最適化を適用して実行パフォーマンスを向上させます。

定数折りたたみオプティマイザ

予備的な例として、定数に対して演算を実行し、出力を返す関数を考えます。

def test_function_1():
  @tf.function
  def simple_function(input_arg):
    print('Tracing!')
    a = tf.constant(np.random.randn(2000,2000), dtype = tf.float32)
    c = a
    for n in range(50):
      c = c@a
    return tf.reduce_mean(c+input_arg)

  return simple_function

定数折りたたみオプティマイザをオフにして、関数を実行します。

with options({'constant_folding': False}):
  print(tf.config.optimizer.get_experimental_options())
  simple_function = test_function_1()
  # Trace once
  x = tf.constant(2.2)
  simple_function(x)
  print("Vanilla execution:", timeit.timeit(lambda: simple_function(x), number = 1), "s")
{'constant_folding': False, 'disable_model_pruning': False, 'disable_meta_optimizer': False}
Tracing!
Vanilla execution: 0.0801323579999007 s

定数折りたたみオプティマイザを有効にして関数を再度実行し、関数実行の高速化を観察します。

with options({'constant_folding': True}):
  print(tf.config.optimizer.get_experimental_options())
  simple_function = test_function_1()
  # Trace once
  x = tf.constant(2.2)
  simple_function(x)
  print("Constant folded execution:", timeit.timeit(lambda: simple_function(x), number = 1), "s")
{'constant_folding': True, 'disable_model_pruning': False, 'disable_meta_optimizer': False}
Tracing!
Constant folded execution: 0.0006300529998952697 s

デバッグストリッパーオプティマイザー

入力引数の数値をチェックしてそれを返す単純な関数を考えます。

def test_function_2():
  @tf.function
  def simple_func(input_arg):
    output = input_arg
    tf.debugging.check_numerics(output, "Bad!")
    return output
  return simple_func

まず、デバッグストリッパーオプティマイザーをオフにして関数を実行します。

test_func = test_function_2()
p1 = tf.constant(float('inf'))
try:
  test_func(p1)
except tf.errors.InvalidArgumentError as e:
  traceback.print_exc(limit=2)
Traceback (most recent call last):
  File "<ipython-input-8-1ac473fdfbab>", line 4, in <module>
    test_func(p1)
  File "/tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/eager/def_function.py", line 780, in __call__
    result = self._call(*args, **kwds)
tensorflow.python.framework.errors_impl.InvalidArgumentError: 2 root error(s) found.
  (0) Invalid argument:  Bad! : Tensor had Inf values
     [[node CheckNumerics (defined at <ipython-input-7-cbee1561c83e>:5) ]]
  (1) Invalid argument:  Bad! : Tensor had Inf values
     [[node CheckNumerics (defined at <ipython-input-7-cbee1561c83e>:5) ]]
     [[Identity/_4]]
0 successful operations.
0 derived errors ignored. [Op:__inference_simple_func_131]

Errors may have originated from an input operation.
Input Source operations connected to node CheckNumerics:
 input_arg (defined at <ipython-input-8-1ac473fdfbab>:4)

Input Source operations connected to node CheckNumerics:
 input_arg (defined at <ipython-input-8-1ac473fdfbab>:4)

Function call stack:
simple_func -> simple_func


tf.debugging.check_numericsは、 tf.debugging.check_numericsへのInf引数のため、無効な引数エラーを発生さtest_funcます。

デバッグストリッパーオプティマイザーを有効にして、関数を再度実行してください。

with options({'debug_stripper': True}):
  test_func2 = test_function_2()
  p1 = tf.constant(float('inf'))
  try:
    test_func2(p1)
  except tf.errors.InvalidArgumentError as e:
    traceback.print_exc(limit=2)

デバッグストリッパーオプティマイザーは、グラフからtf.debug.check_numericsノードをtf.debug.check_numericsし、エラーを発生させることなく関数を実行します。

概要

TensorFlowランタイムはGrapplerを使用して、実行前にグラフを自動的に最適化します。さまざまなグラフオプティマイザを有効または無効にするには、 tf.config.optimizer.set_experimental_optionsを使用します。

Grapplerの詳細については、 TensorFlowグラフの最適化をご覧ください。