Boxx:一個旨在提高 Python 程式碼開發和除錯效率的工具庫,尤其在計算機視覺領域

DIYer22發表於2019-03-04

介紹一個Python 工具包 boxx

在除錯視覺程式碼時, 基本就是和多維陣列打交道, 多維陣列有很多的屬性,列印起來比較麻煩。 boxx.loga 可以一次性展現出一個陣列的大多數屬性.

Boxx:一個旨在提高 Python 程式碼開發和除錯效率的工具庫,尤其在計算機視覺領域

? Note:

  • loga 是 "log array" 的縮寫, 若 array 裡面還含有 naninf, loga 也會一併提示出來。
  • loga 支援許多可以轉為 numpy 的資料型別,包括 torch.tensor, mxnet.ndarray, PIL.Image 等。

做計算機視覺,視覺化影象和 feature 非常重要。boxx.show 能方便地做視覺化。

Boxx:一個旨在提高 Python 程式碼開發和除錯效率的工具庫,尤其在計算機視覺領域

? Note: show 會在複雜的資料結構中 找出所有可能是影象的矩陣,並一一顯示(plt.imshow)出來。 當然,show 也支援 numpytorchmxnetPIL.Image .etc

在開發 CV 程式碼時,會遇到一些複雜的 dict,list(比如 batch、模型引數)。boxx.tree 可以直觀地展示覆雜結構。

Boxx:一個旨在提高 Python 程式碼開發和除錯效率的工具庫,尤其在計算機視覺領域

? Note: 在理解和適配別人的程式碼時,經常用到 treetree 還支援自動從 torch.Dataloader/Dataset 中 sample 一個 batch 來視覺化 (P.S. boxx.show 也支援)


以上三個工具是我在視覺領域經常用到的工具, 接下來介紹一些通用的 Python 開發除錯工具,只要寫 Python 程式碼,都可以用上。

列印變數是最簡單、直接的debug方式, 那能不能更簡單?

Boxx:一個旨在提高 Python 程式碼開發和除錯效率的工具庫,尤其在計算機視覺領域

? Note: boxx.p 使用了 magic method, p/x 便會列印 x 並返回 x。這樣便可以在任何地方列印,比如 例子中的 p/randint(0, 3) 就不需要新建變數便可直接列印

在函式內執行 p(),便會將函式或 module 內的所有變數名和值一同列印(相當於快捷列印 locals())

Boxx:一個旨在提高 Python 程式碼開發和除錯效率的工具庫,尤其在計算機視覺領域

? Note: 在函式內 import boxx.pp() 有相同的效果

許多數情況下, 直接 print 無法獲得除錯的關鍵資訊。 比如訓練 loss 跑飛了, 導致 Bug 的可能是 tensor 的尺度/型別不對, 矩陣裡有 nan , inf 等情況。我曾遇到過 梯度含有nan 的情況

這時 就必須對矩陣進行分析, 方式有:

  1. 在除錯處加上 print(x.mean(), np.hasinf(x),.np.hasnan(x))
  2. 設定斷點進行分析

方法1 每改一次除錯程式碼 都要執行整個程式碼, 不靈活,操作也繁瑣。
方法2 中進入和退出 Debug console 比較麻煩,Debug console 本身也不太好用(沒有自動補全功能)
boxx.g 提供了一種新的方式,通過 g.name 可以將變數傳到當前的 Python 互動終端

Boxx:一個旨在提高 Python 程式碼開發和除錯效率的工具庫,尤其在計算機視覺領域

變數傳到 Python 終端後,就能對變數進行全面分析了,比如 使用 logatree 來分析

? Note:

  • gg 的意思是 to Global and log, 和 g 的用法一樣, 但 gg 會在傳輸的同時列印變數.
  • 需要注意, 如果之前在終端中存在一樣的變數名稱,則變數的值會被新值覆蓋.

在函式內執行 g(),便會將函式 (或 module) 內的所有變數一同傳到當前的 Python 互動終端

Boxx:一個旨在提高 Python 程式碼開發和除錯效率的工具庫,尤其在計算機視覺領域

這樣 任何錯誤都可以在終端中復現和分析了。當然, 注意不要覆蓋重要的全域性變數。

? Note: 在函式內 import boxx.gg() 有相同的效果

在實際開發除錯中, 函式或 module 內可能含有非常多的變數 但我們只對幾個變數感興趣, with p, with g, with gg 可以使操作只作用於幾個感興趣的變數,只需把變數放入 with 結構中即可 :

Boxx:一個旨在提高 Python 程式碼開發和除錯效率的工具庫,尤其在計算機視覺領域

? Note:

  • with p, with g, with gg 只作用於在 with 結構中進行賦值操作的變數.
  • 如果變數名在 with 前存在於 locals() 中, 同時 id(變數) 沒有變化 , with 結構可能無法檢測到該變數.

總結一下,boxx 的除錯工具可以彙總為一個表

boxx 除錯工具矩陣

變數個數 \ 操作 print transport print & transport
單變數 p/x g.name/x gg.name/x
多變數 with p: with g: with gg:
locals() p() g() gg()
locals()_2 import boxx.p import boxx.g import boxx.gg

? Note:

  • transport 操作是指 把函式內的變數傳送到 Python interactive console 中
  • locals() 指 作用於函式或 module 內的所有變數
  • locals()_2: 當 boxx 未匯入時, import boxx.{操作} 能等價於 from boxx import {操作};{操作}()

在學習新框架或適配大佬程式碼時,經常會使用 print(x), dir(x), help(x), type(x) 來了解某個變數的各方面的資訊 (變數可能是 值/function/class/module 等),於是我寫了一個 boox.what(x) 來全面瞭解"what is x?":

Boxx:一個旨在提高 Python 程式碼開發和除錯效率的工具庫,尤其在計算機視覺領域

? Note: what(x) 通過列印 x 自己及x文件, 父類繼承關係, 內部結構所有屬性 來全面瞭解 x. 是 help(x) 的補充.


說了這麼多除錯 再說一下效能調優

測試程式碼效能時,計時很常用, 我寫了一個方便的計時工具boxx.timeit 將想要計時的程式碼塊放入 with timeit(): 中就可以計時了:

Boxx:一個旨在提高 Python 程式碼開發和除錯效率的工具庫,尤其在計算機視覺領域

此外 SnakeViz 是一個很棒的效能分析工具,SnakeViz 能夠通過 cProfile 檔案,來統計程式碼的函式呼叫情況,並視覺化出程式碼的 火焰圖。但是, 先生成 cProfile 檔案,再執行 SnakeViz 的流程非常繁瑣,我把這一套操作封裝成了 boxx.performance 來簡化流程:

Boxx:一個旨在提高 Python 程式碼開發和除錯效率的工具庫,尤其在計算機視覺領域

? Note: performance 也支援字串形式的 Python 程式碼.

如今的資料集都數百上千 GB,在資料清洗和預處理時 要寫多程式的 Python 程式碼 來榨乾 CPU 的每一個執行緒獲得加速。但我覺得 Python 多程式的幾個正規化都不夠方便,我參照 map 的思想和用法把多程式操作封裝成 boxx.mapmp 函式(意思是"Map for Mulit Processing"). mapmpmap 有一樣的用法, 只需把 map 替換為 mapmp 即可獲得多程式加速:

Boxx:一個旨在提高 Python 程式碼開發和除錯效率的工具庫,尤其在計算機視覺領域

? Note:

  • mapmppool 引數來控制程式數目,預設為 CPU 執行緒數目.
  • 在多程式程式中, 列印進度往往非常麻煩. mapmpprintfreq 引數能解決這個問題.
  • 如同 map 一樣,mapmp 支援將多個引數輸入函式,如mapmp(add, list_1, list_2)
  • 在 Python 中,多程式程式碼最好在 __name__ == '__main__' 環境中執行.
  • 如果加速 numpy 程式,請注意 在 MKL 版本的 numpy 中,多程式會更慢, 可以執行 boxx.testNumpyMultiprocessing() 來測試當前環境對多程式 numpy 的友好程度

當要下載 url 形式的資料集或網路爬取圖片時,多執行緒程式設計對這類高IO操作會很有用。boxx 還有個多執行緒版本的 map -- mapmt (意思是 "Map for Mulit Threading")。mapmt 用法和 mapmp 一樣, 但沒有多程式的諸多限制。


再分享一下我自己在寫視覺程式碼的感受吧

由於我自己

  1. 寫 CV 程式碼離不開強大的 Qt console for IPython
  2. 受不了遠端編輯對網路的依賴和延遲

所以 一直用 Anaconda 自帶的 Spyder 作為 Python 開發的 IDE. Spyder 雖然不夠強大,但自帶的 Qt-IPython, 配合自己寫的工具,除錯起來還是比較方便, 順手。所以, 我開發的工具都儘可能地直接, 簡潔,上面介紹的大部分工具都支援 func-x 來代替 func(x) 以方便除錯時呼叫。甚至,我還寫了一些字串處理工具,直接在IPython 內使用, 以彌補 Spyder 作為 IDE 的不足。

此外,我的工作流一般是 先在本地開發除錯, 用 boxx.sysi 檢測執行環境來自動切換執行引數, 本地開發除錯 OK 了, 用 rsync 命令 只傳改過的 .py 檔案到伺服器 再來 train。雖然這樣傳程式碼比較麻煩, 但開發, 除錯起來會方便很多。

之前在實驗室一直是本地 GPU 環境除錯 比較方便。實習後, 曠廠不提供本地 GPU。我主力是 PyTorch, 為了方便除錯 我寫了個 boxx.ylth 包,如果檢測到沒有 CUDA 環境,boxx.ylth 會強行使 .cuda() 和大部分 GPU 操作無效。只要在程式碼開頭 import boxx.ylth 大多數只基於 GPU 的 torch 程式碼, 可以不經更改 直接在 CPU 上執行和除錯。(這操作太暴力 請慎用)


GitHub 主頁:github.com/DIYer22/box…

安裝:pip install git+https://github.com/DIYer22/boxx (其他安裝方法及說明)

教程:boxx 的教程是一個可執行的線上 Notebook。 也就是說,無需下載和執行任何程式碼,只需瀏覽器點選下面的連結,就可以線上執行 Notebook 教程中的程式碼塊。
=> 可直接執行的線上教程

最後 特別感謝徐曉棟、吳國棟、範浩強和熊鵬飛對 boxx 提出的建議。

相關文章