如何管理和組織一個機器學(xué)習(xí)項目
本文主要分享一些組織管理機器學(xué)習(xí)項目的實踐經(jīng)驗。
Python
Python 是機器學(xué)習(xí)項目開發(fā)的主要使用語言之一。它包含了大量的庫/包可以用于機器學(xué)習(xí):
- numpy:適用于多維數(shù)組、數(shù)值計算。常用于數(shù)據(jù)處理。
- pandas:數(shù)據(jù)分析常用庫。pandas dataframes本質(zhì)上是numpy數(shù)組,它用描述性字符串作為行和列標簽。數(shù)據(jù)在pandas dataframes里可以很容易進行排序、過濾、分組、連接等操作,這對數(shù)據(jù)處理很有用。
- PyTorch:用于構(gòu)建神經(jīng)網(wǎng)絡(luò)。包括許多預(yù)訓(xùn)練模型和計算機視覺數(shù)據(jù)集。Pytorch鼓勵使用面向?qū)ο蟮木幊?,用Pytorch編寫代碼很快,而且Pytorch默認支持快速執(zhí)行,因此可以與Python調(diào)試器一起使用。
- TensorFlow:在工業(yè)上更受歡迎的Pytorch的替代品。Pytorch更適合做研究。如果您想使用TensorFlow,并且想要一個更高級別的接口,那么可以使用Keras。
- scikit-learn:這是一個很好的庫,用于回歸、支持向量機、k近鄰、隨機森林、計算混淆矩陣等。
- matplotlib、seaborn:用于數(shù)據(jù)可視化的常用庫之一。
Git
Git版本控制對于機器學(xué)習(xí)項目的組織管理非常有用。
Git是一種可以用來跟蹤對代碼所做的所有更改的工具。Git"repository"是一個包含代碼文件的目錄。Git使用節(jié)省存儲空間的技術(shù),因此它不存儲代碼的多個副本,而是存儲舊文件和新文件之間的相對更改。Git有助于保持代碼文件目錄的整潔和組織,因為只有最新版本才顯示存在(盡管您可以隨時輕松訪問代碼的任何版本)。使用者可以選擇發(fā)生的更改,使用"commit"將代碼的特定更改與相關(guān)的書面描述捆綁在一起。Git存儲庫也使共享代碼和協(xié)作變得更加容易??偟膩碚f,比起保存"myscriptv1.py"、"dataprocessingv56.py"、"utils_73.py"等上百萬個不同版本的代碼,Git是一個更好的方法來保存舊代碼。
Git版本控制可以通過GitHub、GitLab和Bitbucket來實現(xiàn)。我最常使用GitHub。

使用GitHub的方法如下:
- 安裝Git
- 注冊一個GitHub賬戶
- 通過SSH鏈接個人GitHub賬戶和個人電腦。以便于隨時能夠?qū)⒋a上傳并保存在云端。
- 單擊概要文件的"Repositories"部分中的綠色"new"按鈕,在GitHub上創(chuàng)建一個新的存儲庫。
- 使個人計算機能夠?qū)⒋a推送到該存儲庫(以下是示例命令):
- echo "# pytorch-computer-vision" >> README.md
- git init git add README.md
- git commit -m "first commit"
- git branch -M master git remote add origin https://github.com/rachellea/pytorch-computer-vision.git
- git push -u origin master
假設(shè)現(xiàn)在myeditedscript.py有代碼做出了更改,可以通過commit進行版本管理:
- git add myeditedscript.py
- git commit -m 'added super useful functionality'
- git push origin master
Anaconda
Anaconda支持創(chuàng)建不同的環(huán)境,這些環(huán)境可能包含不同的Python版本和不同的包版本。當我們在處理多個具有沖突依賴關(guān)系的項目時,Anaconda特別有用。
使用Anaconda很簡單:
首先,安裝Anaconda
然后,創(chuàng)建環(huán)境。用所在的項目來命名環(huán)境是比較好的。例如,如果該項目是關(guān)于使用神經(jīng)網(wǎng)絡(luò)進行胸部x光分類的,則該環(huán)境可以稱為chestxraynn:
- conda create --name chestxraynn python=3.5
請注意,避免在環(huán)境名稱周圍加引號,否則引號字符本身將是環(huán)境名稱的一部分。此外,可以選擇任何版本的Python。它不一定是python3.5。
一旦環(huán)境被創(chuàng)建,就是激活環(huán)境的時候了。"激活"僅僅意味著你將被"放入環(huán)境中",這樣你就可以使用安裝在里面的所有軟件。Windows激活命令如下:
- activate chestxraynn
Linux/macOS激活命令如下:
- source activate chestxraynn
使用"conda install"命令在環(huán)境中安裝包。以安裝matplotlib為例:
- conda install -c conda-forge matplotlib
從技術(shù)上講,在conda環(huán)境中,也可以使用pip安裝包,但這可能會導(dǎo)致問題,因此應(yīng)盡量避免。
Anaconda將負責(zé)確保環(huán)境中所有內(nèi)容的版本都是兼容的。更多命令見Conda Cheat Sheet。
也可以直接使用別人的命令文件創(chuàng)建conda環(huán)境。在GitHub中g(shù)ithub/rachellea/pytorch-computer-vision, 有一個tutorial_environment.yml文件,此文件指定運行教程代碼所需的依賴項。要基于此文件創(chuàng)建conda環(huán)境,只需在Anaconda提示符中運行以下命令:
- conda env create -f tutorial_environment.yml
代碼管理:類和函數(shù)
代碼管理非常重要。當數(shù)千行的代碼,沒有文件說明,中間到處都是重復(fù)的代碼塊,一些代碼塊沒有解釋就注釋掉了,還有各種奇怪的變量名,這簡直就是一場災(zāi)難。
而Pytorch實現(xiàn)中通常看到的所有代碼都是有組織的,并且有很好的說明記錄。
從長遠來看,如果為自己的項目編寫高質(zhì)量的代碼,將節(jié)省大量時間。高質(zhì)量代碼的一個方面是它在模塊中的組織和管理。
代碼管理建議:
- 面向?qū)ο缶幊?。強烈推薦使用PyTorch機器學(xué)習(xí)框架,因為它有助于為所有事情使用面向?qū)ο蟮木幊獭ytorch中,模型是一個類,數(shù)據(jù)集也是一個類。
- 使用函數(shù)。如果你寫的東西不能作為一個類很好地工作,那么把代碼組織成函數(shù)。函數(shù)是可重用的。

代碼管理示意圖
代碼管理:目錄
使用多個模塊來組織代碼,并將這些模塊組織到目錄中。以一個簡單的為例:
總體組織如下:
- 一個訓(xùn)練-評估-測試循環(huán)模塊(src/run_experiment.py)
- 一個用于計算性能指標的模塊(src/evaluate.py)
- 一個(或多個)用于數(shù)據(jù)處理的模塊(loaddataset/custom-pascal.py、 loaddatasetcustomtiny.py)
- 一個(或多個)模型模塊(models/custommodelsbase.py)

代碼管理目錄圖
請注意,雖然在這個存儲庫中存儲了一個數(shù)據(jù)集(在"train"、"val"和"test"目錄中的png圖片),但一般來說,將數(shù)據(jù)集放入存儲庫并不是一個好主意。此存儲庫中存在數(shù)據(jù)集的唯一原因是,它是為演示目的而創(chuàng)建的小型數(shù)據(jù)集。除非數(shù)據(jù)非常小,否則不應(yīng)將其放入存儲庫中。
導(dǎo)入文件
請注意,需要在每個子目錄中都有一個名為init.py的空文件,以便模塊可以從這些目錄導(dǎo)入文件。
下面是如何根據(jù)彼此所在的目錄讓一個模塊awesomecode.py調(diào)用名為helpercode.py的模塊:

說明文檔
寫說明文檔是很好的。記錄所有函數(shù)、方法和類,有時在編寫函數(shù)之前對其進行文檔記錄。如果文檔有時比代碼長也可以,"過于清晰"比不夠清晰要好。

上面的圖像是一個簡單的函數(shù)rand_rotate(),它隨機旋轉(zhuǎn)表示CT體積的3D numpy數(shù)組。這些注釋很有幫助,因為它們解釋了為什么旋轉(zhuǎn)的向量使用(k-1)——這是因為所選的k是1、2或3,而Python是零索引的。像這樣簡單的說明可以防止以后的混亂。

data processing tutorial code中的說明注釋
文檔將確?;仡櫯f代碼時,可以快速回憶代碼和函數(shù)的作用。文檔可以防止使用者在看到一些看起來很奇怪的東西時意外地破壞自己的代碼,并且有更改它的本能。文檔也將使其他人能夠理解和使用您的代碼。
變量命名
始終使用描述性變量名。"volumetricattngr_truth"是一個比"truth"更好的變量名。
即使在行和列上迭代,也要使用"row"和"col"作為變量名,而不是"i"和"j"。有一次我花了一整天的時間尋找一個非常奇怪的bug,結(jié)果發(fā)現(xiàn)它是由于錯誤地迭代2D數(shù)組而導(dǎo)致的,因為我在數(shù)百行代碼中只切換了一行"I"和"j"。那是我最后一次使用單字母變量名。
模塊測試
很多人聲稱他們沒有時間為他們的代碼編寫測試,因為這只是為了研究。我認為測試研究代碼更重要,因為研究的全部意義在于你不知道"正確答案"是什么,如果你不知道生成答案的代碼是否正確那么如何確保答案是正確的呢?
每次我花一天時間為我的代碼編寫單元測試時,我都會發(fā)現(xiàn)一些錯誤——有些無關(guān)緊要,有些則相當重要。如果你編寫單元測試,將發(fā)現(xiàn)代碼中的錯誤。如果你為別人的代碼編寫單元測試,你也會在他們的代碼中發(fā)現(xiàn)錯誤。
除了促進代碼的正確性,單元測試還可以通過阻止編寫一次做太多事情的"上帝函數(shù)"來幫助實施良好的代碼組織管理。上帝函數(shù)通常是測試的噩夢,我們應(yīng)該將其分解成更小、更易于管理的函數(shù)。
至少,最好對代碼中最關(guān)鍵的部分進行單元測試,例如復(fù)雜的數(shù)據(jù)處理或模型中奇怪的張量排列。確保代碼是正確的決不是浪費時間。
這些單元測試包括對一些內(nèi)置PyTorch函數(shù)的測試,以便進行演示。
可視化糾錯
特別是在計算機視覺中,使用可視化來執(zhí)行健全性檢查是很有用的。
matplotlib非常適合查看圖像、分割圖、帶邊框的圖像等。下面是一個通過將matplotlib的imshow()函數(shù)應(yīng)用于輸入圖像而產(chǎn)生的可視化效果的示例:

matplotlib可視化
seaborn是為統(tǒng)計數(shù)據(jù)可視化而設(shè)計的。它對于制作熱力圖和生成性能指標的復(fù)雜可視化非常有用。下面是一些在seaborn中可以用大約一行代碼繪制的繪圖示例:

seaborn可視化
matplotlib和seaborn都可以用來創(chuàng)建可視化效果,即時顯示輸入數(shù)據(jù)是否合理、基本真實情況是否合理、數(shù)據(jù)處理是否沒有意外出錯、模型的輸出是否有意義等。
單元測試和可視化
Demo-0-Unit-Tests-and-Visualization.py 首先運行 src/unit_tests.py中的單元測,然后對PASCAL VOC 2012數(shù)據(jù)集圖像分割進行可視化。
為了運行演示的可視化部分,請更改demo-0-Unit-Tests-and-visualization.py到計算機上的一個文件夾內(nèi),在其中存儲PASCAL VOC 2012數(shù)據(jù)集。一旦數(shù)據(jù)集下載完成,你就可以運行可視化程序。實現(xiàn)可視化的代碼位于loaddataset/custompascal.py中. 目前,在演示文件中,"imagestovisualize"的總數(shù)設(shè)置為3;如果希望可視化更多圖像,可以進一步增加該數(shù)量,例如增加到100。
可視化結(jié)果如下:

PASCAL VOC 2012數(shù)據(jù)集中的飛機圖像

resample處理后的飛機圖像
從可視化結(jié)果中我們可以推斷出一些有用的東西:
- 輸入圖像與圖像分割之間的映射是正確的。
- 用于定義像素級分割的整數(shù)與標簽描述字符串之間的映射是正確的。比如:1正確地映射為"飛機"。
- 重采樣步驟并沒有"破壞"輸入圖像或分割圖像。
在終端進行可視化
如果處于"非交互式環(huán)境"(即沒有圖形用戶界面的終端),則需要關(guān)閉交互式顯示并保存圖形,以便在其他地方打開:
- import seaborn
- import matplotlib
- matplotlib.use('agg')
- import matplotlib.pyplot as plt
- plt.ioff() #seaborn figure: heatmap = seaborn.heatmap(some_dataframe, cmap = 'Blues', square=True, center=0)
- heatmap.get_figure().savefig('Descriptive_Figure_Name.png',bbox_inches='tight')
- plt.close()
- #matplotlib figure: plt.imshow(chest_x_ray,cmap='gray')
- plt.savefig('Other_Descriptive_Figure_Name.png')
- plt.close()
Python 調(diào)試器
Python調(diào)試器是一個非常有用的工具,因為它允許在程序崩潰的地方檢查變量或?qū)ο蟮臓顟B(tài),并在程序崩潰的地方運行代碼片段,以便可以嘗試可能的解決方案。使用Python調(diào)試器比使用print語句調(diào)試效率更高,它將為節(jié)省數(shù)小時的時間。Python調(diào)試器也可以與PyTorch一起使用,檢查張量、梯度、記錄dataframes等。
要使用Python調(diào)試器在終端中以交互方式運行腳本,請使用以下命令:
- python -m pdb myscript.py
輸入上述命令后,將看到(Pdb)提示符出現(xiàn)。鍵入"c"繼續(xù)。(這只是一個單獨的小寫字母c,表示continue)。
要退出Python調(diào)試器,請使用'q'(這是一個單獨的小寫字母q,表示quit)。有時候可能需要使用q兩次才能完全退出。
如果要在程序中的某個特定點停止,則可以在相關(guān)模塊中導(dǎo)入pdb,然后將"pdb.set_trace()"在你想要停止的特定點。或者,如果不想費心導(dǎo)入pdb,也可以在想停止的地方輸入"assert False",這樣可以保證程序在指定的地方結(jié)束(盡管這不是使用Python調(diào)試器的正式方式)。
不要使用Jupyter Notebooks
考慮到前面的所有部分,本文建議不要將jupyter notebooks用于機器學(xué)習(xí)項目,或者真正用于任何需要花費數(shù)天以上時間的編碼項目。
為什么?
- jupyter notebooks 鼓勵你把所有的東西都放在全局命名空間中,這樣就產(chǎn)生了一個巨大的怪物模塊,它可以做所有的事情,而且沒有函數(shù)、類和任何結(jié)構(gòu)。
- jupyter notebooks 使代碼的重用變得更加困難。函數(shù)是可重用的;而單元格5、10和13中的代碼是不可重用的。
- jupyter notebooks 使單元測試變得困難。函數(shù)和方法可以進行單元測試。單元格5、10和13中的代碼不能進行單元測試。
1. 代碼越有條理(也就是說,越細分為類和函數(shù)),jupyter notebooks 的交互性就越差,交互性是人們喜歡jupyter notebook的主要原因。jupyter notebooks 吸引人的交互特性與高度結(jié)構(gòu)化、組織良好的代碼本質(zhì)上是對立的。
- jupyter notebooks 很難正確使用Git版本控制。jupyter notebooks只是大量的JSON文件,因此正確地合并它們或用它們執(zhí)行提交請求基本上是不可能的。
- jupyter notebooks 使人們很難與他人合作。你必須"輪流"在jupyter notebooks上工作(而不是像使用"常規(guī)代碼"那樣從同一個rep中push/pull)。
- jupyter notebooks 有一個非線性的工作流程,這與可重復(fù)的研究完全相反。
那么jupyter notebooks有什么用?一些可能適用的場景是初始數(shù)據(jù)可視化、家庭作業(yè)、交互式演示。
代碼編寫標準
兩個實用的代碼編寫標準是:
- 編寫正確易懂的代碼。如果你的代碼是正確的,你的模型就更有可能產(chǎn)生好的結(jié)果,你的研究結(jié)論是正確的,你將創(chuàng)造出一些實際有用的東西。
- 確保任何人都可以復(fù)制你所做的一切——例如模型、結(jié)果、圖形——通過在終端中運行一個命令(例如"python main.py"). 將有助于其他人在你的工作基礎(chǔ)上再接再厲,也有助于"未來的你"在自己的工作基礎(chǔ)上再接再厲。
總結(jié)
- Python是一種很好的機器學(xué)習(xí)語言
- Git版本控制有助于跟蹤不同版本的代碼。它可以通過GitHub獲得。
- Anaconda是一個包管理器,它支持創(chuàng)建不同的環(huán)境,這些環(huán)境可能包含不同的Python版本和包。在處理具有沖突依賴關(guān)系的多個項目時,它非常有用。
- 將代碼組織成模塊中的類和函數(shù)。在Git存儲庫中以分層目錄結(jié)構(gòu)組織模塊。
- 用注釋和docstring記錄代碼
- 使用描述性變量名。不要使用單字母變量名。
- 編寫單元測試,特別是對于數(shù)據(jù)處理和模型中最復(fù)雜或最關(guān)鍵的部分。
- 使用matplotlib和seaborn可視化顯示數(shù)據(jù)集、模型輸出和模型性能
- 使用Python調(diào)試器進行快速、高效的調(diào)試
- 不要將jupyter notebooks 用于機器學(xué)習(xí)項目
作者:Rachel Lea Ballantyne Draelos