標籤:

TensorFlow 的 debug 工具 tfdbg 使用

之前經歷過一次極其痛苦的網路訓練出現了 NaN 值的經歷,期間用上了tfdbg也沒有能找出了究竟為何會出現這種情況,最後還是在組員的幫助下才解決,這次經歷讓我對 TensorFlow 的 debug 深有恐懼,所以,這一篇長文會比較詳細的學習怎麼更好的使用這個官方的 debug 工具。

由於TensorFlow 使用的符號編碼的特徵,使得我們使用通用調試器(如Python的pdb)難以進行調試,所以谷歌官方提供了一個 TensorFlow調試器(tfdbg),它是TensorFlow的專用調試器。它允許我們在訓練和前向推導期間查看運行的 Graph 的內部結構和狀態,

註:tfdbg 的運行依賴以下庫。Mac OS X 的 ncurses 。在 Windows 上需要 pyreadline ,不過一般來說如果是使用的 pip 安裝的 TensorFlow,這個問題都不會存在。

tfdbg 在 TensorFlow 中的基本使用

第一步是用一個調試器包裝來包裝原有的 Session 對象:

from tensorflow.python import debug as tf_debugsess = tf_debug.LocalCLIDebugWrapperSession(sess)

這個包裝後的 session 與原有的 Session 具有相同的介面,因此啟用調試時不需要對代碼進行其他更改。

另外這個包裝提供了額外的功能,包括:

  • 在Session.run()調用之前和之後調用CLI,讓我們可以檢查 Graph 的內部狀態。
  • 允許我們為某個張量 tensor 註冊特殊過濾器 filters ,以便於診斷問題。

最常用的就是 tfdbg.has_inf_or_nan 的張量過濾器 filters ,它可以確定張量中是否有nan或inf值,如果註冊了這種過濾器,程序會在運行第一次出現了 nan 或者 inf 的時候停下來,然後你就可以查看計算圖 Graph 的各個細節,以確定是哪裡出了問題;另外也可以編寫自己的自定義過濾器,比如我們要過濾是否出現了某個特定的值。

我們先看看不提供過濾器,僅僅只是查看模型運行時候的情況,也就是只把上面二個語句加入原有代碼裡面,然後在命令行裡面運行該 Python 代碼,就會進入 tfdbg 的命令行界面:

會出現模型的輸入 feed dict 和輸出,也就是在 session 中要獲取 fetch 的信息;

如果顯示不完整,使用 PageUp / PageDown / Home / End 來翻頁,也可以使用 Fn + Up / Fn + Down / Fn + Right / Fn + Left

然後我們就可以在上面圖片最後一行位置的 tfdbg> 的後面輸入一些命令來控制這個工具了,比如最常用的:

tfdbg> run

這個命令會執行計算圖知道下一個 sess.run(),然後會顯示所有的中間變數的信息:

請注意,每次輸入命令時,都會顯示一個新的屏幕輸出。 這有點類似於瀏覽器中的網頁。 通過單擊 CLI 左上角的 < - 和 - >文本箭頭,可以在這些屏幕之間導航。不過如果界面模式ui_type是滑鼠點擊 curses 才可以,如果是 readline 就不行。

常用的 tfdbg 命令如下表:

此外,tfdbg CLI還提供了以下附加功能:

  • 要瀏覽以前的tfdbg命令,輸入幾個字元,然後按向上或向下箭頭鍵。 tfdbg將顯示以這些字元開始的命令的歷史記錄。
  • 使用prev和next命令,或者點擊屏幕左上角附近的帶有下劃線的< - 和 - >鏈接,瀏覽屏幕輸出的歷史記錄
  • Tab完成命令和一些命令參數。
  • 可以使用管道語法將屏幕輸出重定向到文件而不是屏幕

tfdbg> pt cross_entropy/Log:0[:, 0:10] > /tmp/xent_value_slices.txt

下面內容演示如何使用 tfdbg 命令行界面(CLI)調試nans和infs的錯誤,這是TensorFlow 訓練中經常遇到的二種錯誤情況。

以下語句會運行 TensorFlow,直到第一個nan或inf值出現。這類似於某些過程式語言調試器中的條件斷點:

tfdbg> run -f has_inf_or_nan

這個命令可以正常工作是因為在之前包裝session時已經註冊名為 has_inf_or_nan 的張量過濾器。這個過濾器檢測nans和infs 。如果需要運行自定義的過濾器,使用如下語法:

def my_filter_callable(datum, tensor): # 定義過濾 0 值 return len(tensor.shape) == 0 and tensor == 0.0# 在 session 中添加過濾器sess.add_tensor_filter(my_filter, my_filter_callable) # 運行過濾器tfdbg> run -f my_filter

以這個結果圖片為例,當屏幕最頂端顯示 #4 ,表示 has_inf_or_nan 過濾器在第四個Session.run()調用期間被觸發,觸發過程出現在 Adam 優化器中,總共36個 tensor 包含nan或inf值,這些張量按時間順序排列,左邊顯示時間戳,其中錯誤的數值首先出現: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_petropy / Log:0張量的1000個元素中的幾個是-infs

為什麼出現這些無窮大?要進一步調試檢查,通過單擊頂部帶下劃線的node_info菜單項或輸入相應的node_info(ni)命令來顯示有關節點cross_entropy / Log的更多信息:

tfdbg> ni cross_entropy / Log

你可以看到這個節點的操作類型為Log,輸入是節點softmax / Softmax。運行以下命令仔細查看輸入張量:

tfdbg> softmax / Softmax:0

檢查輸入張量中的值,搜索零:

tfdbg> /0.000

確實有零。現在很明顯的是,0數值的起源是節點cross_entropy / Log,通過查找零的日誌,要找出Python源代碼中的罪魁禍首,使用ni命令的-t標誌來顯示節點構造的起源信息:

tfdbg> ni -t cross_entropy / Log

從回溯查找中,可以看到操作 op 在以下行構建:debug_mnist.py:

diff = y_ * tf.log(y)

tfdbg 可以很容易地將張量tensor和操作OP 的創建過程跟蹤回溯到Python源文件中的代碼行,只要使用ps(或print_source)命令,例如:ps /path/to/source.py:

要解決這個問題,只需要改變原來自己定義的計算交叉熵的公式:

diff = - (y_ * tf.log(y))

把它改成TensorFlow 定義的比較穩定的 softmax 交叉熵函數:

diff = tf.nn.softmax_cross_entropy_with_logits(labels = y_,logits = logits)

然後再運行 debug:

run -f has_inf_or_nan

確認沒有張量被標記為包含nan值或inf值,並且模型指標表現正常,表示已經解決了這個問題。

參考資料:Debugging TensorFlow Programs | TensorFlow

推薦閱讀:

Quo Vadis, Action Recognition? A New Model and the Kinetics
tensorflow讀取數據-tfrecord格式
TensorFlow會話的配置項
TensorFlow識別字母扭曲干擾型驗證碼-開放源碼與98%模型
學習筆記TF058:人臉識別

TAG:TensorFlow |