https://blog.csdn.net/gubenpeiyuan/article/details/82710163
TensorFlow 調試程序
tfdbg
是 TensorFlow 的專用調試程序。借助該調試程序,您可以在訓練和推理期間查看運行中 TensorFlow 圖的內部結構和狀態,由於 TensorFlow 的計算圖模式,使用通用調試程序(如 Python 的 pdb
)很難完成調試。
本指南重點介紹 tfdbg
的命令行界面 (CLI)。有關如何使用 tfdbg 的圖形用戶界面 (GUI)(即 TensorBoard 調試程序插件)的指導,請訪問相關 README 文件。
注意:TensorFlow 調試程序使用基於 curses 的文本界面。在 Mac OS X 上,ncurses
庫是必需的,而且可以使用 brew install homebrew/dupes/ncurses
進行安裝。在 Windows 上,curses 並沒有得到同樣的支持,因此基於 readline 的界面可以與 tfdbg 配合使用(具體方法是使用 pip
安裝 pyreadline
)。如果您使用的是 Anaconda3,則可以使用 "C:\Program Files\Anaconda3\Scripts\pip.exe" install pyreadline
等命令進行安裝。您可以在此處下載非官方 Windows curses 軟件包,然后使用 pip install <your_version>.whl
進行安裝;不過,Windows 上的 curses 可能無法像 Linux 或 Mac 上的 curses 一樣穩定地運行。
本教程展示了如何使用 tfdbg CLI 調試出現 nan
和 inf
的問題,這是 TensorFlow 模型開發期間經常出現的一種錯誤類型。下面的示例適用於使用低階 TensorFlow Session
API 的用戶。本文檔的后面部分介紹了如何將 tfdbg 與更高階的 API(即 tf-learn Estimator
和 Experiment
)相結合。要觀察此類問題,請在不使用調試程序的情況下運行以下命令(可在此處找到源代碼):
python -m tensorflow.python.debug.examples.debug_mnist
此代碼訓練了一個簡單的神經網絡來識別 MNIST 數字圖像。請注意,在完成第一個訓練步之后,准確率略有提高,但之后停滯在較低(近機會)水平:
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 來調試此問題,並確定第一次出現此數字問題的確切圖節點。
使用 tfdbg 封裝 TensorFlow 會話
要向示例中的 tfdbg 添加支持,我們只需添加下列代碼行,並使用調試程序封裝容器封裝會話對象。此代碼已添加到 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.run()
調用前后調出 CLI,以便您控制執行情況和檢查圖的內部狀態。 - 允許您為張量值注冊特殊
filters
,以便診斷問題。
在本示例中,我們已經注冊了一個名為 tfdbg.has_inf_or_nan
的張量過濾器,它僅僅確定任何中間張量(不是 Session.run()
調用的輸入或輸出,而是位於從輸入到輸出的路徑中的張量)中是否存在任何 nan
或 inf
值。此過濾器可以確定是否存在 nan
和 inf
,這是一種常見的用例,我們在 debug_data
模塊中包含了此過濾器。
注意:您還可以自行編寫自定義過濾器。要了解詳情,請參閱 DebugDumpDir.find()
的 API 文檔。
使用 tfdbg 調試模型訓練
我們嘗試再次訓練模型,但這次添加 --debug
標記:
python -m tensorflow.python.debug.examples.debug_mnist --debug
調試封裝容器會話會在將要執行第一次 Session.run()
調用時提示您,而屏幕上會顯示關於獲取的張量和 feed 字典的信息。
這就是我們所說的 run-start CLI。它先列出對當前 Session.run
調用的 feed 和 fetch,然后再執行任何操作。
如果因屏幕尺寸太小而無法顯示完整的消息內容,您可以調整屏幕大小。
使用 PageUp/PageDown/Home/End 鍵可以瀏覽屏幕上的輸出。在大部分沒有這些鍵的鍵盤上,使用 Fn + Up/Fn + Down/Fn + Right/Fn + Left 也可以。
在命令提示符處輸入 run
命令(或只輸入 r
):
tfdbg> run
run
命令會讓 tfdbg 一直執行,直到下一次 Session.run()
調用結束,而此調用會使用測試數據集計算模型的准確率。tfdbg 會擴展運行時圖來轉儲所有中間張量。運行結束后,tfdbg 會在 run-end CLI 中顯示所有轉儲的張量值。例如:
在執行 run
之后運行命令 lt
也可以獲得此張量列表。
tfdbg CLI 常用命令
在 tfdbg>
提示符處嘗試下列命令(參考 tensorflow/python/debug/examples/debug_mnist.py
中的代碼):
命令 | 語法或選項 | 說明 | 示例 |
---|---|---|---|
lt |
列出轉儲張量。 | lt |
|
-n <name_pattern> |
列出名稱符合指定正則表達式格式的轉儲張量。 | lt -n Softmax.* |
|
-t <op_pattern> |
列出指令類型符合指定正則表達式格式的轉儲張量。 | lt -t MatMul |
|
-f <filter_name> |
列出僅通過已注冊張量過濾器的張量。 | lt -f has_inf_or_nan |
|
-f <filter_name> -fenn <regex> |
列出僅通過已注冊張量過濾器的張量,不包括名稱符合正則表達式的節點。 | lt -f has_inf_or_nan -fenn .*Sqrt.* |
|
-s <sort_key> |
按指定的 sort_key 對輸出進行排序,該鍵可能的值為 timestamp (默認)、dump_size 、op_type 和 tensor_name 。 |
lt -s dump_size |
|
-r |
按相反的順序排序。 | lt -r -s dump_size |
|
pt |
輸出轉儲張量的值。 | ||
pt <tensor> |
輸出張量值。 | pt hidden/Relu:0 |
|
pt <tensor>[slicing] |
使用 Numpy 樣式的數組切片輸出張量的子數組。 | pt hidden/Relu:0[0:50,:] |
|
-a |
輸出整個大張量,而不使用省略號(對於大張量來說可能需要很長時間)。 | pt -a hidden/Relu:0[0:50,:] |
|
-r <range> |
突出顯示屬於指定數值范圍的元素。可以結合使用多個范圍。 | pt hidden/Relu:0 -a -r [[-inf,-1],[1,inf]] |
|
-n <number> |
輸出編號對應於指定轉儲編號(從 0 開始)的轉儲。具有多個轉儲的張量必須如此。 | pt -n 0 hidden/Relu:0 |
|
-s |
包括張量的數值摘要(僅適用於布爾型和數字型(例如 int* 和 float* )的非空張量)。 |
pt -s hidden/Relu:0[0:50,:] |
|
-w |
使用 numpy.save() 將張量(可能已切片)的值寫入 Numpy 文件 |
pt -s hidden/Relu:0 -w /tmp/relu.npy |
|
@[coordinates] |
轉到 pt 輸出中的指定元素。 |
@[10,0] 或 @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> |
評估 Python/Numpy 表達式,其中 np 表示 Numpy,調試張量名稱用反引號引起來。 |
eval "np.matmul((`output/Identity:0` / `Softmax:0`).T,`Softmax:0`)" |
|
-a |
輸出很長的完整評估結果,即不使用省略號。 | 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 |
列出節點中的調試轉儲。 | ni -d hidden/Relu |
|
-t |
顯示節點創建的 Python 堆棧追蹤。 | ni -t hidden/Relu |
|
li |
列出節點的輸入 | ||
-r |
遞歸地列出節點的輸入(輸入樹)。 | li -r hidden/Relu:0 |
|
-d <max_depth> |
在 -r 模式下限制遞歸深度。 |
li -r -d 3 hidden/Relu:0 |
|
-c |
包含控制輸入。 | li -c -r hidden/Relu:0 |
|
-t |
顯示輸入節點的指令類型。 | 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 |
顯示接收方節點的指令類型。 | 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 |
執行關於張量(而不是默認的節點)的注解。 | 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 (無需調試),然后在開始下一次運行之前進入 CLI。 |
run -n |
|
-t <T> |
執行 T - 1 次 Session.run (無需調試),接着執行一次運行(需要調試)。然后,在執行需要調試的運行之后進入 CLI。 |
run -t 10 |
|
-f <filter_name> |
繼續執行 Session.run ,直到任何中間張量觸發指定的張量過濾器(導致過濾器返回 True )為止。 |
run -f has_inf_or_nan |
|
-f <filter_name> -fenn <regex> |
繼續執行 Session.run ,直到其節點名稱不符合正則表達式的任何中間張量觸發指定的張量過濾器(導致過濾器返回 True )為止。 |
run -f has_inf_or_nan -fenn .*Sqrt.* |
|
--node_name_filter <pattern> |
執行下一次 Session.run ,僅查看名稱符合指定正則表達式格式的節點。 |
run --node_name_filter Softmax.* |
|
--op_type_filter <pattern> |
執行下一次 Session.run ,僅查看指令類型符合指定正則表達式格式的節點。 |
run --op_type_filter Variable.* |
|
--tensor_dtype_filter <pattern> |
執行下一次 Session.run ,僅轉儲數據類型 (dtype ) 符合指定正則表達式格式的張量。 |
run --tensor_dtype_filter int.* |
|
-p |
在分析模式下執行下一次 Session.run 調用。 |
run -p |
|
ri |
顯示有關運行當前運行的信息,包括 fetch 和 feed。 | ri |
|
config |
設置或顯示永久性 TFDBG 界面配置。 | ||
set |
設置配置項的值:{graph_recursion_depth , mouse_mode }。 |
config set graph_recursion_depth 3 |
|
show |
顯示當前的永久性界面配置。 | config show |
|
help |
輸出常規幫助信息 | help |
|
help <command> |
輸出指定命令的幫助信息。 | help lt |
請注意,每次輸入命令時,都會顯示新的屏幕輸出。這有點類似於瀏覽器中的網頁。您可以通過點擊 CLI 左上角附近的 <--
和 -->
文本箭頭在這些屏幕之間導航。
tfdbg CLI 的其他功能
除了上面列出的命令外,tfdbg CLI 還提供了下列其他功能:
- 要瀏覽之前的 tfdbg 命令,請輸入幾個字符,然后按向上或向下箭頭鍵。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
和 inf
在第一個 Session.run()
調用中,沒有出現存在問題的數值。您可以使用命令 run
或其簡寫形式 r
轉到下一次運行。
提示:如果您反復輸入
run
或r
,則將能夠依序在Session.run()
調用之間移動。您還可以使用
-t
標記一次向前移動多個Session.run()
調用,例如:tfdbg> run -t 10
在每次 Session.run()
調用之后,您無需重復輸入 run
並在 run-end 界面中手動搜索 nan
和 inf
(例如,通過使用上表中顯示的 pt
命令),而是可以使用以下命令讓調試程序反復執行 Session.run()
調用(不在 run-start 或 run-end 提示符處停止),直到第一個 nan
或 inf
值出現在圖中。這類似於一些程序式語言調試程序中的條件斷點:
tfdbg> run -f has_inf_or_nan
注意:上述命令可正常運行,因為在創建封裝會話時已為您注冊了一個名為
has_inf_or_nan
的張量過濾器。此過濾器會檢測nan
和inf
(如前所述)。如果您已注冊任何其他過濾器,則可以使用“run -f”讓 tfdbg 一直運行,直到任何張量觸發該過濾器(導致過濾器返回 True)為止。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
請參閱此 API 文檔,詳細了解與 add_tensor_filter()
搭配使用的謂詞 Callable
的預期簽名和返回值。
如屏幕所示,在第一行中,has_inf_or_nan
過濾器在第四次 Session.run()
調用期間第一次被觸發:Adam 優化器前向-后向訓練通過了圖。在本次運行中,36 個(共 95 個)中間張量包含 nan
或 inf
值。這些張量按時間先后順序列出,具體時間戳顯示在左側。在列表頂部,您可以看到第一次出現錯誤數值的第一個張量:cross_entropy/Log:0
。
要查看張量的值,請點擊帶下划線的張量名稱 cross_entropy/Log:0
或輸入等效命令:
tfdbg> pt cross_entropy/Log:0
向下滾動一點,您會發現一些分散的 inf
值。如果很難用肉眼找到出現 inf
和 nan
的地方,可以使用以下命令執行正則表達式搜索並突出顯示輸出:
tfdbg> /inf
或者:
tfdbg> /(inf|nan)
您還可以使用 -s
或 --numeric_summary
命令獲取張量中的數值類型的快速摘要:
tfdbg> pt -s cross_entropy/Log:0
您可以從摘要中看到 cross_entropy/Log:0
張量的若干個元素(共 1000 個)都是 -inf
(負無窮大)。
為什么會出現這些負無窮大的值?為了進一步進行調試,通過點擊頂部帶下划線的 node_info
菜單項或輸入等效的 node_info (ni
) 命令,顯示有關節點 cross_entropy/Log
的更多信息:
tfdbg> ni cross_entropy/Log
您可以看到,此節點的指令類型為 Log
,輸入為節點 Softmax
。運行以下命令可進一步查看輸入張量:
tfdbg> pt Softmax:0
檢查輸入張量中的值,並搜索其中是否存在零:
tfdbg> /0\.000
確實存在零。現在很明顯,錯誤數值的根源是節點 cross_entropy/Log
取零的對數。要在 Python 源代碼中找出導致錯誤的行,請使用 ni
命令的 -t
標記來顯示節點構造的回溯:
tfdbg> ni -t cross_entropy/Log
如果您點擊屏幕頂部的“node_info”,tfdbg 會自動顯示節點構造的回溯。
從回溯中可以看到該操作是在以下行構建的 - debug_mnist.py
:
diff = y_ * tf.log(y)
tfdbg 有一個可以輕松將張量和指令追溯到 Python 源文件中的行的功能。它可以用行創建的指令或張量注解 Python 文件的行。要使用此功能,只需點擊 ni -t <op_name>
命令的堆棧追蹤輸出中帶下划線的行編號,或者使用 ps
(或 print_source
)命令,例如:ps /path/to/source.py
。例如,以下屏幕截圖顯示了 ps
命令的輸出。
解決問題
要解決此問題,請修改 debug_mnist.py
,將原始行:
diff = -(y_ * tf.log(y))
更改為 softmax 交叉熵的在數值上穩定的內置實現:
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`
確認沒有任何張量被標記為包含 nan
或 inf
值,並且准確率現在繼續上升(而不是停滯不變)。大功告成!
調試 tf-learn Estimator 和 Experiment
本部分介紹了如何調試使用 Estimator
和 Experiment
API 的 TensorFlow 程序。這些 API 提供的部分便利性是它們在內部管理 Session
。這樣一來,上面的部分介紹的 LocalCLIDebugWrapperSession
就不適用了。幸運的是,您仍然可以使用 tfdbg
提供的特殊 hook
對其進行調試。
調試 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"]
debug_tflearn_iris.py(基於 tf-learn 的鳶尾花教程)包含如何搭配使用 tfdbg 和 Estimator
的完整示例。要運行此示例,請執行以下操作:
python -m tensorflow.python.debug.examples.debug_tflearn_iris --debug
調試 tf.contrib.learn Experiment
在 tf.contrib.learn
中,Experiment
是一個比 Estimator
更高級別的構造。它提供了用於訓練和評估模型的單個界面。為了調試對 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
還允許您配置 watch_fn
,后者可用於靈活指定在不同的 Session.run()
調用期間要查看哪些 Tensor
,這些調用作為 fetches
和 feed_dict
以及其他狀態的函數。如需了解詳情,請參閱此 API 文檔。
使用 TFDBG 調試 Keras 模型
要結合使用 TFDBG 和 Keras,請允許 Keras 后端使用 TFDBG 封裝的會話對象。例如,要使用 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()])
離線調試遠程運行的會話
您的模型往往在您沒有終端訪問權限的遠程機器或進程上運行。要在這種情況下調試模型,您可以使用 tfdbg
的 offline_analyzer
二進制文件(如下所述)。它在轉儲的數據目錄上運行。可以對較低階的 Session
API 以及較高階的 Estimator
和 Experiment
API 執行此操作。
調試遠程 tf.Sessions
如果您直接與 python
版 tf.Session
API 互動,則可以使用方法 tfdbg.watch_graph
配置 RunOptions
原型(您使用此原型調用 Session.run()
方法)。這樣一來,在發生 Session.run()
調用時,中間張量和運行時圖會被轉儲到您選擇的共享存儲位置(以降低性能為代價)。例如:
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
提供了一種更簡單、更靈活的方法來生成可離線分析的文件系統轉儲。要使用該方法,只需將您的會話封裝到 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
參數接受 Callable
,而后者允許您配置在不同的 Session.run()
調用期間要查看哪些 tensor
,這些調用作為 run()
調用的 fetches
和 feed_dict
及其他狀態的函數。
C++ 和其他語言
如果您的模型代碼是采用 C++ 或其他語言編寫的,則您還可以修改 RunOptions
的 debug_options
字段以生成可離線檢查的調試轉儲。要了解詳情,請參閱原型定義。
調試遠程運行的 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
示例一樣的方法使用此 hook
。在訓練和/或評估 Estimator
或 Experiment
期間,tfdbg 會創建具有以下名稱格式的目錄:/shared/storage/location/tfdbg_dumps_1/run_<epoch_timestamp_microsec>_<uuid>
。每個目錄對應一個 Session.run()
調用,而此調用會成為 fit()
或 evaluate()
調用的基礎。您可以使用 tfdbg 提供的 offline_analyzer
加載這些目錄並以離線方式在命令行界面中進行檢查。例如:
python -m tensorflow.python.debug.cli.offline_analyzer \
--dump_dir="/shared/storage/location/tfdbg_dumps_1/run_<epoch_timestamp_microsec>_<uuid>"
常見問題解答
問:lt
輸出左側的時間戳是否反映了非調試會話的實際性能?
答:否。調試程序在圖中插入了其他特殊用途的調試節點來記錄中間張量的值。這些節點減緩了圖的執行。如果您對分析模型感興趣,請查看:
- tfdbg 的分析模式:
tfdbg> run -p
。 - tfprof 和 TensorFlow 的其他分析工具。
問:如何在 Bazel 中將 tfdbg 與我的 Session
關聯起來?為什么我會看到“ImportError: cannot import name debug”這樣的錯誤?
答:在您的 BUILD 規則中,聲明依賴項 "//tensorflow:tensorflow_py"
和 "//tensorflow/python/debug:debug_py"
。所包含的第一個依賴項讓您即使沒有調試程序支持也可以使用 TensorFlow;第二個用於啟用調試程序。然后,在您的 Python 文件中,添加:
from tensorflow.python import debug as tf_debug
# Then wrap your TensorFlow Session with the local-CLI wrapper.
sess = tf_debug.LocalCLIDebugWrapperSession(sess)
問:tfdbg 是否可以幫助調試運行時錯誤(例如形狀不匹配)?
答:可以。tfdbg 在運行時期間會攔截指令生成的錯誤,並在 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
問:如何讓 tfdbg 封裝的會話或鈎子僅通過主線程運行調試模式?
答:這是一個常見用例,其中 Session
對象同時在多個線程中使用。通常情況下,子線程負責后台任務,例如運行入列指令。您通常僅需要調試主線程(或者不太頻繁地僅調試一個子線程)。您可以使用 LocalCLIDebugWrapperSession
的 thread_name_filter
關鍵字參數實現這種類型的線程選擇性調試。例如,您要僅通過主線程進行調試,請按如下方式構造一個封裝的 Session
:
sess = tf_debug.LocalCLIDebugWrapperSession(sess, thread_name_filter="MainThread$")
以上示例的前提是 Python 中的主線程具有默認名稱 MainThread
。
問:我正在調試的模型非常大。tfdbg 轉儲的數據占滿了磁盤的可用空間。我該怎么做?
答:出現以下任何情況,您都可能會遇到此問題:
- 模型具有很多中間張量
- 中間張量非常大
- 很多
tf.while_loop
迭代
有三種可能的解決方案:
LocalCLIDebugWrapperSession
和LocalCLIDebugHook
的構造函數提供了一個關鍵字參數dump_root
,用於指定 tfdbg 轉儲調試數據的路徑。您可以使用此參數讓 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.*
的節點。上面的第二個命令僅查看名稱符合格式Variable.*
的操作。上面的第三個命令僅查看 dtype 符合格式int.*
(例如int32
)的張量。
問:為什么不能在 tfdbg CLI 中選擇文本?
答:這是因為 tfdbg CLI 默認在終端中啟用了鼠標事件。此 mouse-mask 模式會替換默認的終端交互,包括文本選擇。您可以通過使用命令 mouse off
或 m off
來重新啟用文本選擇。
問:為什么我在調試如下代碼時,tfdbg CLI 沒有顯示轉儲的張量?
a = tf.ones([10], name="a")
b = tf.add(a, a, name="b")
sess = tf.Session()
sess = tf_debug.LocalCLIDebugWrapperSession(sess)
sess.run(b)
答:您之所以沒有看到轉儲數據,是因為執行的 TensorFlow 圖中的每個節點都由 TensorFlow 運行時進行了常數折疊處理。在本示例中,a
是一個常數張量;因此,已獲取的張量 b
其實也是一個常數張量。TensorFlow 的圖優化將包含 a
和 b
的圖折疊成單個節點,以加快圖的未來運行速度,因此,tfdbg
不會生成任何中間張量轉儲。不過,如果 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)
則不會發生常數折疊,tfdbg
應顯示中間張量轉儲。
問:我正在調試一個產生垃圾無窮數或 NaN 的模型。但是,我的模型中有一些節點已知會在輸出張量中產生無窮值或 NaN,即使在完全正常的條件下也是如此。我如何在 run -f has_inf_or_nan
操作期間跳過這些節點?
答:使用 --filter_exclude_node_names
(簡稱為 -fenn
)標記。例如,如果您知道您有一個名稱符合正則表達式 .*Sqrt.*
的節點,無論模型是否正常運行,該節點都會產生無窮數或 NaN,那么您可以使用命令 run -f has_inf_or_nan -fenn .*Sqrt.*
,將節點從無窮數/NaN-finding 運行中排除。
問:是否有用於 tfdbg 的 GUI?
答:有,TensorBoard 調試程序插件就是 tfdbg 的 GUI。它提供了諸如計算圖檢查、張量值實時可視化、張量連續性和條件性斷點以及將張量關聯到其圖形構建源代碼等功能,所有這些功能都在瀏覽器環境中運行。要開始使用,請訪問相關 README 文件。
Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 3.0 License, and code samples are licensed under the Apache 2.0 License. For details, see our Site Policies. Java is a registered trademark of Oracle and/or its affiliates.
上次更新日期:七月 9, 2018