TensorFlow : Guide : Debugging TensorFlow デバッガー (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
更新日時 : 07/14/2018
作成日時 : 05/04/2018
* TensorFlow 1.9 でドキュメント構成が変わりましたので調整しました。
* 本ページは、TensorFlow 本家サイトの Guide – Debugging – TensorFlow Debugger を翻訳した上で
適宜、補足説明したものです:
* サンプルコードの動作確認はしておりますが、適宜、追加改変している場合もあります。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。
- お住まいの地域に関係なく Web ブラウザからご参加頂けます。事前登録 が必要ですのでご注意ください。
- Windows PC のブラウザからご参加が可能です。スマートデバイスもご利用可能です。
◆ お問合せ : 本件に関するお問い合わせ先は下記までお願いいたします。
株式会社クラスキャット セールス・マーケティング本部 セールス・インフォメーション |
E-Mail:sales-info@classcat.com ; WebSite: https://www.classcat.com/ |
Facebook: https://www.facebook.com/ClassCatJP/ |
TensorFlow デバッガー (tfdbg) は TensorFlow のために特化されたデバッガーです。それは訓練と推論の間に動作している TensorFlow グラフの内部構造と状態を見せてくれます。TensorFlow の計算グラフ・パラダイムゆえに、Python の pdb のような一般目的のデバッガーではそれはデバッグすることが困難です。
NOTE: このガイドは tfdbg のコマンドライン・インターフェイス (CLI) にフォーカスしています。tfdbg のグラフィカル・ユーザ・インターフェイス (GUI) i.e., TensorBoard デバッガー Plugin をどのように使用するかのガイドについては、その README を訪ねてください。
このチュートリアルは TensorFlow モデル開発で頻繁に遭遇するタイプのバグ、nan と inf の出現をデバッグするためにどのように tfdbg CLI を使用するかを示します。次のサンプルは TensorFlow の低位 Session API を使用するユーザのためのものです。このドキュメントの後のセクションは高位 API、つまり tf-learn Esitomator と Experiment とともに tfdbg をどのように使用するかを記述します。そのような問題を観測するために、デバッガーなしで次のコマンドを実行します (ソースコードは ここで 見つかります) :
python -m tensorflow.python.debug.examples.debug_mnist
このコードは MNIST 数字画像認識のための単純なニューラルネットワークを訓練します。accuracy は最初の訓練ステップ後にわずかばかり上がり、しかしそれから低い (ほぼ偶然) レベルで抜け出せなくなることに気がつくでしょう :
Accuracy at step 0: 0.1113 Accuracy at step 1: 0.3183 Accuracy at step 2: 0.098 Accuracy at step 3: 0.098 Accuracy at step 4: 0.098
何が間違っていたのかと考えながら、貴方は訓練グラフのあるノードが inf と nan のような悪い数値を生成したことを疑います、何故ならばこれはこのタイプの訓練の失敗の一般的な原因であるからです。この問題をデバッグしてこの数値問題が最初に浮上した正確なグラフノードの位置を示すために tfdbg を使用しましょう。
TensorFlow Session を tfdbg でラップする
私達のサンプルで tfdbg のためのサポートを追加するために、必要な総てのことは次のコード行を追加して Session オブジェクトを debugger ラッパーでラップすることです。このコードは既に debug_mnist.py に追加されていますので、コマンドラインで –debug フラグにより tfdbg CLI をアクティベートできます。
# Let your BUILD target depend on "//tensorflow/python/debug:debug_py" # (You don't need to worry about the BUILD dependency if you are using a pip # install of open-source TensorFlow.) from tensorflow.python import debug as tf_debug sess = tf_debug.LocalCLIDebugWrapperSession(sess)
このラッパーは Session と同じインターフェイスを持ちますので、デバッギングの有効化はコードへの他の変更は必要としません。ラッパーは追加の特徴を提供します、以下を含みます :
- Session.run() 呼び出しの前後に CLI を起動し、貴方に実行を制御してグラフの内部状態を調査させます。
- tensor 値のための特別なフィルタを登録して、問題の診断を容易にすることを可能にします。
このサンプルでは、私達は既に tfdbg.has_inf_or_nan と呼ばれる tensor フィルタを登録していて、これは任意の中間 tensor に任意の nan か inf 値があるかを単純に決定します (tensor は Session.run() 呼び出しの入力や出力ではなく、入力から出力に繋がるパス内にあります)。
Note: 貴方自身のカスタム・フィルタを書くこともできます。追加の情報のためには DebugDumpDir.find() の API 文書 を見てください。
tfdbg でモデル訓練をデバッグする
モデルを再度訓練してみましょう、但し今回は –debug フラグとともにです :
python -m tensorflow.python.debug.examples.debug_mnist --debug
debug ラッパー session は最初の Session.run() 呼び出しを実行しようとするとき貴方にプロンプトを出します、取得された tensor と feed 辞書に関する情報をスクリーンに表示するとともに。
これが run-start CLI として言及したものです。それは何かを実行する前に現在の Session.run 呼び出しへの供給 (= feeds) と取得 (= fetches) をリストします。
スクリーンサイズが全体的にメッセージ内容を表示するために小さ過ぎる場合には、それをリサイズすることができます。
スクリーン出力をナビゲートするために PageUp / PageDown / Home / End キーを使用します。それらのキーが欠落しているキーボードの殆どの上では Fn + Up / Fn + Down / Fn + Right / Fn + Left が機能するでしょう。
コマンド・プロンプトで run コマンド (or 単に r) を入力します :
tfdbg> run
run コマンドは tfdbg に次の Session.run() 呼び出し (これは test データセットを使用してモデル精度を計算します) の最後まで実行させます。tfdbg は総ての中間 tensor をダンプするために runtime Graph を増強します。実行終了後、tfdbg は総てのダンプされた tensor 値を run-end CLI で表示します。例えば :
tensor のこのリストは run を実行した後でコマンド lt を実行することによっても得られます。
tfdbg CLI Frequently-Used コマンド
tfdbg> プロンプトで次のコマンドを試してください (tensorflow/python/debug/examples/debug_mnist.py のコードを参照しています) :
コマンド | シンタックス or オプション | 説明 | 例 |
lt | ダンプされた tensor をリストします。 | lt | |
-n <name_pattern> | 与えられた正規表現パターンにマッチする名前を持つダンプされた tensor をリストします。 | lt -n Softmax.* | |
-t <op_pattern> | 与えられた正規表現パターンにマッチする op タイプを持つダンプされた tensor をリストします。 | lt -t MatMul | |
-f <filter_name> | 登録された tensor フィルタを通過する tensor のみをリストします。 | lt -f has_inf_or_nan | |
-s <sort_key> | 与えられた sort_key により出力をソートします、その可能な値は timestamp (default), dump_size, op_type そして tensor_name です。 | lt -s dump_size | |
-r | 逆順でのソート。 | lt -r -s dump_size | |
pt | ダンプされた tensor の値をプリントします。 | ||
pt <tensor> | tensor 値をプリントします。 | pt hidden/Relu:0 | |
pt <tensor>[slicing] | numpy-スタイルの配列スライシングを使用して、tensor の部分配列をプリントします。 | pt hidden/Relu:0[0:50,:] | |
-a | ellipsis を使用することなく、より巨大な tensor の全体をプリントします。(巨大な tensor のためには長時間かかるかもしれません。) | pt -a hidden/Relu:0[0:50,:] | |
-r <range> | 指定された数字範囲に入る要素をハイライトします。複数の範囲が連結して使用できます。 | pt hidden/Relu:0 -a -r [[-inf,-1],[1,inf]] | |
-n <number> | 指定された 0-ベースのダンプ番号に対応するダンプをプリントします。複数のダンプを持つ tensor のために必要です。 | pt -n 0 hidden/Relu:0 | |
-s | tensor の数値の要約を含みます (Boolean と int* と float* のような数値型を持つ non-empty tensor にのみ適用可能です) | pt -s hidden/Relu:0[0:50,:] | |
-w | (多分スライスされている) tensor の値を numpy.save() を使用して Numpy ファイルに書きます。 | pt -s hidden/Relu:0 -w /tmp/relu.npy | |
@[coordinates] | pt 出力の指定された要素にナビゲートします。 | @[10,0] or @10,0 | |
/regex | 与えられた正規表現に対して less-スタイル検索。 | /inf | |
/ | 検索された正規表現にマッチする次の行にスクロールします。 | / | |
pf | Session.run への feed_dict の値をプリントします。 | ||
pf <feed_tensor_name> | feed の値をプリントします。また pf コマンドは -a, -r と -s フラグも持つことに注意してください (下にリストされません)、これは pt の同一の名前のフラグと同じシンタックスとセマンティクスを持ちます。 | pf input_xs:0 | |
eval | 任意の Python と numpy 式を評価します。 | ||
eval <expression> | np として利用可能な numpy による、Python / numpy 式を評価して、バッククォートで囲まれた tensor 名をデバッグします。 | eval “np.matmul(( `output/Identity:0` / `Softmax:0`).T, `Softmax:0`)” |
|
-a | それを全体として i.e., ellipsis を使用することなく、巨大なサイズの評価結果をプリントします。 | eval -a ‘np.sum(`Softmax:0`, axis=1)’ | |
-w | 評価の結果を numpy.save() を使用して Numpy ファイルに書きます。 | eval -a ‘np.sum(`Softmax:0`, axis=1)’ -w /tmp/softmax_sum.npy | |
ni | ノード情報を表示します。 | ||
-a | 出力にノード属性を含みます。 | ni -a hidden/Relu | |
-d | ノードから利用可能な debug ダンプをリストします。 | ni -d hidden/Relu | |
-t | ノード作成の Python スタックトレースを表示します。 | ni -t hidden/Relu | |
li | ノードへの入力をリストします。 | ||
-r | ノードへの入力をリストします、再帰的に (入力ツリー)。 | li -r hidden/Relu:0 | |
-d |
-r モード下で再帰の深さを制限します。 | li -r -d 3 hidden/Relu:0 | |
-c | 制御入力を含めます。 | li -c -r hidden/Relu:0 | |
-t | 入力ノードの op タイプを示します。 | li -t -r hidden/Relu:0 | |
lo | ノードの出力受取者をリストします。 | ||
-r | ノードの出力受取者をリストします、再帰的に (出力ツリー)。 | lo -r hidden/Relu:0 | |
-d <max_depth> | -r モード下で再帰の深さを制限します。 | lo -r -d 3 hidden/Relu:0 | |
-c | 制御エッジ経由の受取者を含めます。 | lo -c -r hidden/Relu:0 | |
-t | 受取者ノードの op タイプを示します。 | lo -t -r hidden/Relu:0 | |
ls | ノード作成に伴う Python ソースファイルをリストします。 | ||
-p <path_pattern> | 出力を与えられた正規表現パス・パターンにマッチするソースファイルに制限します。 | ls -p .*debug_mnist.* | |
-n | 出力を与えられた正規表現パターンにマッチするノード名に制限します。 | ls -n Softmax.* | |
ps | Python ソースファイルをプリントします。 | ||
ps <file_path> | (もしあれば、行の) 各々で作成されたノードでアノテートされた行とともに、与えられた Python ソースファイル source.py をプリントします。 | ps /path/to/source.py | |
-t | デフォルトのノードの代わりに、Tensor に関するアノテーションを遂行します。 | ps -t /path/to/source.py | |
-b <line_number> | 与えられたラインから始まる source.py をアノテートします。 | ps -b 30 /path/to/source.py | |
-m <max_elements> | 各行に対するアノテーションの要素数を制限します。 | ps -m 100 /path/to/source.py | |
run | 次の Session.run() まで進めます。 | run | |
-n | デバッギングなしで次の Session.run を通して実行します、そしてそれ以後の run の直前に CLI に落ちます。 | run -n | |
-t <T> | デバッギングなしで Session.run を T – 1 回実行し、続いてデバッギングとともに run します。それからデバッグされた run 直後に CLI に落ちます | run -t 10 | |
-f <filter_name> | 任意の中間 tensor が指定された Tensor フィルタをトリガーするまで Session.run を実行し続けます (フィルタに True を返させます)。 | run -f has_inf_or_nan | |
–node_name_filter <pattern> | 次の Session.run を実行し、与えられた正規表現パターンにマッチする名前を持つノードだけを監視します。 | run –node_name_filter Softmax.* | |
–op_type_filter <pattern> | 次の Session.run を実行し、与えられた正規表現パターンにマッチする op タイプを持つノードだけを監視します。 | run –op_type_filter Variable.* | |
–tensor_dtype_filter <pattern> | 次の Session.run を実行し、与えられた正規表現パターンにマッチするデータ型 (dtypes) を持つ Tensor だけをダンプします。 | run –tensor_dtype_filter int.* | |
-p | profiling モードで次の Session.run 呼び出しを実行します。 | run -p | |
ri | fetches と feeds を含む、現在の実行についての情報を表示します。 | ri | |
config | 永続的な TFDBG UI configuration を設定するか表示します。 | ||
set | config 項目の値を設定します: {graph_recursion_depth, mouse_mode}。 | config set graph_recursion_depth 3 | |
show | 現在の永続的 UI configuration を表示します。 | config show | |
help | 一般的なヘルプ情報をプリントします。 | help | |
help <command> | 与えられたコマンドに対するヘルプをプリントします。 | help lt |
貴方がコマンドを入力するたびに、新しいスクリーン出力が現れることに注意してください。これはブラウザの web ページに幾分類似しています。これらのスクリーンの間を CLI の左上隅近くの <– and –> テキスト矢印をクリックすることによりナビゲートできます。
tfdbg CLI の他の特徴
上でリストされたコマンドに加えて、tfdbg CLI は次の追加の特徴を提供します :
- 以前の tfdbg コマンドを通してナビゲートするために、2, 3 のキャラクタのタイプに続いて Up または Down 矢印キーを続けます。tfdbg はそれらのキャラクタで始まるコマンドの履歴を示します。
- スクリーン出力の履歴を通してナビゲートするためには、次のいずれかを行ないます :
- prev と next コマンドを使用します。
- スクリーンの左上隅近くのアンダーラインがされた <– と –> リンクをクリックします。
- コマンドと幾つかのコマンド引数の Tab 補完。
- スクリーン出力をスクリーンの代わりにファイルにリダイレクトするためには、コマンドを bash-スタイルのリダイレクションで終了します。例えば、次のコマンドは pt コマンドの出力を /tmp/xent_value_slices.txt ファイルにリダイレクトします :
tfdbg> pt cross_entropy/Log:0[:, 0:10] > /tmp/xent_value_slices.txt
nan と inif を見つける
この最初の Session.run() 呼び出しでは、問題のある数値は発生していません。コマンド run かその簡略記法 r を使用して次の run に進むことができます。
TIP: run か r を繰り返し入力すれば、シーケンシャルな方法で Session.run() 呼び出しを通して移動することができるでしょう。
一度に多くの Session.run() 呼び出しを進むためには -t フラグを使用することもできます、例えば :
tfdbg> run -t 10
run-end UI で run を繰り返し入力して総ての Session.run() 呼び出しの後に (例えば、上のテーブルで示された pt コマンドを使用して) nan と inf を手動で探す代わりに、グラフで最初の nan や inf 値が現れるまで run-start や run-end プロンプトで停止することなしにデバッガーに繰り返し Session.run() 呼び出しを実行させるために次のコマンドを使用できます。これは幾つかの手続型言語デバッガーの条件ブレークポイントに類似しています :
tfdbg> run -f has_inf_or_nan
NOTE: 前のコマンドは正しく動作します、何故ならばラップされた session が作成されたときに has_inf_or_nan という名前の tensor フィルタが貴方のために登録されているからです。このフィルタは (前に説明したように) nan と inf を検出します。もし貴方が任意の他のフィルタを登録した場合には、任意の tensor が (フィルタに True を返させて) そのフィルタをトリガーするまで tfdbg を実行させるために “run -f” を使用できます。
def my_filter_callable(datum, tensor): # A filter that detects zero-valued scalars. return len(tensor.shape) == 0 and tensor == 0.0 sess.add_tensor_filter('my_filter', my_filter_callable)そして tfdbg run-start プロンプトで貴方のフィルタがトリガーされるまで実行します :
tfdbg> run -f my_filter
add_tensor_filter() で使用される想定されるシグネチャと predicate Callable の返り値についての更なる情報については この API ドキュメント を見てください。
スクリーン・ディスプレイが最初の行で示すように、has_inf_or_nan フィルタは 4 番目の Session.run() 呼び出しの間に最初にトリガーされます : グラフ上の Adam optimizer forward-backward 訓練パスです。この run では、(総計 95 から) 36 の中間 tensor が nan か inf 値を含みます。これらの tensor は、左側に表示されるそれらのタイムスタンプとともに時系列順にリストされます。リストのトップでは、悪い数値が最初に現れた最初の tensor を見ることができます : cross_entropy/Log:0。
tensor の値を見るためには、アンダーラインがつけられた tensor 名 cross_entropy/Log:0 をクリックするか同等のコマンドを入力します :
tfdbg> pt cross_entropy/Log:0
少しスクロール・ダウンすると貴方は幾つかの散らばった inf 値に気がつくでしょう。もし inf と nan のインスタンスを目で見つけるのが難しいのであれば、regex 検索を遂行して出力をハイライトするために次のコマンドを使用できます :
tfdbg> /inf
あるいは、代わりに :
tfdbg> /(inf|nan)
tenosr の数値の型の素早い要約を得るために -s か –numeric_summary コマンドを使用することもできます :
tfdbg> pt -s cross_entropy/Log:0
要約から、cross_entropy/Log:0 tensor の 1000 要素の幾つかが -inf (負の無限大) であることが見て取れます。
何故これらの無限大が出現したのでしょう?更にデバッグするためには、トップのアンダーラインがつけられた node_info メニュー項目をクリックするか同値の node_info (ni) コマンドを入力することによりノード cross_entropy/Log について更なる情報を表示します :
tfdbg> ni cross_entropy/Log
このノードが op タイプ Log を持ちそしてその入力がノード Softmax であることを見て取れます。入力 tensor をより密接に見るために次のコマンドを実行します :
tfdbg> pt Softmax:0
入力 tensor の値を調査して、ゼロを探します :
tfdbg> /0\.000
実際にゼロがあります。今では悪い数値の源はゼロの log を取るノード cross_entropy/Log であることが明らかです。Python ソースコード内の犯人を見つけ出すために、ノードの構築のトレースバックを示すために ni コマンドの -t フラグを使用します :
tfdbg> ni -t cross_entropy/Log
スクリーンのトップの “node_info” をクリックすれば、tfdbg はノードの構築のトレースバックを自動的に示します。
トレースバックから、op は次の行で構築されたことが見てとれます : debug_mnist.py :
diff = y_ * tf.log(y)
tfdbg は Tensor と ops を Python ソースファイルの行にトレースバックすることを容易にする特徴を持ちます。それらから作成された ops や Tensor を持つ Python ファイルの行にアノテートすることができます。この特徴を使用するためには、単純に ni -t <op_name> コマンドのスタック・トレース出力のアンダーラインがつけられた行番号をクリックするか、ps /path/to/source.py のように ps (or print_source) コマンドを使用します。例えば、次のスクリーンショットは ps コマンドの出力を示します。
問題を修正する
問題を修正するためには、debug_mnist.py を編集して、元の行を :
diff = -(y_ * tf.log(y))
組み込みの、softmax cross-entropy の数値的に安定な実装に変更します :
diff = tf.losses.sparse_softmax_cross_entropy(labels=y_, logits=logits)
次のように –debug フラグで再実行します :
python -m tensorflow.python.debug.examples.debug_mnist --debug
tfdbg> プロンプトで、次のコマンドを入力します :
run -f has_inf_or_nan
どの tensor も nan や inf 値を含むとフラグされておらず、そして精度が今では硬直するのではなく上がり続けることを確認してください。成功です!
tf-learn Estimator と Experiment をデバッグする
このセクションでは Estimator と Experiment API を使用する TensorFlow プログラムをどのようにデバッグするかについて説明します。これらの API により提供される便利さの一部はそれらが Session を内部的に管理することです。これは前のセクションで記述された LocalCLIDebugWrapperSession を適用できなくなります。幸い、tfdbg により提供される特別なフックを使用してそれらを依然としてデバッグできます。
tf.contrib.learn Estimator をデバッグする
現在、tfdbg は tf-learn Estimator の fit() evaluate() メソッドをデバッグできます。Estimator.fit() をデバッグするためには、LocalCLIDebugHook を作成してそれを monitors 引数に供給します。例えば :
# First, let your BUILD target depend on "//tensorflow/python/debug:debug_py" # (You don't need to worry about the BUILD dependency if you are using a pip # install of open-source TensorFlow.) from tensorflow.python import debug as tf_debug # Create a LocalCLIDebugHook and use it as a monitor when calling fit(). hooks = [tf_debug.LocalCLIDebugHook()] classifier.fit(x=training_set.data, y=training_set.target, steps=1000, monitors=hooks)
Estimator.evaluate() をデバッグするためには、次のサンプル内のように、フックを hooks パラメータに割り当てます :
accuracy_score = classifier.evaluate(x=test_set.data, y=test_set.target, hooks=hooks)["accuracy"]
tf-learn のアイリス・チュートリアル に基づく、debug_tflearn_iris.py は Estimator で tfdbg をどのように使用するかの完全なサンプルを含みます。このサンプルを実行するためには、次を行ないます :
python -m tensorflow.python.debug.examples.debug_tflearn_iris --debug
tf.contrib.learn Experiment をデバッグする
Experiment は Estimator よりもより高位の tf.contrib.learn の構成要素です。それはモデルを訓練して評価するための単一のインターフェイスを提供します。Experiment オブジェクトへの train() と evaluate() 呼び出しをデバッグするためには、そのコンストラクタを呼び出すときキーワード引数 train_monitors と eval_hooks をそれぞれ使用できます。例えば :
# First, let your BUILD target depend on "//tensorflow/python/debug:debug_py" # (You don't need to worry about the BUILD dependency if you are using a pip # install of open-source TensorFlow.) from tensorflow.python import debug as tf_debug hooks = [tf_debug.LocalCLIDebugHook()] ex = experiment.Experiment(classifier, train_input_fn=iris_input_fn, eval_input_fn=iris_input_fn, train_steps=FLAGS.train_steps, eval_delay_secs=0, eval_steps=1, train_monitors=hooks, eval_hooks=hooks) ex.train() accuracy_score = ex.evaluate()["accuracy"]
Experiment モードで debug_tflearn_iris サンプルを構築して実行するためには、次を行ないます :
python -m tensorflow.python.debug.examples.debug_tflearn_iris \ --use_experiment --debug
LocalCLIDebugHook はまた fetches と feed_dict と他の状態の関数として、異なる Session.run() 呼び出し上でどの Tensor を監視するかを柔軟に指定するために使用できる watch_fn を configure することを可能にします。更なる詳細のためにはこの API doc を見てください。
TFDBG で keras モデルをデバッグする
Keras で TFDBG を使用するためには、Keras バックエンドに TFDBG-wrapped Session オブジェクトを使用させます。例えば、CLI ラッパーを使用するには :
import tensorflow as tf from keras import backend as keras_backend from tensorflow.python import debug as tf_debug keras_backend.set_session(tf_debug.LocalCLIDebugWrapperSession(tf.Session())) # Define your keras model, called "model". model.fit(...) # This will break into the TFDBG CLI.
TFDBG で tf-slim をデバッグする
TFDBG は tf-slim による訓練と評価のデバッギングをサポートします。下で詳述されるように、訓練と評価は少し異なるデバッギング・ワークフローを必要とします。
tf-slim 内で訓練をデバッグする
訓練プロセスをデバッグするには、LocalCLIDebugWrapperSession を slim.learning.train() の session_wrapper に提供します。例えば :
import tensorflow as tf from tensorflow.python import debug as tf_debug # ... Code that creates the graph and the train_op ... tf.contrib.slim.learning.train( train_op, logdir, number_of_steps=10, session_wrapper=tf_debug.LocalCLIDebugWrapperSession)
tf-slim 内で評価をデバッグする
評価プロセスをデバッグするには、LocalCLIDebugHook を slim.evaluation.evaluate_once() の hooks 引数に提供します。例えば :
import tensorflow as tf from tensorflow.python import debug as tf_debug # ... Code that creates the graph and the eval and final ops ... tf.contrib.slim.evaluation.evaluate_once( '', checkpoint_path, logdir, eval_op=my_eval_op, final_op=my_value_op, hooks=[tf_debug.LocalCLIDebugHook()])
リモートで動作する Session のオフライン・デバッギング
しばしば、貴方のモデルはアクセスする端末を持たないリモート・マシンやプロセス上で動作します。そのようなケースでモデル・デバッギングを遂行するために、tfdbg の offline_analyzer バイナリを使用できます (下で説明されます)。それはダンプされたデータ・ディレクトリ上で動作します。これは低位 Session API とより高位な Estimator と Experiment API の両者に対して行なうことができます。
リモート tf.Session をデバッグする
python で tf.Session API と直接的に相互作用する場合には、メソッド tfdbg.watch_graph を使用して、それと一緒に Session.run() メソッドを呼び出すことができる RunOptions proto を configure することができます。これは、Session.run() 呼び出しが発生するとき、(より遅いパフォーマンスという代償を払って) 中間 tensor とランタイム・グラフが貴方が選択した共有ストレージ位置にダンプされることを引き起こすでしょう。例えば :
from tensorflow.python import debug as tf_debug # ... Code where your session and graph are set up... run_options = tf.RunOptions() tf_debug.watch_graph( run_options, session.graph, debug_urls=["file:///shared/storage/location/tfdbg_dumps_1"]) # Be sure to specify different directories for different run() calls. session.run(fetches, feed_dict=feeds, options=run_options)
後で、アクセスする端末を持つ環境で(例えば、上のコードで指定された共有ストレージ位置にアクセスできるローカル・コンピュータ)、tfdbg の offline_analyzer バイナリを使用して共有ストレージ上のダンプ・ディレクトリ内のデータをロードして調査することができます。例えば :
python -m tensorflow.python.debug.cli.offline_analyzer \ --dump_dir=/shared/storage/location/tfdbg_dumps_1
Session ラッパー DumpingDebugWrapperSession はオフラインで解析できるファイルシステム・ダンプを生成するためのより容易で柔軟な方法を提供します。それを使用するためには、単に貴方の session を tf_debug.DumpingDebugWrapperSession でラップします。例えば :
# Let your BUILD target depend on "//tensorflow/python/debug:debug_py # (You don't need to worry about the BUILD dependency if you are using a pip # install of open-source TensorFlow.) from tensorflow.python import debug as tf_debug sess = tf_debug.DumpingDebugWrapperSession( sess, "/shared/storage/location/tfdbg_dumps_1/", watch_fn=my_watch_fn)
watch_fn 引数は、run() 呼び出しへの fetches と feed_dict と他の状態の関数として、異なる Session.run() 呼び出し上で何の Tensor を監視するかを configure することを可能にする Callable を受け取ります。
C++ と他の言語
モデル・コードが C++ か他の言語で書かれている場合でもまた、オフラインで調査できるうデバッグ・ダンプを生成するためにRunOptions の debug_options フィールドを変更できます。より詳細のためには proto 定義 を見てください。
リモートで動作する tf-learn Estimator と Experiment をデバッグする
リモートの TensorFlow サーバが Estimator を実行する場合、非対話的な DumpingDebugHook を使用できます。例えば :
# Let your BUILD target depend on "//tensorflow/python/debug:debug_py # (You don't need to worry about the BUILD dependency if you are using a pip # install of open-source TensorFlow.) from tensorflow.python import debug as tf_debug hooks = [tf_debug.DumpingDebugHook("/shared/storage/location/tfdbg_dumps_1")]
それからこのフックはこのドキュメントの前の方で説明された LocalCLIDebugHook サンプルと同じ用法で使用できます。Estimator か Experiment の訓練 and/or 評価が発生するとき、tfdbg は次の名前パターンを持つディレクトリを作成します :
/shared/storage/location/tfdbg_dumps_1/run_<epoch_timestamp_microsec>_<uuid>。
各ディレクトリは fit() か evaluate() 呼び出しの基礎となる Session.run() 呼び出しに対応します。tfdbg で提供される offline_analyzer を使用してこれらのディレクトリをロードしてそれらをオフライン流儀でコマンドライン・インターフェイスで調査することができます。例えば :
python -m tensorflow.python.debug.cli.offline_analyzer \ --dump_dir="/shared/storage/location/tfdbg_dumps_1/run_<epoch_timestamp_microsec>_<uuid>"
Frequently Asked Questions
Q: lt 出力kの左側のタイムスタンプは非デバッギング session の実際のパフォーマンスを反映していますか?
A: No. デバッガーは中間 tensor の値を記録するためにグラフに追加の特殊な目的のデバッグ・ノードを挿入しています。これらのノードはグラフ実行を遅くします。貴方のモデルを profile することに興味があれば、以下をチェックしてください :
- tfdbg の profiling モード: tfdbg> run -p。
- TensorFlow のための tfprof と他の profiling ツール。
Q: Bazel の Session に対してどのように tfdbg をリンクしますか?何故 “ImportError: cannot import name debug” のようなエラーを見るのでしょう?
A: 貴方の BUILD ルールで、dependencies を宣言してください : “//tensorflow:tensorflow_py” 及び “//tensorflow/python/debug:debug_py”。最初のはデバッガー・サポートなしでさえも TensorFlow を使用するために include する依存です ; 2 番目がデバッガーを有効にします。それから貴方の Python ファイルで、以下を追加します :
from tensorflow.python import debug as tf_debug # Then wrap your TensorFlow Session with the local-CLI wrapper. sess = tf_debug.LocalCLIDebugWrapperSession(sess)
Q: tfdbg は shape ミスマッチのようなランタイム・エラーをデバッグするのに役立ちますか?
A: Yes. tfdbg は実行時に ops により生成されたエラーをインターセプトして CLI のユーザに何某かのデバッグ手順とともにエラーを提示します。サンプルを見てください :
# Debugging shape mismatch during matrix multiplication. python -m tensorflow.python.debug.examples.debug_errors \ --error shape_mismatch --debug # Debugging uninitialized variable. python -m tensorflow.python.debug.examples.debug_errors \ --error uninitialized_variable --debug
Q: tfdbg-wrapped Session や Hook をどのようにメインスレッドからだけデバッグモードで実行させますか?
A: これは一般的なユースケースで、そこでは Session オブジェクトはマルチスレッドから同時に使用されます。典型的には、子スレッドは enqueue 演算を実行するようなバックグラウンド・タスクをケアします。しばしば、メインスレッドのみをデバッグすることを望むでしょう (あるいは頻度は下がるでしょうが、子スレッドの一つだけ)。このタイプの thread-selective デバッギングを遂行するために LocalCLIDebugWrapperSession の thread_name_filter キーワード引数を使用できます。例えば、メインスレッドだけからデバッグするためには、次のように wrapped Session を構築します :
sess = tf_debug.LocalCLIDebugWrapperSession(sess, thread_name_filter="MainThread$")
上のサンプルは Python のメインスレッドがデフォルト名 MainThread を持つという事実に依拠しています。
Q: 私がデバッグしているモデルは非常に巨大です。tfdbg によりダンプされたデータは私のディスクの空き容量を一杯にします。どうしたら良いでしょう?
A: 次のような状況のどれでもこの問題に遭遇するかもしれません :
- 多くの中間 tensor を持つモデル
- 非常に巨大な中間 tensor
- 多くの tf.while_loop iteration
3つの可能なワークアラウンドあるいは解法があります :
- LocalCLIDebugWrapperSession と LocalCLIDebugHook のコンストラクタは tfdbg がデバッグデータをダンプするパスを指定するためのキーワード引数、dump_root を提供します。tfdbg がより大きな空き容量を持つディスク上にデバッグデータをダンプさせるためにそれを使用できます。例えば :
# For LocalCLIDebugWrapperSession sess = tf_debug.LocalCLIDebugWrapperSession(dump_root="/with/lots/of/space") # For LocalCLIDebugHook hooks = [tf_debug.LocalCLIDebugHook(dump_root="/with/lots/of/space")]
dump_root によりポイントされているディレクトリが空か存在しないことを確認してください。tfdbg は抜ける前にダンプ・ディレクトリをクリーンアップします。
- 実行の間に使用されるバッチサイズを減じます。
- グラフの特定のノードだけを監視するために tfdbg の run コマンドのフィルタリング・オプションを使用します。例えば :
tfdbg> run --node_name_filter .*hidden.* tfdbg> run --op_type_filter Variable.* tfdbg> run --tensor_dtype_filter int.*
上の最初のコマンドは名前が正規表現パターン .*hidden.* にマッチするノードだけを監視します。2番目のコマンドは名前がパターン Variable.* にマッチする演算のみを監視します。3番目のものは dtype がパターン int.* (e.g., int32) にマッチする tensor だけを監視します。
Q: tfdbg CLI で何故テキストを選択できないのでしょう?
A: これは tfdbg CLI がデフォルトで端末のマウス・イベントを有効にするためです。mouse-マスク モードは、テキスト選択を含むデフォルトの端末相互作用を override します。コマンド mouse off か m off を使用してテキスト選択を再有効にすることができます。
Q: 次のようなコードをデバッグするとき tfdbg CLI はダンプされた tensor を何故表示しないのでしょう?
a = tf.ones([10], name="a") b = tf.add(a, a, name="b") sess = tf.Session() sess = tf_debug.LocalCLIDebugWrapperSession(sess) sess.run(b)
A: ダンプされたデータを見ない理由は実行される TensorFlow グラフの総てのノードが TensorFlow ランタイムにより constant-folded であるからです。このサンプルでは、a は constant tensor です ; 従って取得される tensor b もまた事実上 constant tensor です。TensorFlow グラフ最適化はグラフの将来的な実行をスピードアップするために a と b を含むグラフを単一のノードに折り畳みます、これが何故 tfdbg がどのような中間 tensor ダンプも生成しないかです。けれども、次のサンプル内のように a が tf.Variable であるならば、
import numpy as np a = tf.Variable(np.ones[10], name="a") b = tf.add(a, a, name="b") sess = tf.Session() sess.run(tf.global_variables_initializer()) sess = tf_debug.LocalCLIDebugWrapperSession(sess) sess.run(b)
constant-folding は発生せずに tfdbg は中間 tensor ダンプを表示するはずです。
Q: 望まない無限大や NaN を生成するモデルをデバッグしています。しかし私のモデルでは、完全に正常な条件下でさえも出力 tensor 内で無限大や NaN を生成することが分かっている幾つかのノードがあります。run -f has_inf_or_nan アクションの間にそれらをどのようにスキップできるでしょう?
A: –filter_exclude_node_names (-fenn for short) フラグを使用してください。例えば、モデルが正しく振舞っているか否かに無関係に無限大や NaN を生成する、正規表現 .*Sqrt.* にマッチする名前を持つノードを持つことを知っているのであれば、コマンド run -f has_inf_or_nan -fenn .*Sqrt.* で infinity/NaN-finding run からノードを除外できます。
Q: tfdbg のための GUI はありますか?
A: Yes, TensorBoard Debugger Plugin は tfdbg の GUI です。それは、計算グラフの精査、tensor 値のリアルタイム可視化、tensor への継続と条件ブレークポイント、そして tensor のそれらのグラフ構築ソースコードへの結び付けをブラウザ環境で提供します。始めるためには、その README を訪ねてください。
以上