介紹一個Python 工具包 boxx
在除錯視覺程式碼時, 基本就是和多維陣列打交道, 多維陣列有很多的屬性,列印起來比較麻煩。 boxx.loga
可以一次性展現出一個陣列的大多數屬性.
? Note:
loga
是 "log array" 的縮寫, 若array
裡面還含有nan
或inf
,loga
也會一併提示出來。loga
支援許多可以轉為numpy
的資料型別,包括torch.tensor
,mxnet.ndarray
,PIL.Image
等。
做計算機視覺,視覺化影象和 feature 非常重要。boxx.show
能方便地做視覺化。
? Note:
show
會在複雜的資料結構中 找出所有可能是影象的矩陣,並一一顯示(plt.imshow
)出來。 當然,show
也支援 numpy
,torch
,mxnet
,PIL.Image
.etc
在開發 CV 程式碼時,會遇到一些複雜的 dict,list(比如 batch、模型引數)。boxx.tree
可以直觀地展示覆雜結構。
? Note: 在理解和適配別人的程式碼時,經常用到 tree
。tree
還支援自動從 torch.Dataloader/Dataset
中 sample 一個 batch 來視覺化 (P.S. boxx.show
也支援)
以上三個工具是我在視覺領域經常用到的工具, 接下來介紹一些通用的 Python 開發除錯工具,只要寫 Python 程式碼,都可以用上。
列印變數是最簡單、直接的debug方式, 那能不能更簡單?
? Note: boxx.p
使用了 magic method, p/x
便會列印 x 並返回 x。這樣便可以在任何地方列印,比如 例子中的 p/randint(0, 3)
就不需要新建變數便可直接列印
在函式內執行 p()
,便會將函式或 module 內的所有變數名和值一同列印(相當於快捷列印 locals()
)
? Note: 在函式內 import boxx.p
和 p()
有相同的效果
許多數情況下, 直接 print
無法獲得除錯的關鍵資訊。 比如訓練 loss 跑飛了, 導致 Bug 的可能是 tensor
的尺度/型別不對, 矩陣裡有 nan , inf 等情況。我曾遇到過 梯度含有nan 的情況
這時 就必須對矩陣進行分析, 方式有:
- 在除錯處加上
print(x.mean(), np.hasinf(x),.np.hasnan(x))
- 設定斷點進行分析
方法1 每改一次除錯程式碼 都要執行整個程式碼, 不靈活,操作也繁瑣。
方法2 中進入和退出 Debug console 比較麻煩,Debug console 本身也不太好用(沒有自動補全功能)
boxx.g
提供了一種新的方式,通過 g.name
可以將變數傳到當前的 Python 互動終端
變數傳到 Python 終端後,就能對變數進行全面分析了,比如 使用 loga
,tree
來分析
? Note:
gg
的意思是to Global and log
, 和g
的用法一樣, 但gg
會在傳輸的同時列印變數.- 需要注意, 如果之前在終端中存在一樣的變數名稱,則變數的值會被新值覆蓋.
在函式內執行 g()
,便會將函式 (或 module) 內的所有變數一同傳到當前的 Python 互動終端
這樣 任何錯誤都可以在終端中復現和分析了。當然, 注意不要覆蓋重要的全域性變數。
? Note: 在函式內 import boxx.g
和 g()
有相同的效果
在實際開發除錯中, 函式或 module 內可能含有非常多的變數 但我們只對幾個變數感興趣, with p
, with g
, with gg
可以使操作只作用於幾個感興趣的變數,只需把變數放入 with
結構中即可 :
? Note:
with p
,with g
,with gg
只作用於在with
結構中進行賦值操作的變數.- 如果變數名在
with
前存在於locals()
中, 同時id(變數)
沒有變化 ,with
結構可能無法檢測到該變數.
總結一下,boxx
的除錯工具可以彙總為一個表
boxx
除錯工具矩陣
變數個數 \ 操作 | 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
?":
? Note:
what(x)
通過列印 x
自己及x
的 文件, 父類繼承關係, 內部結構 及 所有屬性 來全面瞭解 x
. 是 help(x)
的補充.
說了這麼多除錯 再說一下效能調優
測試程式碼效能時,計時很常用, 我寫了一個方便的計時工具boxx.timeit
將想要計時的程式碼塊放入 with timeit():
中就可以計時了:
此外 SnakeViz
是一個很棒的效能分析工具,SnakeViz
能夠通過 cProfile
檔案,來統計程式碼的函式呼叫情況,並視覺化出程式碼的 火焰圖。但是, 先生成 cProfile
檔案,再執行 SnakeViz
的流程非常繁瑣,我把這一套操作封裝成了 boxx.performance
來簡化流程:
? Note: performance
也支援字串形式的 Python 程式碼.
如今的資料集都數百上千 GB,在資料清洗和預處理時 要寫多程式的 Python 程式碼 來榨乾 CPU 的每一個執行緒獲得加速。但我覺得 Python 多程式的幾個正規化都不夠方便,我參照 map
的思想和用法把多程式操作封裝成 boxx.mapmp
函式(意思是"Map for Mulit Processing"). mapmp
和 map
有一樣的用法, 只需把 map
替換為 mapmp
即可獲得多程式加速:
? Note:
mapmp
的 pool 引數來控制程式數目,預設為 CPU 執行緒數目.- 在多程式程式中, 列印進度往往非常麻煩.
mapmp
的 printfreq 引數能解決這個問題. - 如同
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
一樣, 但沒有多程式的諸多限制。
再分享一下我自己在寫視覺程式碼的感受吧
由於我自己
- 寫 CV 程式碼離不開強大的 Qt console for IPython
- 受不了遠端編輯對網路的依賴和延遲
所以 一直用 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
提出的建議。