Copyright 2018 The TensorFlow Authors.
Eager Execution
Note: これらのドキュメントは私たちTensorFlowコミュニティが翻訳したものです。コミュニティによる 翻訳はベストエフォートであるため、この翻訳が正確であることや英語の公式ドキュメントの 最新の状態を反映したものであることを保証することはできません。 この翻訳の品質を向上させるためのご意見をお持ちの方は、GitHubリポジトリtensorflow/docsにプルリクエストをお送りください。 コミュニティによる翻訳やレビューに参加していただける方は、 [email protected] メーリングリストにご連絡ください。
TensorflowのEager Executionは、計算グラフの作成と評価を同時におこなう命令的なプログラミングを行うための環境です: オペレーションはあとで実行するための計算グラフでなく、具体的な計算結果の値を返します。 この方法を用いることにより、初心者にとってTensorFlowを始めやすくなり、またモデルのデバッグも行いやすくなります。 さらにコードの記述量も削減されます。 このガイドの内容を実行するためには、対話的インタープリタpython
を起動し、以下のコードサンプルを実行してください。
Eager Executionは研究や実験のための柔軟な機械学習環境として、以下を提供します。
直感的なインタフェース—Pythonのデータ構造を使用して、コードをナチュラルに記述することができます。スモールなモデルとデータに対してすばやく実験を繰り返すことができます。
より簡単なデバッグ—opsを直接呼び出すことで、実行中のモデルを調査したり、変更をテストすることができます。Python標準のデバッグツールを用いて即座にエラーのレポーティングができます。
自然な制御フロー—TensorFlowのグラフ制御フローの代わりにPythonの制御フローを利用するため、動的なモデルのパラメータ変更をシンプルに行うことができます。
Eager ExecutionはTensorflowのほとんどのオペレーションとGPUアクセラレーションをサポートします。 Eager Executionの実行例については、以下を参照してください。 tensorflow/contrib/eager/python/examples.
Note: いくつかのモデルはEager Executionを有効化することでオーバヘッドが増える可能性があります。 パフォーマンス改善を行っていますが、もしも問題を発見したら、バグ報告してベンチマークを共有してください。
セットアップと基本的な使い方
Eager Executionをはじめるためには、プログラムやコンソールセッションの最初に、tf.enable_eager_execution()
を追加してください。 プログラムが呼び出すほかのモジュールにこのオペレーションを追加しないでください。
これでTensorFlowのオペレーションを実行してみましょう。結果はすぐに返されます。
Eager Executionを有効化することで、TensorFlowの挙動は変わります—TensorFlowは即座に式を評価して結果をPythonに返すようになります。 tf.Tensor
オブジェクトは計算グラフのノードへのシンボリックハンドルの代わりに具体的な値を参照します。 セッションの中で構築して実行する計算グラフが存在しないため、print()
やデバッガを使って容易に結果を調べることができます。 勾配計算を終了することなくテンソル値を評価、出力、およびチェックすることができます。
Eager Executionは、NumPyと一緒に使うことができます。 NumPyのオペレーションは、tf.Tensor
を引数として受け取ることができます。 TensorFlow math operations はPythonオブジェクトとNumpy arrayをtf.Tensor
にコンバートします。 tf.Tensor.numpy
メソッドはオブジェクトの値をNumPyのndarray
形式で返します。
tf.contrib.eager
モジュールは、Eager ExecutionとGraph Executionの両方の環境で利用可能なシンボルが含まれており、Graph Execution方式での記述に便利です:
動的な制御フロー
Eager Executionの主要なメリットは、モデルを実行する際にホスト言語のすべての機能性が利用できることです。 たとえば、fizzbuzzが簡単に書けます:
この関数はテンソル値に依存する条件式を持ち、実行時にこれらの値を表示します。
モデルの構築
多くの機械学習モデルはレイヤーを積み重ねによって成り立っています。Eager ExecutionでTensorFlowを使うときは、自分でレイヤーの内容を記述してもいいし、もしくは tf.keras.layers
パッケージで提供されるレイヤーを使うこともできます。
レイヤーを表現するためには任意のPythonオブジェクトを使用できますが、 TensorFlowには便利な基本クラスとして tf.keras.layers.Layer
があります。 このクラスを継承した独自のレイヤーを実装してみます:
MySimpleLayer
の代わりに、その機能のスーパーセットを持っているtf.keras.layers.Dense
レイヤーを使用してください (このレイヤーはバイアスを加えることもできるもできます)。
レイヤーをモデルに組み立てるとき、レイヤーの線形スタックである モデルを表すために tf.keras.Sequential
を使うことができます。この書き方は基本的なモデルを扱いやすいです。
もしくは、 tf.keras.Model
を継承してモデルをクラスにまとめます。 これはレイヤー自身であるレイヤーのコンテナで、 tf.keras.Model
オブジェクトが他の tf.keras.Model
オブジェクトを含むことを可能にします。
Alternatively, organize models in classes by inheriting from tf.keras.Model
. This is a container for layers that is a layer itself, allowing tf.keras.Model
objects to contain other tf.keras.Model
objects.
入力のshapeは最初のレイヤーに初めて入力データを渡すときにセットされるため、 モデル構築時にtf.keras.Model
クラスに設定する必要はありません。
tf.keras.layers
クラスは独自のモデル変数を作成し、包含します。このモデル変数は、それを含むレイヤーオブジェクトのライフタイムにひもづきます。レイヤー変数を共有するには、それらのオブジェクトを共有します。
Eager Executionにおける学習
勾配の計算
自動微分はニューラルネットワークの学習で利用されるバックプロパゲーションなどの機械学習アルゴリズムの実装を行う上で便利です。 Eager Executionでは、勾配計算をあとで行うためのオペレーションをトレースするためにtf.GradientTape
を利用します。
tf.GradientTape
はトレースしない場合に最大のパフォーマンスを提供するオプトイン機能です。各呼び出し中に異なるオペレーションが発生する可能性があるため、すべてのforward-passオペレーションは一つの「テープ」に記録されます。勾配を計算するには、テープを逆方向に再生してから破棄します。特定の tf.GradientTape
は一つのグラデーションしか計算できません。後続の呼び出しは実行時エラーをスローします。
モデル学習
以下のexampleはMNISTという手書き数字分類を行うマルチレイヤーモデルを作成します。 Eager Execution環境における学習可能なグラフを構築するためのオプティマイザーとレイヤーAPIを提示します。
学習を行わずとも、モデルを呼び出して、Eager Executionにより、出力を検査することができます:
kerasモデルは組み込みで学習のループを回すメソッドfit
がありますが、よりカスタマイズが必要な場合もあるでしょう。 Eager Executionを用いて実装された学習ループのサンプルを以下に示します:
値とオプティマイザ
tf.Variable
オブジェクトは、学習中にアクセスされるミュータブルなtf.Tensor
値を格納し、自動微分を容易にします。 モデルのパラメータは、変数としてクラスにカプセル化できます。
tf.GradientTape
と共に tf.Variable
を使うことでモデルパラメータはよりカプセル化されます。たとえば、上の の自動微分の例は以下のように書き換えることができます:
Eager Executionの途中でオブジェクトのステータスを使用する
Graph Executionでは、プログラムの状態(変数など)はglobal collectionに格納され、それらの存続期間は tf.Session
オブジェクトによって管理されます。 対照的に、Eager Executionの間、状態オブジェクトの存続期間は、対応するPythonオブジェクトの存続期間によって決定されます。
変数とオブジェクト
Eager Executionの間、変数はオブジェクトへの最後の参照が削除され、その後削除されるまで存続します。
オブジェクトベースの保存
tf.train.Checkpoint
はチェックポイントを用いてtf.Variable
を保存および復元することができます:
モデルを保存して読み込むために、 tf.train.Checkpoint
は隠れ変数なしにオブジェクトの内部状態を保存します。 モデル
、 オプティマイザ
、そしてグローバルステップの状態を記録するには、それらを tf.train.Checkpoint
に渡します。
オブジェクト指向メトリクス
tfe.metrics
はオブジェクトとして保存されます。新しいデータを呼び出し可能オブジェクトに渡してメトリクスを更新し、 tfe.metrics.result
メソッドを使って結果を取得します。次に例を示します:
サマリとTensorBoard
TensorBoard はモデルの学習プロセスを理解、デバッグ、最適化するための可視化ツールです。プログラムの実行中に書き込まれるサマリイベントを使用します。
tf.contrib.summary
はEager ExecutionとGraph Executionの両方の環境と互換性があります。 tf.contrib.summary.scalar
のようなサマリオペレーションはモデル構築の間に挿入されます。 たとえば、100のグローバルステップごとにサマリを記録するには、次のようにします。
高度な自動分類トピック
動的なモデル
tf.GradientTape
は動的モデルでも使うことができます。 以下のバックトラックライン検索 アルゴリズムの例は、複雑な制御フローにも関わらず 勾配があり、微分可能であることを除いて、通常のNumPyコードのように見えます:
勾配計算のための追加機能
tf.GradientTape
は強力な勾配計算インタフェースですが、 自動微分に利用できる別のAutogradスタイルのAPIもあります。 これらの関数はテンソルと勾配関数のみを使って、tf.variables
を使わずに数式コードを書く場合に便利です:
tfe.gradients_function
—引数をとり、入力関数パラメータの導関数を計算する関数を返します。 入力パラメータはスカラ値を返さなければなりません。返された関数が されると、tf.Tensor
オブジェクトのリストを返します:入力関数のそれぞれの 引数に対して一つの要素。重要なものすべてを関数パラメータとして渡さなければならないので、 多くのtrainableパラメータに依存している場合、これは扱いにくくなります。tfe.value_and_gradients_function
—tfe.gradients_function
に似ていますが、 返された関数が呼び出されると、その引数に関する入力関数の導関数のリストに加えて、入力関数からの値を返します。
次の例では、 tfe.gradients_function
は引数として square
関数を取り、その入力に関して square
の偏微分 導関数を計算する関数を返します。 3
における square
の微分を計算するために、 grad(3.0)
は 6
を返します。
カスタム勾配
カスタム勾配は、Eager ExecutionとGraph Executionの両方の環境で、勾配を上書きする簡単な方法です。 フォワード関数では、 入力、出力、または中間結果に関する勾配を定義します。たとえば、逆方向パスにおいて勾配のノルムを切り取る簡単な方法は次のとおりです:
カスタム勾配は、一連の演算に対して数値的に安定した勾配を提供するために共通的に使用されます。
ここで、 log1pexp
関数はカスタム勾配を用いて解析的に単純化することができます。 以下の実装は、フォワードパスの間に計算された tf.exp(x)
の値を 再利用します—冗長な計算を排除することでより効率的になります:
パフォーマンス
Eager Executionの間、計算は自動的にGPUにオフロードされます。計算を実行するデバイスを指定したい場合は、 tf.device( '/ gpu:0')
ブロック(もしくはCPUを指定するブロック)で囲むことで指定できます:
tf.Tensor
オブジェクトはそのオブジェクトに対するオペレーションを実行するために別のデバイスにコピーすることができます:
ベンチマーク
GPUでの ResNet50 の学習のような、計算量の多いモデルの場合は、Eager ExecutionのパフォーマンスはGraph Executionのパフォーマンスに匹敵します。 しかし、この2つの環境下のパフォーマンスの違いは計算量の少ないモデルではより大きくなり、小さなたくさんのオペレーションからなるモデルでホットコードパスを最適化するためにやるべきことがあります。
Graph Executionの実行
Eager Executionは開発とデバッグをより対話的にしますが、 TensorFlowのGraph Executionは分散学習、パフォーマンスの最適化、そしてプロダクション環境へのデプロイの観点で利点があります。 しかし、Graph Executionのコードの記述方法、標準的なのPythonコードの書き方と異なり、デバッグがより難しく感じるかもしれません。
Graph Execution形式のモデルの構築と学習のために、Pythonプログラムは最初に計算グラフを構築し、 それからC++ベースのランタイムで実行するためにSession.run
を呼び出し、グラフを渡します。この機能の特徴は以下のとおりです:
静的なautodiffによる自動微分
プラットフォームに依存しないサーバーへの簡単なデプロイ
グラフベースの最適化(共通的な部分式の削除、定数の畳み込みなど)
コンパイルとカーネルフュージョン
自動分散とレプリケーション(分散システムへのノード配置)
Eager Executionのコードは、Graph Executionのコードよりもデプロイが難しいです:モデルから 計算グラフを生成するか、またはサーバ上で直接Pythonランタイムからコードを実行する必要があります。
互換性のあるコードの記述
Eager Execution環境で記述されたコードは、Eager Executionが有効になっていない新しいPythonセッションでおなじコードを実行するだけで おなじコードのままGraph Executionで実行することができます。
ほとんどのTensorFlowオペレーションはEager Executionで動作しますが、注意すべき点がいくつかあります:
入力処理にはキューの代わりに
tf.data
を使います。この方法はより高速で簡単です。tf.keras.layers
やtf.keras.Model
のような、オブジェクト指向のレイヤーAPIを使用します—これらのAPIは変数のための明示的なストレージを持っているためです。ほとんどのモデルコードは、Eager ExecutionとGraph Executionにおなじように機能しますが、例外があります。 (たとえば、Pythonによる制御フローで入力に基づいて演算を変更する動的モデルなど)
一度
tf.enable_eager_execution
によってEager Executionが有効化されると、それを無効化することはできません。 Graph Executionに戻すには、新しいPythonセッションを開始する必要があります。
以上が、Eager Execution と Graph Executionの両方のためのコードを書くためのベストプラクティスです。これによって、 Eager Executionによる対話的な実験とデバッガビリティを享受することができ、かつGraph Executionによる分散パフォーマンスの恩恵を受けることができます。
Eager Executionを用いてコードを記述、デバッグ、実験を繰り返したのちにプロダクションへのデプロイのためにモデルパスをimportします。 モデル変数を保存および復元するには tf.train.Checkpoint
を使います。これはEager ExecutionとGraph Executionの両環境の互換性を担保します。 以下にEager Executionのサンプル集があります:
tensorflow/contrib/eager/python/examples
Graph Execution環境でEager Executionを使う
tfe.py_func
を使ってTensorFlowGraph Execution環境でEager Executionを選択的に可能にすることができます。 この機能は、 tf.enable_eager_execution()
が呼ばれていないときに使うことができます。