在機(jī)器學(xué)習(xí)社區(qū),越來越多的人開始討論研究的可復(fù)現(xiàn)性,但這些討論大部分局限于學(xué)術(shù)環(huán)境。如何確保生產(chǎn)環(huán)境的ML可復(fù)現(xiàn)?近日,機(jī)器學(xué)習(xí)開發(fā)服務(wù)提供商 maiot.io 的 CTO Benedikt Koller 發(fā)布一篇博客文章,介紹了他基于自身經(jīng)驗(yàn)總結(jié)的開發(fā)可復(fù)現(xiàn)生產(chǎn)級機(jī)器學(xué)習(xí)所要注意的 12 個(gè)要素。
過去二十年來,我們對軟件開發(fā)的理解有了大幅提升。其中一大部分原因是 DevOps 概念的出現(xiàn)及其在軟件開發(fā)行業(yè)的廣泛應(yīng)用。
領(lǐng)先的軟件公司都遵循著同樣的模式:首先是在軟件開發(fā)過程中快速迭代,然后進(jìn)行持續(xù)集成、持續(xù)交付、持續(xù)部署。每個(gè)特性都要經(jīng)過測試,看其提供價(jià)值的能力如何,而且軟件始終要處于就緒的狀態(tài),并且通過自動化方法進(jìn)行部署。
機(jī)器學(xué)習(xí)這個(gè)領(lǐng)域雖不同于傳統(tǒng)的軟件開發(fā),但我們也能從軟件開發(fā)行業(yè)汲取很多實(shí)用的經(jīng)驗(yàn)教訓(xùn)。過去幾年里,我們一直在開發(fā)生產(chǎn)型機(jī)器學(xué)習(xí)項(xiàng)目。我們的目標(biāo)并不只是概念驗(yàn)證,而是與軟件開發(fā)一樣的可復(fù)現(xiàn)能力(reproducibility)。因此,我們構(gòu)建了一套流程協(xié)調(diào)器、強(qiáng)大的自動化能力并建立了一套用于實(shí)現(xiàn)該目標(biāo)的工作流程。
為什么不直接使用 Jupyter Notebook?從頭開始構(gòu)建一組包含所有處理步驟的筆記需要多長時(shí)間?為團(tuán)隊(duì)納入新成員的難易程度如何?你現(xiàn)在可以復(fù)現(xiàn)兩個(gè)月前的結(jié)果嗎?能以多快的速度復(fù)現(xiàn)?你能將今天的結(jié)果和歷史結(jié)果進(jìn)行對比嗎?你能在訓(xùn)練過程中關(guān)注到數(shù)據(jù)的出處嗎?如果你的模型過時(shí)了又會發(fā)生什么?
我們遇到過所有這些問題。現(xiàn)在,我們將這些經(jīng)驗(yàn)進(jìn)行了歸納總結(jié),得到了成功構(gòu)建生產(chǎn)型機(jī)器學(xué)習(xí)的 12 個(gè)要素(類似于軟件開發(fā)中的十二要素應(yīng)用/12 factor app)。
1. 版本控制
對軟件工程師來說,版本控制基本上是理所當(dāng)然需要做的,但是這一方法論還尚未被數(shù)據(jù)科學(xué)家廣泛接受。讓我引述一下 Gitlab 上一些人的說法:
版本控制可促進(jìn)整個(gè)軟件開發(fā)團(tuán)隊(duì)之間的協(xié)調(diào)、共享和協(xié)作。版本控制軟件讓團(tuán)隊(duì)可以在分布式和異步環(huán)境中工作、管理代碼和文件的修改和版本以及解決合并沖突和相關(guān)異常。
簡單來說,版本控制能讓你安全地管理軟件開發(fā)中會變化的部分。
機(jī)器學(xué)習(xí)其實(shí)是一種特殊的軟件開發(fā),有著自己特定的要求。首先,機(jī)器學(xué)習(xí)中會變化的部分不止一種,而是兩種:代碼和數(shù)據(jù)。其次,模型訓(xùn)練的方式是(快速)迭代,并且代碼中的差異會很大(比如拆分、預(yù)處理、模型)。
只要數(shù)據(jù)發(fā)生更改,就需要保存一個(gè)版本,這樣才能保證能復(fù)現(xiàn)結(jié)果以及重復(fù)執(zhí)行實(shí)驗(yàn)和訓(xùn)練模型。簡單粗暴的版本控制(硬拷貝)具有很大的改進(jìn)空間,不過尤其是在團(tuán)隊(duì)共享的情況下,能夠保持不變的版本控制是至關(guān)重要的。
代碼的版本控制還要更加重要。除了上面引述的內(nèi)容,預(yù)處理代碼不僅在訓(xùn)練階段很重要,而且在服務(wù)階段也很重要,需要與模型有保持不變的相關(guān)性。為了在數(shù)據(jù)科學(xué)家的工作流程和投入生產(chǎn)的要求之間建立一種中臺,一種方便的方法是提供無服務(wù)器的功能。
總結(jié):你需要對代碼進(jìn)行版本控制,也需要對數(shù)據(jù)進(jìn)行版本控制。 2. 明確的特征依賴關(guān)系
在理想世界中,產(chǎn)生你的輸入數(shù)據(jù)的東西應(yīng)該總是會產(chǎn)生同樣的數(shù)據(jù),至少結(jié)構(gòu)上是這樣。但這個(gè)世界并不是完美的,你從上游服務(wù)獲取的數(shù)據(jù)也是由人類構(gòu)建的,因此可能會發(fā)生變化。最終,特征也可能發(fā)生改變。最好的情況是你的模型會直接故障報(bào)錯(cuò),但還有最壞的情況:你的模型悄悄繼續(xù)工作,但得到的結(jié)果都是垃圾。
明確定義的特征依賴關(guān)系能夠盡快揭示出失敗案例。如果系統(tǒng)設(shè)計(jì)得好,還能在服務(wù)時(shí)進(jìn)行持續(xù)訓(xùn)練,然后調(diào)整依賴關(guān)系并加以適應(yīng)。
總結(jié):明確代碼中的特征依賴關(guān)系。
3. 描述性的訓(xùn)練和預(yù)處理
優(yōu)良的軟件都有優(yōu)良的描述和注釋——讓人無需閱讀每一行代碼就能輕松閱讀和理解代碼功能。
盡管機(jī)器學(xué)習(xí)是一類特殊的軟件開發(fā),但它并不鼓勵實(shí)踐者背離已有的代碼書寫準(zhǔn)則。在代碼書寫標(biāo)準(zhǔn)中,最基本的一條是能讓人在短時(shí)間內(nèi)不費(fèi)力地閱讀。
預(yù)處理和模型的代碼都應(yīng)該遵循 PEP8 規(guī)范。代碼中應(yīng)當(dāng)使用有意義的對象名并包含有助于理解的注釋。遵循 PEP8 規(guī)范可提升代碼的可讀性,降低復(fù)雜度并加快調(diào)試速度。SOLID 之類的編程范式提供了經(jīng)過深思熟慮的框架,可讓代碼在未來用例中的可維護(hù)性、可理解性和靈活性都得到改善。
配置應(yīng)該與代碼分離。不要將數(shù)據(jù)分配比例硬編碼到代碼之中,而是通過配置方式提供,以便在運(yùn)行時(shí)修改。人們在超參數(shù)調(diào)節(jié)方面已經(jīng)熟知這一點(diǎn)了:使用分離的配置文件可以顯著加快迭代速度,并且讓代碼庫可以重復(fù)使用。
總結(jié):提升代碼可讀性并且將代碼和配置分開。 4. 訓(xùn)練結(jié)果的可復(fù)現(xiàn)性
如果你不能復(fù)現(xiàn)訓(xùn)練結(jié)果,那么這個(gè)結(jié)果就是不可信的。盡管這是本文的主題,但在可復(fù)現(xiàn)性方面有一些細(xì)節(jié)需要說明。不僅是你自己需要能復(fù)現(xiàn)訓(xùn)練結(jié)果,你的整個(gè)團(tuán)隊(duì)都要能做到這一點(diǎn)。不管是在 PC 還是在 AWS 虛擬機(jī)上,模糊處理 Jupyter Notebook 中的訓(xùn)練結(jié)果都與可復(fù)現(xiàn)性背道而馳。
通過設(shè)定訓(xùn)練的工作流程,整個(gè)團(tuán)隊(duì)都可以透明地訪問已執(zhí)行的實(shí)驗(yàn)和已運(yùn)行的訓(xùn)練。通過綁定可復(fù)用的代碼庫以及分離的配置文件,每個(gè)人都可在任何時(shí)間成功重新訓(xùn)練。
總結(jié):使用管道式工作流程和自動化。
5. 測試
測試的形式有很多。舉兩個(gè)例子:
1)單元測試是原子層面上的測試——基于各自的標(biāo)準(zhǔn)單獨(dú)測試每個(gè)函數(shù)和功能。
2)集成測試則相反,是將代碼庫的所有元素都放到一起進(jìn)行測試,同時(shí)還會測試上下游服務(wù)的克隆版本或模擬版本。
這兩種范式都適應(yīng)于機(jī)器學(xué)習(xí)。預(yù)處理代碼是預(yù)先確定的,直到測試階段——這樣的轉(zhuǎn)換能在不同的輸入下都得到正確結(jié)果嗎?模型是集成測試的一個(gè)絕佳案例——在生產(chǎn)環(huán)境中提供服務(wù)時(shí),你的模型的表現(xiàn)是否與評估時(shí)相當(dāng)?
總結(jié):測試你的代碼,測試你的模型。
6. 偏移與持續(xù)訓(xùn)練
在生產(chǎn)場景中,任務(wù)發(fā)生偏移是合理存在的問題。只要數(shù)據(jù)存在變化的可能性,你就需要考慮偏移的可能性。對于此問題的風(fēng)險(xiǎn),有兩種可以采取的措施:
1)監(jiān)控生產(chǎn)系統(tǒng)中的數(shù)據(jù)。建立自動化報(bào)告機(jī)制,在數(shù)據(jù)發(fā)生變化時(shí)通知團(tuán)隊(duì),這種變化甚至可能超過明確定義的特征依賴關(guān)系。
2)基于新輸入的數(shù)據(jù)持續(xù)訓(xùn)練。良好自動化的管道化流程可以基于新數(shù)據(jù)重復(fù)運(yùn)行,然后與歷史訓(xùn)練結(jié)果進(jìn)行比較,展示性能變化情況以及將訓(xùn)練得到的模型快速投放到生產(chǎn)中,從而讓模型表現(xiàn)更好。
總結(jié):如果你的數(shù)據(jù)會發(fā)生變化,那就采用一種持續(xù)訓(xùn)練的管道化流程。
7. 跟蹤結(jié)果
Excel 并非一種跟蹤實(shí)驗(yàn)結(jié)果的好方法。而且還不只是 Excel,任何分散的人工跟蹤方法得到的信息都是不夠權(quán)威的,也因此是不可信的。
正確的做法是以一種中心化的數(shù)據(jù)存儲方式自動記錄訓(xùn)練結(jié)果。自動化能夠保證可靠地跟蹤每次訓(xùn)練,從而方便之后比較每次訓(xùn)練的結(jié)果。對結(jié)果進(jìn)行中心化存儲,能為團(tuán)隊(duì)提供透明,實(shí)現(xiàn)持續(xù)性分析。
總結(jié):通過自動化方法跟蹤結(jié)果。
8. 實(shí)驗(yàn)?zāi)P团c生產(chǎn)模型
我們需要努力才能理解數(shù)據(jù)集。通常來說,我們會通過實(shí)驗(yàn)來實(shí)現(xiàn)理解,尤其是當(dāng)我們關(guān)注的領(lǐng)域具備大量隱含領(lǐng)域知識時(shí)。創(chuàng)建一個(gè) Jupyter Notebook,將部分/全部數(shù)據(jù)導(dǎo)入 Pandas Dataframe,進(jìn)行幾個(gè)小時(shí)無序研究,訓(xùn)練第一個(gè)模型,評估結(jié)果——任務(wù)完成。但幸運(yùn)的是,現(xiàn)實(shí)并不如此。
在機(jī)器學(xué)習(xí)的生命周期中,實(shí)驗(yàn)有自己的目的。這些目的并不是模型,而是理解。基于探索性 Jupyter Notebook 的模型是為了理解,而不是為生產(chǎn)開發(fā)的成品。理解之后,還需要進(jìn)一步開發(fā)和適應(yīng),才能開始打造用于生產(chǎn)的訓(xùn)練流程。
不過,所有與領(lǐng)域特定的知識無關(guān)的理解都可以自動化。你可以基于你使用的每個(gè)數(shù)據(jù)版本生成統(tǒng)計(jì)信息,從而可以跳過那些你在 Jupyter Notebook 中做過的一次性的臨時(shí)探索工作,然后直達(dá)第一個(gè)管道式流程。你在流程中實(shí)驗(yàn)進(jìn)行得越早,你就能越早地在中間結(jié)果上進(jìn)行協(xié)作,也就能更早地實(shí)現(xiàn)可投入生產(chǎn)的模型。
總結(jié):筆記不能投入生產(chǎn),因此要在流程中盡早實(shí)驗(yàn)。
9. 訓(xùn)練和服務(wù)之間的方法差異
訓(xùn)練和實(shí)際服務(wù)之間往往存在方法差異,為了正確地將所有數(shù)據(jù)預(yù)處理過程都納入到模型服務(wù)環(huán)境中,需要減少這些差異。這當(dāng)然是正確的,你也需要堅(jiān)持這一原則。但是,這只是對這一問題的部分解讀。
先來簡單看一段古老的 DevOps 歷史:2006 年,亞馬遜的 CTO Werner Vogels 創(chuàng)造了一個(gè)說法「You build it, you run it(你構(gòu)建的東西你要運(yùn)行)」。這是一個(gè)描述性的短語,意思是開發(fā)者的責(zé)任不只是寫程序,還需要運(yùn)行它們。
機(jī)器學(xué)習(xí)項(xiàng)目也需要類似的機(jī)制——理解上游的數(shù)據(jù)生成以及下游的模型使用都在數(shù)據(jù)科學(xué)家的職責(zé)范圍內(nèi)。你訓(xùn)練用的數(shù)據(jù)是通過什么體系生成的?它會出問題嗎?該體系的服務(wù)級目標(biāo)(SLO)是什么?這與實(shí)際服務(wù)的目標(biāo)一致嗎?你的模型的服務(wù)方式是怎樣的?運(yùn)行時(shí)環(huán)境是怎樣的?怎樣在服務(wù)時(shí)對函數(shù)進(jìn)行預(yù)處理?這些都是數(shù)據(jù)科學(xué)家需要理解和解答的問題。
總結(jié):正確地將預(yù)處理嵌入到服務(wù)之中,確保你理解數(shù)據(jù)的上下游。
10. 可比較性
從為項(xiàng)目引入第二個(gè)訓(xùn)練腳本開始,可比較性就成了未來工作的重要組成部分。如果第二個(gè)模型的結(jié)果無法與第一個(gè)模型的結(jié)果進(jìn)行比較,則整個(gè)過程就浪費(fèi)了,其中至少有一個(gè)是多余的,甚至可能兩個(gè)都多余。
根據(jù)定義,所有試圖解決同一問題的模型訓(xùn)練都需要可以比較,否則它們就不是在解決同一問題。盡管迭代過程可能導(dǎo)致所要比較的東西發(fā)生變化,但是在技術(shù)上實(shí)現(xiàn)模型訓(xùn)練的可比較性需要一開始就作為首要功能內(nèi)置于訓(xùn)練架構(gòu)之中。
總結(jié):構(gòu)建你自己的管道式流程,以便輕松比較各個(gè)流程的訓(xùn)練結(jié)果。
11. 監(jiān)控
粗略地說,機(jī)器學(xué)習(xí)的目標(biāo)應(yīng)該是通過學(xué)習(xí)數(shù)據(jù)來解決問題。為了解決這個(gè)問題,需要分配計(jì)算資源。首先是分配給模型的訓(xùn)練,然后是分配給模型的服務(wù)。負(fù)責(zé)在訓(xùn)練期間提供資源的不管是人還是部門,都需要負(fù)責(zé)將這些資源轉(zhuǎn)移給服務(wù)。模型在使用過程中可能出現(xiàn)很多性能下降問題。數(shù)據(jù)可以偏移,模型可能成為整體性能的瓶頸,偏差也是一個(gè)真實(shí)存在的問題。
效果:數(shù)據(jù)科學(xué)家和團(tuán)隊(duì)負(fù)責(zé)監(jiān)控他們創(chuàng)建的模型。他們并不一定要負(fù)責(zé)實(shí)施監(jiān)控,尤其是當(dāng)組織結(jié)構(gòu)很大時(shí),但他們肯定需要負(fù)責(zé)監(jiān)控?cái)?shù)據(jù)的理解和解釋。最低限度上,需要監(jiān)控的內(nèi)容包括輸入數(shù)據(jù)、推理次數(shù)、資源使用情況(CPU、RAM)和輸出數(shù)據(jù)。
總結(jié):同樣,「You build it, you run it(你構(gòu)建的東西你要運(yùn)行)」。監(jiān)控生產(chǎn)過程中的模型是數(shù)據(jù)科學(xué)的部分工作。
12. 模型的可部署性
從技術(shù)層面講,每個(gè)模型訓(xùn)練流程都需要得到可部署到生產(chǎn)環(huán)境中的成品。毫無疑問,這些模型結(jié)果可能很糟糕,但它需要做成可以部署到生產(chǎn)環(huán)境的形態(tài)。
這是軟件開發(fā)中的常見模式,也叫做持續(xù)交付(Continuous Delivery)。團(tuán)隊(duì)需要能夠隨時(shí)部署他們的軟件,為了滿足這個(gè)目標(biāo),迭代周期需要足夠快。
機(jī)器學(xué)習(xí)也需要采用類似的方法。這樣才能迫使團(tuán)隊(duì)首先考慮現(xiàn)實(shí)與期望之間的平衡。所有利益相關(guān)者都應(yīng)當(dāng)清楚,在模型結(jié)果方面,哪些結(jié)果是理論上可能的。所有利益相關(guān)者都應(yīng)當(dāng)在模型的部署方式以及如何與更大的軟件架構(gòu)整合上達(dá)成一致。但是,這也可能需要自動化,也需要前文提到的一些要素。
總結(jié):每個(gè)訓(xùn)練流程都需要得到可部署的成品,而不「只是」模型。
原文標(biāo)題:機(jī)器學(xué)習(xí)工業(yè)復(fù)現(xiàn)的 12 個(gè)要素
文章出處:【微信公眾號:Imagination Tech】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
責(zé)任編輯:haq
-
代碼
+關(guān)注
關(guān)注
30文章
4753瀏覽量
68369 -
機(jī)器學(xué)習(xí)
+關(guān)注
關(guān)注
66文章
8382瀏覽量
132444
原文標(biāo)題:機(jī)器學(xué)習(xí)工業(yè)復(fù)現(xiàn)的 12 個(gè)要素
文章出處:【微信號:Imgtec,微信公眾號:Imagination Tech】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論