介紹一個Python 工具包 boxx
html
在調試視覺代碼時, 基本就是和多維數組打交道, 多維數組有不少的屬性,打印起來比較麻煩。 boxx.loga
能夠一次性展示出一個數組的大多數屬性.
python
💡 Note:git
loga
是 "log array" 的縮寫, 若 array
裏面還含有 nan
或 inf
, loga
也會一併提示出來。loga
支持許多能夠轉爲 numpy
的數據類型,包括 torch.tensor
, mxnet.ndarray
, PIL.Image
等。作計算機視覺,可視化圖像和 feature 很是重要。boxx.show
能方便地作可視化。
github
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
結構中便可 :
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:
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
?":
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
便可得到多進程加速:
mapmp
的 pool 參數來控制進程數目,默認爲 CPU 線程數目.mapmp
的 printfreq 參數能解決這個問題.map
同樣,mapmp
支持將多個參數輸入函數,如mapmp(add, list_1, list_2)
__name__ == '__main__'
環境中運行.numpy
程序,請注意 在 MKL 版本的 numpy
中,多進程會更慢, 能夠運行 boxx.testNumpyMultiprocessing()
來測試當前環境對多進程 numpy
的友好程度當要下載 url 形式的數據集或網絡爬取圖片時,多線程編程對這類高IO操做會頗有用。boxx
還有個多線程版本的 map
-- mapmt
(意思是 "Map for Mulit Threading")。mapmt
用法和 mapmp
同樣, 但沒有多進程的諸多限制。
再分享一下我本身在寫視覺代碼的感覺吧
因爲我本身
因此 一直用 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
提出的建議。