選自arXiv
作者:Adam Rule、Amanda Birmingham等
機(jī)器之心編譯
參與:韓放、路
你真的是 Jupyter Notebook 高手嗎,真的能將代碼和文檔打造成鐵桶一般的整體嗎?
Jupyter Notebook 是一個(gè)非常常用的代碼編輯器,它非常適合做數(shù)據(jù)分析與代碼展示,很多云服務(wù)也采用它作為代碼編輯器。此外,因?yàn)橛眠@種編輯器看代碼比較輕松,文檔描述和輸出效果也能進(jìn)一步幫助理解,很多研究者都會(huì)采用 Jupyter 作為解釋研究實(shí)現(xiàn)的工具。
如果 Jupyter Notebook 寫的好,那么研究實(shí)現(xiàn)及復(fù)現(xiàn)就更優(yōu)美,如果再放到 Colab 等具有免費(fèi)算力的工具上,那就比較完美了。
在機(jī)器之心之前介紹過的文章中,我們關(guān)注 Jupyter Notebook 的炫酷插件與主題風(fēng)格,更強(qiáng)調(diào)工具本身的使用姿態(tài)。而一篇發(fā)在 arXiv 上的文章介紹了什么是展示實(shí)現(xiàn)代碼的十大簡(jiǎn)單規(guī)則,我該又該如何利用它們構(gòu)建 Jupyter 項(xiàng)目。這對(duì)于研究者和希望展示項(xiàng)目實(shí)現(xiàn)的開發(fā)者而言非常重要,我們可以像說故事一樣介紹我們的實(shí)現(xiàn)。
論文鏈接:https://arxiv.org/pdf/1810.08055.pdf
下面,我們就以展示可復(fù)現(xiàn)性研究成果為目標(biāo),看看 Jupyter 要怎樣寫才比較合理。
Jupyter Notebook 與研究的可復(fù)現(xiàn)性
可復(fù)現(xiàn)性(Reproducibility)需要提供研究所用數(shù)據(jù)、軟件、依賴項(xiàng)和計(jì)算環(huán)境(如硬件或云配置)的人類可讀和機(jī)器可讀的描述,以及介紹如何組合以上所有部分的文檔。
之前分析人員通常將這些信息保存在單獨(dú)的數(shù)據(jù)、分析、結(jié)果、配置和注釋文件中(這些文件通常很難組合和共享),不過他們?cè)絹碓蕉嗟厥褂糜?jì)算型 notebook(如 Jupyter Notebooks 和 R Notebooks),在單個(gè)交互式和可移植文檔中組合可執(zhí)行代碼、渲染可視化效果和描述性文本。
Jupyter Notebooks 大大降低了可復(fù)現(xiàn)性的困難,它使科學(xué)家能夠輕松地編寫混合了代碼、結(jié)果和文本的共享計(jì)算敘述,從而支持可復(fù)現(xiàn)性研究。然而,像 Jupyter Notebook 這樣的計(jì)算型 notebook 并沒有解決實(shí)現(xiàn)可復(fù)現(xiàn)性的所有障礙,而且它們還引入了另一些獨(dú)特的挑戰(zhàn),其中部分挑戰(zhàn)源于它們的交互性。
考慮到在 Jupyter Notebooks 上發(fā)布可復(fù)現(xiàn)研究的技術(shù)和社會(huì)障礙,來自加州大學(xué)圣地亞哥分校和伯克利分校的研究者編制了一套規(guī)則、提示、工具和示例 notebook。這套規(guī)則專注于 Jupyter Notebooks,不過也適用于其他混合了實(shí)時(shí)代碼和敘述性描述的文檔。
下圖 1 展示了在 notebook 開發(fā)周期不同階段所應(yīng)用的規(guī)則。
圖 1:將十個(gè)簡(jiǎn)單規(guī)則應(yīng)用于創(chuàng)建 Jupyter Notebooks 的工作流。從上到下,該圖描述了開發(fā)一個(gè)記錄詳盡、功能良好、用于可復(fù)現(xiàn)性研究的 Jupyter Notebooks 所需的三個(gè)不同的階段。
規(guī)則 1:為觀眾講故事
使用 Jupyter Notebooks 的一個(gè)主要好處是,它能將解釋性文本與代碼和結(jié)果交織在一起,創(chuàng)建計(jì)算性敘述 [8]。不要只保留零星的筆記,而是用解釋性文字講述一個(gè)引人入勝的故事,故事的開頭介紹主題,中間介紹步驟,結(jié)尾解釋結(jié)果。不僅要描述你做了什么,還要描述為什么要這樣做、這些步驟是如何連接的,以及它們意味著什么。
如何講述這個(gè)故事將取決于你的觀眾。你打算和實(shí)驗(yàn)室的非技術(shù)同事、另一個(gè)實(shí)驗(yàn)室的分析師、某一期刊的讀者還是公眾分享你的 notebook?你可能需要為每一類觀眾提供不同種類和級(jí)別的解釋。
規(guī)則 2:記錄過程,而不僅僅是結(jié)果
計(jì)算型 notebook 的交互特性使得嘗試和對(duì)比不同方法或參數(shù)更加快速和容易,以至于我們?cè)趫?zhí)行這些交互式調(diào)研時(shí)往往無法將其記錄下來。因此,這個(gè)建議變得更加重要:確保記錄下所有的探索,甚至那些導(dǎo)致進(jìn)入死胡同的探索!這些將幫助你記住做了什么和為什么做。
許多 notebook 用戶等到分析結(jié)束、得到了可靠結(jié)果后,才添加這樣的解釋性文字。不要等,到那時(shí)你可能已經(jīng)忘記了為什么選擇某個(gè)特定參數(shù)值、從哪里復(fù)制了一段代碼,或者中間結(jié)果的有趣之處是什么。如果你沒有時(shí)間全面記錄你此刻正在做什么或在想什么,那么留下簡(jiǎn)短的描述性筆記來提醒自己,在可以停下時(shí)抓緊把這些內(nèi)容添加上。
規(guī)則 3:添加分割,使步驟更清晰
notebook 是一個(gè)交互式的環(huán)境,所以它很容易編寫和運(yùn)行單行單元格。這有利于實(shí)驗(yàn),但會(huì)讓 notebook 凌亂不堪,充滿難以理解的短小片段。那么,嘗試讓 notebook 中的每個(gè)單元格執(zhí)行一個(gè)有意義的分析步驟,并且該步驟可以根據(jù)單元格中的代碼或周圍的 markdown 描述很容易地理解。
按單元格模塊化代碼,并在單元格上方用 markdown 標(biāo)記。將每個(gè)單元格想象為一個(gè)段落、擁有一個(gè)函數(shù)或完成一個(gè)任務(wù)(例如,創(chuàng)建一個(gè)繪圖)。避免長單元格(任何超過 100 行或一頁的內(nèi)容都太長了)。在代碼注釋中放入低級(jí)文檔。使用描述性的 markdown header 將 notebook 分區(qū),使其可以輕松導(dǎo)航和添加目錄。將長 notebook 拆分為一系列 notebook,并保留一個(gè) top-level index notebook,其中包含指向各個(gè) notebook 的鏈接。
規(guī)則 4:模塊化代碼
避免重復(fù)代碼總是很好的做法,但是在 notebook 中,復(fù)制一個(gè)單元格、調(diào)整幾行、將生成的代碼粘貼到新單元格或其他 notebook 中并再次運(yùn)行是特別容易的。這種試驗(yàn)形式很方便,但如果你想更改復(fù)制的代碼的功能或修復(fù)其中的 bug,就會(huì)使 notebook 難以閱讀,并且?guī)缀醪豢赡苓M(jìn)行維護(hù)。因此你可以將要復(fù)制和重用的代碼包裝在一個(gè)函數(shù)中,這樣就可以根據(jù)需要從任意多個(gè)單元格中調(diào)用該函數(shù)。如果你要在其他項(xiàng)目或 notebook 中重用代碼,請(qǐng)考慮將其轉(zhuǎn)換為模塊、包或庫,并遵循良好的軟件開發(fā)實(shí)踐(如單元測(cè)試)。
模塊化不僅節(jié)省空間,支持維護(hù),調(diào)試方便,還使增加交互性變得更加簡(jiǎn)單。
規(guī)則 5:記錄依賴項(xiàng)
未來重新生成分析時(shí),不僅需要訪問代碼,還需要訪問依賴項(xiàng)。計(jì)算科學(xué)的最佳實(shí)踐是,從一開始就使用諸如 conda 的 environment.yml 或 pip 的 requirements.txt 之類的工具明確地管理依賴項(xiàng),以列出所有相關(guān)的依賴項(xiàng)(包括它們的軟件版本)。始終在這些依賴項(xiàng)創(chuàng)建的環(huán)境中工作,以確保不添加未記錄的依賴項(xiàng)。
在 notebook 中,你可以使用 notebook 的擴(kuò)展(如 watermark)顯式打印依賴項(xiàng)。列出 notebook 中關(guān)鍵依賴項(xiàng)的版本(最好列在最下方),如果 notebook 與環(huán)境隔離使用,那么這將保證 notebook 中仍然包含關(guān)鍵信息,從而幫助讀者復(fù)制結(jié)果。
規(guī)則 6:使用版本控制
版本控制是 notebook 使用的一個(gè)重要輔助工具,因?yàn)?notebook 的交互特性使其很容易意外地更改或刪除重要內(nèi)容。此外,由于 notebook 中包含代碼,代碼不可避免會(huì)有 bug,因此確定 bug 引入與修復(fù)的時(shí)間(及其可能影響的分析)是科學(xué)計(jì)算中的一項(xiàng)關(guān)鍵能力。
但是,請(qǐng)注意,Jupyter Notebook 將每個(gè)單元格的代碼和特定且廣泛的元數(shù)據(jù)存儲(chǔ)為 JSON 格式的文本文件。版本控制系統(tǒng)比較這些 JSON 文件中的差異,而不是用戶友好型 notebook GUI(圖形用戶界面)中的差異。
規(guī)則 7:構(gòu)建 pipeline
記錄初步探索性研究的 notebook 很少能被廣泛推廣,但一旦確定了某種穩(wěn)定的分析方法,設(shè)計(jì)良好的 notebook 就可以通過 pipeline 推廣到其他任務(wù)中,從而使用不同的輸入數(shù)據(jù)和參數(shù)很容易地重復(fù)分析。記住這一點(diǎn),從一開始就設(shè)計(jì)你的 notebook,以允許將來重新調(diào)整用途。把關(guān)鍵變量聲明(尤其是在進(jìn)行新的分析時(shí)會(huì)改變的變量)放在 notebook 的頂部,而不是埋在中間的某個(gè)地方。直接在 notebook 中執(zhí)行準(zhǔn)備步驟,如數(shù)據(jù)清理,并盡可能避免手動(dòng)干預(yù)。
規(guī)則 8:分享和解釋數(shù)據(jù)
如果底層數(shù)據(jù)被鎖定,那么訪問清晰注釋的 notebook 對(duì)可復(fù)現(xiàn)性也幾乎沒有用處。努力使你的數(shù)據(jù)或數(shù)據(jù)樣本與 notebook 一起公開。notebook 可以很容易地提供輸入數(shù)據(jù)和上游處理步驟的描述,這對(duì)于解釋結(jié)果至關(guān)重要。
理想情況下,你可以在 notebook 中共享整個(gè)數(shù)據(jù)集。我們認(rèn)識(shí)到許多數(shù)據(jù)集太大或太敏感,無法以這種方式共享。在這些情況下,考慮將大型和復(fù)雜的數(shù)據(jù)集分解為多個(gè)層次,這樣即使原始數(shù)據(jù)太大,無法與已發(fā)布的 notebook 一起共享,或者受到隱私或其他訪問問題的限制,也不會(huì)影響到可復(fù)現(xiàn)性。
規(guī)則 9:允許閱讀、運(yùn)行和探索 notebook
如果你遵循了前面的規(guī)則,那么你的 notebook 應(yīng)該能夠捕獲整個(gè)過程并易于閱讀。但是其他人如何訪問、運(yùn)行和探索它們呢?你可以通過多種方式支持他人重用你的 notebook。首先,將 notebook 存儲(chǔ)到一個(gè)具備清晰 README 文件的公共代碼庫中。
除了允許重用之外,你還要考慮如何利用 notebook 的獨(dú)特結(jié)構(gòu)來支持閱讀和探索。至少,將所有 notebook 的靜態(tài) HTML/PDF 版本存儲(chǔ)在出版物附帶代碼庫的最終版本中。
規(guī)則 10:促進(jìn)可復(fù)現(xiàn)和開放的研究
顯然,僅使用計(jì)算型 notebook 并不能保證研究的可復(fù)現(xiàn)。如果 notebook 的便利性和交互性讓你滿意,那你可以采取下一步行動(dòng),在實(shí)驗(yàn)室或工作場(chǎng)所宣傳其可復(fù)現(xiàn)性。讓實(shí)驗(yàn)室的同事試著運(yùn)行你的 notebook,然后聽他們解釋在什么地方出了問題。也試著運(yùn)行他們的 notebook,讓他們知道你是否遇到了障礙。
將可復(fù)現(xiàn)性作為研究小組所有計(jì)算工作的關(guān)鍵要素,而不是在分析完成后才執(zhí)行,或被期刊或評(píng)審人員要求后才思考。
版權(quán)聲明:本文內(nèi)容由互聯(lián)網(wǎng)用戶自發(fā)貢獻(xiàn),該文觀點(diǎn)僅代表作者本人。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如發(fā)現(xiàn)本站有涉嫌抄襲侵權(quán)/違法違規(guī)的內(nèi)容, 請(qǐng)發(fā)送郵件至 舉報(bào),一經(jīng)查實(shí),本站將立刻刪除。