在過去的幾年間,數(shù)據(jù)科學(xué)這個概念已經(jīng)被非常多的行業(yè)所接受。數(shù)據(jù)科學(xué)(源自于一個科學(xué)研究課題)最早是來自于一些試圖去理解人類的智能并創(chuàng)造人工智能的科學(xué)家,但現(xiàn)在它已經(jīng)被證明是完全可以帶來真正的商業(yè)價值。
例如,我所在的公司:Zalando(歐洲最大的時尚品零售店)。在這里,數(shù)據(jù)科學(xué)和其他工具一起被用來提供數(shù)據(jù)驅(qū)動的推薦。推薦本身作為后端服務(wù),被提供給很多地方,包括產(chǎn)品頁面、分類目錄頁面、通訊電郵以及重新定位目標(biāo)客戶等。

圖1:圖片來自Mikio Braun的演講頁
產(chǎn)生推薦
實際上,有非常多的方法可以由數(shù)據(jù)驅(qū)動產(chǎn)生推薦。例如在所謂的“協(xié)同過濾”里,所有用戶的行為(比如瀏覽商品、對想買商品列表的操作、以及購買行為)都可以被收集起來作為推薦的基礎(chǔ),然后分析發(fā)現(xiàn)哪些商品有相似的用戶行為模式。這種方法的優(yōu)美之處在于計算機根本不用知道這些商品是什么。而它的缺點則是商品必須要有足夠多的用戶行為信息數(shù)據(jù)才能保證這個方法起作用。另外一類產(chǎn)生推薦的方法是只看商品的屬性。例如,推薦具有相同品牌的或者相同顏色的商品。當(dāng)然,對這些方法還有非常多的擴展或者組合。

圖2:圖片由Antonio Freno友情提供并授權(quán)使用。引用自發(fā)表在KDD 2015會議的《One-Pass Ranking Models for Low-Latency Product Recommendations》論文
更簡單一些的方法就是只通過計數(shù)來做推薦。但這種方法在實踐里會有非常多的復(fù)雜的變形。例如,對個性化推薦,我們曾使用過“學(xué)習(xí)排序”的方法,即對商品集做個性化的排序。上圖里所顯示的就是這個方法需要最小化的損失函數(shù)。不過,這里畫出這個圖的主要目的還是來展示數(shù)據(jù)科學(xué)可能會引入的復(fù)雜度。這個函數(shù)自身使用了成對的加權(quán)指標(biāo),并帶有正則化條件。這個函數(shù)的數(shù)學(xué)展現(xiàn)是很簡化的,當(dāng)然也就很抽象。這個方法不僅對于電商的推薦場景有用,還對當(dāng)物品有足夠特征的時候的所有類型的排序問題也有用。
將數(shù)據(jù)科學(xué)方法引入工業(yè)界
為了把類似上圖的非常復(fù)雜的數(shù)學(xué)算法引入到生產(chǎn)系統(tǒng)中,我們需要做什么?數(shù)據(jù)科學(xué)和軟件工程之間的界面應(yīng)該是什么樣?什么樣的組織架構(gòu)和隊伍結(jié)構(gòu)才最適合使用這些數(shù)據(jù)科學(xué)的方法。這些都是非常相關(guān)和合理的問題。因為這些問題的答案將會決定對于一個數(shù)據(jù)科學(xué)家或者是整個數(shù)據(jù)科學(xué)團隊的投資是否能最終得到回報。
在下文里,我會根據(jù)我作為一個機器學(xué)習(xí)的研究人員以及在Zalando帶領(lǐng)一個數(shù)據(jù)科學(xué)家和工程師團隊的經(jīng)驗,來對這些問題做一些探討。
理解數(shù)據(jù)科學(xué)(系統(tǒng))與生產(chǎn)系統(tǒng)的關(guān)系
讓我首先從了解數(shù)據(jù)科學(xué)系統(tǒng)與后端生產(chǎn)系統(tǒng)的關(guān)系開始,看看如果將兩者進(jìn)行集成。

圖3:圖片來自Mikio Braun的演講頁
典型的數(shù)據(jù)科學(xué)工作流程(管道)如上圖里所示:第一步總是從發(fā)現(xiàn)問題和收集一些數(shù)據(jù)(來自于數(shù)據(jù)庫或者生產(chǎn)系統(tǒng)的日志)開始。取決于機構(gòu)的數(shù)據(jù)準(zhǔn)備好的程度,這一步有可能就是很困難的。首先,你有可能需要搞清楚誰能讓你接觸到所需的數(shù)據(jù),并搞清楚誰能給你權(quán)限去使用這個數(shù)據(jù)。當(dāng)數(shù)據(jù)可用后,它們就可能需要被再次處理,以便提取特征值。你希望這些特征可以為解決問題提供有用的信息。接著這些特征值被導(dǎo)入學(xué)習(xí)的算法,并用測試數(shù)據(jù)對產(chǎn)生的結(jié)果模型做評估,以決定這個模型是否能較好地對新數(shù)據(jù)做預(yù)測。
上述的這個分析管道通常都是短期一次性的工作。一般是由數(shù)據(jù)科學(xué)家手工完成所有的步驟。數(shù)據(jù)科學(xué)家可能會用到如Python這樣的編程語言,并包括很多的數(shù)據(jù)分析和可視化的庫。取決于數(shù)據(jù)數(shù)量,有時候數(shù)據(jù)科學(xué)家也使用類似Spark和Hadoop這樣的計算框架。但一般他們在一開始都只會使用整個數(shù)據(jù)集的一小部分來做分析。
為什么開始只用一小部分?jǐn)?shù)據(jù)
開始只用一小部分?jǐn)?shù)據(jù)的主要原因是:整個分析管道過程并不是一錘子買賣,而是非常多次反復(fù)迭代的過程。數(shù)據(jù)科學(xué)項目從本質(zhì)上講是探索性的,甚至在某種程度上是開放式的命題。雖然項目目標(biāo)很清楚,但什么數(shù)據(jù)可用,或可用的數(shù)據(jù)是否適合分析,這些在項目一開始都不是很清楚。畢竟,選擇機器學(xué)習(xí)作為方法就已經(jīng)意味著不能僅僅只是通過寫代碼來解決問題。而是要訴諸于數(shù)據(jù)驅(qū)動的方法。
這些特點都意味著上述的分析管道是迭代的,并需要有多次改進(jìn),嘗試不同的特征、不同的預(yù)處理模式、不同的學(xué)習(xí)方法,甚至是重回起點并尋找和實驗更多的數(shù)據(jù)來源。
這整個過程本質(zhì)上就是反復(fù)的,而且經(jīng)常是高度探索性的。當(dāng)做出的模型的整體的表現(xiàn)不錯后,數(shù)據(jù)科學(xué)家就會對真實的數(shù)據(jù)運用開發(fā)的分析管道。到這時,我們就會面臨與生成系統(tǒng)的集成問題。

圖4:圖片來自Mikio Braun的演講頁
區(qū)分生產(chǎn)系統(tǒng)和數(shù)據(jù)科學(xué)系統(tǒng)
生產(chǎn)系統(tǒng)和一個數(shù)據(jù)科學(xué)系統(tǒng)的最主要區(qū)別就是生產(chǎn)系統(tǒng)是一個實時地、在持續(xù)運行的系統(tǒng)。數(shù)據(jù)一定要被處理而模型必須是經(jīng)常更新的。產(chǎn)生的事件也通常會被用來計算關(guān)鍵業(yè)務(wù)性能指標(biāo),比如點擊率等。而模型則通常會每隔幾個小時就被用新數(shù)據(jù)再進(jìn)行訓(xùn)練,然后再導(dǎo)入生產(chǎn)系統(tǒng)中去服務(wù)于新來的(例如通過REST接口送入的)數(shù)據(jù)。
這些生產(chǎn)系統(tǒng)一般都是用如Java這樣的編程語言寫的,可以支持高性能和高可靠性。

圖5:圖片來自Mikio Braun的演講頁
如果你把生產(chǎn)系統(tǒng)和數(shù)據(jù)科學(xué)系統(tǒng)并排放置,那么就會得到一個類似上圖的情況。在右上角,是數(shù)據(jù)科學(xué)的部分。其典型特征是使用類似Python的語音或者是Spark的系統(tǒng),但一般是一次性的手工觸發(fā)的計算任務(wù),并經(jīng)過迭代來優(yōu)化整個系統(tǒng)。它的產(chǎn)出就是一個模型,本質(zhì)上就是一堆學(xué)習(xí)到的數(shù)字。這個模型隨后被導(dǎo)入進(jìn)生成系統(tǒng)。而生產(chǎn)系統(tǒng)則是一個典型的企業(yè)應(yīng)用系統(tǒng),用諸如Java語言寫成的,并持續(xù)運行。
當(dāng)然,上面的這個圖有一些簡化了?,F(xiàn)實中,模型都是需要被重新訓(xùn)練的,所以一些版本的數(shù)據(jù)處理管道會和生成系統(tǒng)集成在一起,以便不時地更新生產(chǎn)系統(tǒng)里的模型。
請注意那個在生成系統(tǒng)里運行的A/B測試。它對應(yīng)于數(shù)據(jù)科學(xué)一側(cè)的評估部分。但這兩部分經(jīng)常并不完全具有可比性。例如不把離線的推薦結(jié)果展示給客戶,就很難去模擬一個推薦的效果,但有這樣做可能會帶來性能的提升。
最后,必須要意識到,這個系統(tǒng)并不是在安裝部署完成后就“萬事大吉了”。就如數(shù)據(jù)科學(xué)側(cè)的人需要迭代多次來優(yōu)化數(shù)據(jù)分析管道,整個實時系統(tǒng)也必須隨著數(shù)據(jù)分布漂移來做迭代演進(jìn)。由此新的數(shù)據(jù)分析任務(wù)就成為可能。對我而言,能正確做好這個“外部迭代”是對生產(chǎn)系統(tǒng)的最大的挑戰(zhàn),同時也是最重要的一步。因為這將決定你能否持續(xù)地改善生產(chǎn)系統(tǒng),并確保你在數(shù)據(jù)科學(xué)上的初期投資取得回報。
數(shù)據(jù)科學(xué)家和程序員:合作的模式
到目前為止,我們主要關(guān)注的是生產(chǎn)環(huán)境里的系統(tǒng)是什么樣。當(dāng)然對于如何保證生產(chǎn)系統(tǒng)穩(wěn)定和高效則有很多種方法。有時候,直接部署Python寫的模型就足夠了,但生產(chǎn)系統(tǒng)和探索分析部分的分離是肯定存在的。
你將會面對的艱巨挑戰(zhàn)之一就是如何協(xié)調(diào)數(shù)據(jù)科學(xué)家與程序員的合作?!皵?shù)據(jù)科學(xué)家”依然是一個新的角色,但他們所做的工作與典型的程序員有著明顯差異。由此導(dǎo)致的誤解和溝通障礙就不可避免了。
數(shù)據(jù)科學(xué)家的工作通常是探索性的。數(shù)據(jù)科學(xué)項目一般始于一個模糊的目標(biāo)、哪些數(shù)據(jù)可用的一些想法、以及可能的算法。但非常常見的情況是,數(shù)據(jù)科學(xué)家必須嘗試多種想法,并從數(shù)據(jù)里獲取洞察。數(shù)據(jù)科學(xué)家會寫很多的代碼,但是大部分都是用于測試想法,并不會被用于最終的解決方案。

圖6:圖片來自Mikio Braun的演講頁
與數(shù)據(jù)科學(xué)家相反,程序員通常非常關(guān)注于編程。他們的目標(biāo)是開發(fā)一個系統(tǒng),實現(xiàn)所要求的功能。程序員有時會做一些探索性的工作,比如構(gòu)建原型、驗證概念或是測試性能基準(zhǔn)。但他們的工作的主要目標(biāo)還是寫代碼。
他們間的不同還明顯地體現(xiàn)在代碼的變化上。程序員通常會堅持一個非常明確定義的代碼開發(fā)流程。一般包括創(chuàng)建自己工作流的分支,在開發(fā)完成后做評測檢查,然后把自己的分支合并進(jìn)主分支。大家可以并行開發(fā),但必須在協(xié)商后才能把他們的分支合并進(jìn)主分支。然后這個過程再重復(fù)進(jìn)行。這整個過程都是確保主分支會以一個有序的方式演進(jìn)。

圖7:圖片來自Mikio Braun的演講頁
數(shù)據(jù)科學(xué)家也會寫很多的代碼。但正如我之前所說的,這些代碼通常是為了驗證想法。所以數(shù)據(jù)科學(xué)家可能是會寫出一個版本1,但它并沒有實現(xiàn)需求。然后又針對一個新的想法寫了版本2,隨后是2.1和2.2,直到發(fā)現(xiàn)還是不能實現(xiàn)需求而停止。再對更新的想法去寫版本3和3.1。也許在這個時候,數(shù)據(jù)科學(xué)家意識到,如果采用2.1版里的某些方法并結(jié)合3.1版里的某些方法,就能獲得一個更好的解決方案。這就帶來了版本3.3和3.4,并可能由此形成了最終解決方案。

圖8:圖片來自Mikio Braun的演講頁
一個有意思的事情是,數(shù)據(jù)科學(xué)家實際上可能希望保留所有這些沒成功的版本。因為之后的某個時間,也許它們又會被拿來測試新的想法。也許有些部分可以被放入一個“工具箱”里,逐步形成數(shù)據(jù)科學(xué)家自己的私人機器學(xué)習(xí)庫。程序員更希望去刪除“無用的代碼”(因為他們知道如何快速地找回這些代碼),而數(shù)據(jù)科學(xué)家則喜歡保留代碼以防萬一。
上述的兩大不同意味著,在現(xiàn)實中,直接讓程序員和數(shù)據(jù)科學(xué)家共同工作可能會出問題。標(biāo)準(zhǔn)的軟件工程流程對數(shù)據(jù)科學(xué)家的探索性工作模式并不合適,因為他們的目標(biāo)是不同的。引入代碼評測檢查和有序的分支管理、評測、合并分支的工作流對數(shù)據(jù)科學(xué)家而言并不合適,還會減慢他們的工作。同樣的,把探索性的模式引入生產(chǎn)系統(tǒng)開發(fā)也不會成功。
為此,如何才能構(gòu)建一個合作模式來保證兩邊都能高產(chǎn)出的工作?可能第一直覺就是讓他們相互分離地工作。例如,完全分開代碼庫,并讓數(shù)據(jù)科學(xué)家獨立工作,產(chǎn)出需求文檔,再由程序員團隊實現(xiàn)。這種方法也行得通,但流程通常會非常得慢,且容易出錯。因為重新開發(fā)實現(xiàn)一遍就可能會引入錯誤,尤其是在程序員并不熟悉數(shù)據(jù)分析算法的情況下。同時能否進(jìn)行外部迭代來改進(jìn)系統(tǒng)的表現(xiàn)也依賴于程序員是否有足夠的能力來實現(xiàn)數(shù)據(jù)科學(xué)家的需求。

圖9:圖片來自Mikio Braun的演講頁
幸運的是,很多數(shù)據(jù)科學(xué)家實際上是希望能成為好的程序員,或是反過來。所以我們已經(jīng)開始試驗一些更直接和更能幫助加快流程的合作模式,
例如,數(shù)據(jù)科學(xué)家和程序員的代碼庫依然是分離的,但部分生產(chǎn)系統(tǒng)會提供清晰定義的接口來方便數(shù)據(jù)科學(xué)家把他們的方法嵌入進(jìn)系統(tǒng)。與這些生產(chǎn)系統(tǒng)的接口進(jìn)行溝通的代碼必須嚴(yán)格地依據(jù)軟件開發(fā)實踐流程,但這是數(shù)據(jù)科學(xué)家的工作。用這種方式,數(shù)據(jù)科學(xué)團隊可以在自己的代碼快速地迭代,同時也就是完成了對生產(chǎn)系統(tǒng)的迭代。

圖10:圖片來自Mikio Braun的演講頁
這種架構(gòu)模式的一個具體實現(xiàn)是采用“微服務(wù)”方法。即讓生產(chǎn)系統(tǒng)去調(diào)用數(shù)據(jù)科學(xué)家團隊開發(fā)的微服務(wù)來獲取推薦。用這個方式,整個數(shù)據(jù)科學(xué)家使用的離線分析管道還可以被調(diào)整用來做A/B測試,甚至是加入生產(chǎn)系統(tǒng)而不用程序員團隊重新開發(fā)實現(xiàn)。這種模式會要求數(shù)據(jù)科學(xué)家具有更多的軟件工程技能,但我們看到越來越多的數(shù)據(jù)科學(xué)家已經(jīng)具有這樣的技能集。事實上,后來我們修改了Zalando的數(shù)據(jù)科學(xué)家的職銜為“研究工程師(數(shù)據(jù)科學(xué))”來反應(yīng)這種實際情況。
采用類似這樣的方法,數(shù)據(jù)科學(xué)家可以快速實踐,對離線數(shù)據(jù)做迭代研究,并在生產(chǎn)系統(tǒng)環(huán)境里迭代開發(fā)。整個團隊可以持續(xù)地把穩(wěn)定的數(shù)據(jù)分析方法遷移進(jìn)生產(chǎn)系統(tǒng)。
持續(xù)適應(yīng)并改進(jìn)
至此,我概述了一個能把數(shù)據(jù)科學(xué)引入生產(chǎn)系統(tǒng)的架構(gòu)的典型模式。需要理解的一個關(guān)鍵概念就是這樣的系統(tǒng)需要持續(xù)地適應(yīng)并改進(jìn)(這和幾乎所有的針對實際數(shù)據(jù)的數(shù)據(jù)驅(qū)動項目類似)。能夠快速迭代,實驗新的方法,使用A/B測試驗證結(jié)果,這一切都非常重要。
依據(jù)我的經(jīng)驗,保持?jǐn)?shù)據(jù)科學(xué)家團隊和程序員團隊的分離是不可能達(dá)成這些目標(biāo)的。與此同時,很重要的是我們也要承認(rèn)他們兩個團隊的工作方式確實是不同的,因為他們的目標(biāo)不一樣(數(shù)據(jù)科學(xué)家的工作更加具有探索性,而程序員更關(guān)注于開發(fā)軟件和系統(tǒng))。通過允許各自團隊能工作在更適合他們的目標(biāo)的方式,并定義一些清晰的接口,是有可能集成兩個團隊,并保證新的方法可以被快速地試錯的。這會要求數(shù)據(jù)科學(xué)家團隊具有更多的軟件工程技能,或是至少能有軟件工程師來橋接起兩個世界。
Mikio Braun
Mikio Braun是Zalando的推薦和搜索系統(tǒng)的交付帶頭人。Zalando是歐洲最大的時尚品平臺之一。Mikio擁有機器學(xué)習(xí)的博士學(xué)位,并在投身把研究成果轉(zhuǎn)化成行業(yè)應(yīng)用前進(jìn)行了多年的研究工作。

