Uber 工程師們一直致力於開發各種新技術,以讓客戶得到有效、無縫的用戶體驗。現在,他們正在加大對人工智慧、機器學習領域的投入來實現這個願景,「米開朗基羅平臺」因此產生。本文譯自「Meet Michelangelo: Uber’s Machine Learning Platform」 (by Jeremy Hermann and Mike Del Balso),主要講解Uber研發的機器學習平臺-米開朗基羅,下面請看詳細內容~
在 Uber,工程師們開發出了一個名為「米開朗基羅」(Michelangelo)的機器學習平臺,它是一個內部的「MLaaS」(機器學習即服務)平臺,用以降低機器學習開發的門檻,並能根據不同的商業需求對 AI 進行拓展與縮放,就有如客戶使用 Uber 打車一樣方便。
米開朗基羅平臺可以讓公司內部團隊無縫構建、部署與運行 Uber 規模的機器學習解決方案。它旨在覆蓋全部的端到端機器學習工作流,包括:數據管理、訓練模型、評估模型、部署模型、進行預測、預測監控。此系統不僅支持傳統的機器學習模型,還支持時間序列預測以及深度學習。
米開朗基羅在 Uber 投產約一年時間,已經成為了 Uber 工程師、數據科學家真正意義上的「平臺」,現在有數十個團隊在此平臺上構建、部署模型。實際上,米開朗基羅平臺現在部署於多個 Uber 數據中心並使用專用硬體,用於為公司內最高負載的在線服務提供預測功能。
本文將介紹米開朗基羅以及其產品用例,並簡單通過這個強大的MLaaS 系統介紹整個機器學習工作流。
在米開朗基羅平臺出現前,Uber 的工程師和數據科學家們在構建、部署一些公司需要,並且能根據實際操作進行規模拓展的機器學習模型時,遇到了很多挑戰。那時他們試圖使用各種各樣的工具來創建預測模型(如 R 語言、scikit-learn、自定義算法等),此時工程團隊會構建一些一次性的系統以使用這些模型進行預測。因此,在 Uber 內能夠在短時間內使用各種開源工具構建出框架的數據科學家與工程師少之又少,限制了機器學習在公司內的應用。
具體來說,那時沒有建立一個可靠、統一、pipeline 可復用的系統用於創建、管理、訓練、預測規模化數據。因此在那時,不會有人做出數據科學家的臺式機跑不了的模型,也沒有一個規範的結果存儲方式,要將幾個實驗結果進行對比也是相當困難的事情。更重要的是,那時沒有一種將模型部署到生產環境的確定方法。因此,大多數情況下都是相關的工程團隊不得不為手中的項目開發定製的服務容器。這時,他們注意到了這些跡象符合由 Scully 等人記錄的機器學習的反模式一文的描述。
米開朗基羅旨在將整個團隊的工作流程和工具標準化,通過端對端系統讓整個公司的用戶都能輕鬆構建、運行大型機器學習系統。但是工程師們的目標不僅限於解決這些直觀的問題,更是要創立一個能與業務共同發展的體系。
當工程師們於 2015 年年中開始構建米開朗基羅系統時,他們也開始解決一些規模化模型訓練以及一些將模型部署於生產環境容器的問題。接著,他們專注於構建能夠更好進行管理、共享特徵 pipeline 的系統。而最近,他們的重心轉移到了開發者生產效率 — 如何加速從想法到產品模型的實現以及接下來的快速迭代。
下一節將通過一個樣例來介紹如何使用米開朗基羅構建、部署一個模型,用於解決 Uber 的某種特定問題。雖然下面重點講的是 UberEATS 中的具體用例,但是這個平臺也管理著公司裡其他針對多種預測用例的類似模型。
UberEATS 在米開朗基羅中有數個模型在運行,包括送餐到達時間預測、搜索排行、搜索自動完成、餐廳排行等。送餐到達時間預測模型能夠預測準備膳食、送餐以及送餐過程中的各個階段所需的時間。
圖 1:UberEATSapp 提供了估測外賣送達時間的功能,此功能由基於米開朗基羅構建的機器學習模型驅動
預測外賣的送達時間(ETD)並不是一件簡單的事情。當 UberEATS用戶下單時,訂單將被送到餐廳進行處理。餐廳需要確認訂單,根據訂單的複雜度以及餐廳的繁忙程度準備餐品,這一步自然要花費一些時間。在餐品快要準備完畢的時候,Uber 外賣員出發去取餐。接著,外賣員需要開車到達餐廳、找到停車場、進餐廳取餐、回到車裡、開車前往客戶家(這個步驟耗時取決於路線、交通等因素)、找到車位、走到客戶家門口,最終完成交貨。UberEATS 的目標就是預測這個複雜的多階段過程的總時間,並在各個步驟重新計算ETD。
在米開朗基羅平臺上,UberEATS 數據科學家們使用了 GBDT(梯度提升決策樹)回歸模型來預測這種端到端的送達時間。此模型使用的特徵包括請求信息(例如時間、送餐地點)、歷史特徵(例如餐廳在過去 7 天中的平均餐食準備時間)、以及近似實時特徵(例如最近一小時的平均餐食準備時間)。此模型部署於 Uber 數據中心的米開朗基羅平臺提供的容器中,通過 UberEATS 微服務提供網絡調用。預測結果將在餐食準備及送達前展示給客戶。
米開朗基羅系統由一些開源系統和內置組件組成。主要使用的開源組件有 HDFS、Spark、Samza、Cassandra、MLLib、XGBoost、TensorFlow。在條件允許的前提下,開發團隊更傾向於使用一些成熟的開源系統,並會進行 fork、定製化,如果有需求的話也會對其進行貢獻。如果找不到合適的開源解決方案,他們也會自己構建一些系統。
米開朗基羅系統建立與 Uber 的數據及計算基礎設施之上,它們提供了一個「數據湖」,其中包含了 Uber 所有的事務和日誌數據。由 Kafka 對 Uber 的所有服務日誌進行採集匯總,使用 Cassandra 集群管理的 Samza 流計算引擎以及 Uber 內部服務進行計算與部署。
在下一節中將以 UberEATS 的 ETD 模型為例,簡單介紹系統的各個層次,說明米開朗基羅的技術細節。
在 Uber,大多數的機器學習用例(包括一些正在做的工作,例如分類、回歸以及時間序列預測等)都有著一套同樣的工作流程。這種工作流程可以與具體實現分離,因此很容易進行拓展以支持新的算法和框架(例如最新的深度學習框架)。它還適用於各種不同預測用例的部署模式(如在線部署與離線部署,在車輛中使用與在手機中使用)。
米開朗基羅專門設計提供可拓展、可靠、可重用、易用的自動化工具,用於解決下面 6 步工作流:
下面將詳細介紹米開朗基羅的架構是如何促進工作流中的各個步驟的。
找出良好的特徵經常是是機器學習最難的部分,工程師們也發現整個機器學習解決方案中最費時費力的部分就是構建及管理數據管道。
因此,平臺應提供一套標準工具以構建數據管道,生成特徵,對數據集進行標記(用於訓練及再訓練),以及提供無標記特徵數據用以預測,這些工具需要與公司的數據湖、數據中心以及公司的在線數據服務系統進行深度的整合。構建出來的數據管道必須具有可縮放性以及足夠的性能,能夠監控數據流以及數據質量,為各種在線/離線訓練與預測都提供全面的支持。這些工具還應該能通過團隊共享的方式生成特徵,以減少重複工作並提高數據質量。此外,這些工具應當提供強有力的保護措施,鼓勵用戶去採用最好的方式使用工具(例如,保證在訓練時和預測時都採用同一批次生成的數據)。
米開朗基羅的數據管理組件分為在線管道和離線管道。目前,離線管道主要用於為批量模型訓練以及批量預測作業提供數據;在線管道主要為在線、低時延預測作業提供數據(以及之後會為在線學習系統提供支持)。
此外,工程師們還為數據管理層新加了一個特徵存儲系統,可以讓各個團隊共享、發現高質量的數據特徵以解決他們的機器學習問題。工程師們發現,Uber 的許多模型都是用了類似或相同的特徵,而在不同組織的團隊以及團隊裡的不同項目中共享特徵是一件很有價值的事情。
圖 2:數據預處理管道將數據存入特徵庫以及訓練數據倉庫中
Uber 的事務與日誌數據會「流入」一個 HDFS 數據湖中,可以使用 Spark 和 Hive SQL 的計算作業輕鬆調用這些數據。平臺提供了容器與計劃任務兩種方式運行常規作業,用於計算項目內部的私有特徵或將其發布至特徵存儲庫(見後文)與其他團隊共享。當計劃任務運行批量作業或通過別的方式觸發批量作業時,作業將被整合傳入數據質量監控工具,此工具能夠快速回溯找出問題出在 pipeine 中的位置,判明是本地代碼的問題還是上遊代碼的問題導致的數據錯誤。
在線部署的模型將無法訪問 HDFS 存儲的數據,因此,一些需要在Uber 生產服務的支撐資料庫中讀取的特徵很難直接用於這種在線模型(例如,無法直接查詢 UberEATS 的訂單服務去計算某餐廳某特定時間段平均膳食準備時間)。因此,工程師們將在線模型需要的特徵預計算並存儲在 Cassandra 中,線上模型可以低延遲讀取這些數據。
在線部署支持兩種計算系統:批量預計算與近實時計算,詳情如下:
✔ 批量預計算。這個系統會定期進行大批量計算,並將 HDFS 中的特徵歷史記錄加載進 Cassandra 資料庫中。這樣做雖然很簡單粗暴,但是如果需要的特徵對實時性要求不高(比如允許隔幾小時更新一次),那麼效果還是很好的。這個系統還能保證在批處理管道中用於訓練和服務的數據是同批次的。UberEATS 就採用了這個系統處理一部分特徵,如「餐廳過去七天的膳食平均準備時間」。
✔ 近實時計算。這個系統會將相關指標發布至 Kafka 系統,接著運行 Samza 流計算作業以低時延生成所有特徵。接著這些特徵將直接存入 Cassandra 資料庫用於提供服務,並同時備份至 HDFS 用於之後的訓練作業。和批量預計算系統一樣,這樣做同樣能保證提供服務和進行訓練的數據為同一批次。為了避免這個系統的冷啟動,工程師們還專門為這個系統製作了一個工具,用於「回填」數據與基於歷史記錄運行批處理生成訓練數據。UberEATS 就使用了這種近實時計算 pipeline 來得到如「餐廳過去一小時的膳食平均準備時間」之類的特徵。
工程師們發現建立一個集中的特徵庫是很有用的,這樣 Uber 的各個團隊可以使用其他團隊創建和管理的可靠的特徵,且特徵可以被分享。從大方向上看,它做到了以下兩件事情:
✔ 它可以讓用戶輕鬆地將自己構建的特徵存入共享特徵庫中(只需要增加少許元數據,如添加者、描述、SLA 等),另外它也能讓一些特定項目使用的特徵以私有形式存儲。
✔ 只要特徵存入了特徵庫,那之後再用它就十分簡單了。無論是在線模型還是離線模型,都只要簡單地在模型配置中寫上特徵的名稱就行了。系統將會從 HDFS 取出正確的數據,進行處理後返回相應的特徵集既可以用於模型訓練,也可以用於批量預測或者從 Cassandra 取值做在線預測。
目前,Uber 的特徵庫中有大約 10000 個特徵用於加速機器學習工程的構建,公司的各個團隊還在不斷向其中增加新的特徵。特徵庫中的特徵每天都會進行自動計算與更新。
未來,工程師們打算構建自動化系統,以進行特徵庫搜索並找出解決給定預測問題的最有用的特徵。
用於特徵選擇及轉換的領域特定語言(DSL)。
由數據 pipeline 生成的特徵與客戶端服務傳來的特徵經常不符合模型需要的數據格式,而且這些數據時常會缺失一些值,需要對其進行填充;有時候,模型可能只需要傳入的特徵的一個子集;還有的時候,將傳入的時間戳轉換為小時/天 或者 天/周 會在模型中起到更好的效果;另外,還可能需要對特徵值進行歸一化(例如減去平均值再除以標準差)。
為了解決這些問題,工程師們為建模人員創造了一種 DSL(領域特定語言),用於選擇、轉換、組合那些用於訓練或用於預測的特徵。這種 DSL 為 Scala 的子集,是一種純函數式語言,包含了一套常用的函數集,工程師們還為這種 DSL 增加了自定義函數的功能。這些函數能夠從正確的地方取出特徵(離線模型從數據pipeline 取特徵值,在線模型從客戶請求取特徵值,或是直接從特徵庫中取出特徵)。
此外,DSL 表達式是模型配置的一部分,在訓練時取特徵的 DSL 與在與測試時用的 DSL 需要保持一致,以確保任何時候傳入模型的特徵集的一致性。
目前平臺支持離線、大規模分布式訓練,包括決策樹、線性模型、邏輯模型、無監督模型(k-means)、時間序列模型以及深度神經網絡。工程師們將定期根據用戶的需求增加一些由 Uber AI 實驗室新開發的模型。此外,用戶也可以自己提供模型類型,包括自定義訓練、評價以及提供服務的代碼。分布式模型訓練系統可以規模化處理數十億的樣本數據,也可以處理一些小數據集進行快速迭代。
一個模型的配置包括模型類型、超參、數據源、特徵 DSL,以及計算資源需求(需要的機器數量、內存用量、是否使用 GPU 等)。這些信息將用於配置運行在 YARN或 Mesos集群上的訓練作業。
在模型訓練完畢之後,系統會將其計算得到的性能指標(例如 ROC 曲線和PR 曲線)進行組合,得到一個模型評價報告。在訓練結束時,系統會將原始配置、學習到的參數以及評價包括存回模型庫,用於分析與部署。
除了訓練單個模型之外,米開朗基羅系統還支持對分塊模型等各種模型進行超參搜索。以分塊模型為例,以分塊模型為例,系統會根據用戶配置自動對訓練數據進行分塊,對每個分塊訓練一個模型;在有需要的時候再將各個分塊模型合併到父模型中(例如,先對每個城市數據進行訓練,如果無法得到準確的市級模型時再將其合併為國家級模型)。
訓練作業可以通過 Web UI 或者 API 進行配置與管理(通常使用 Jupyternotebook)。大多數團隊都使用 API 以及流程管理工具來對他們的模型進行定期重訓練。
圖 3:模型訓練作業使用特徵庫與數據訓練倉庫中的數據集來訓練模型,接著將模型存入模型庫中
訓練模型可以看成是一種尋找最佳特徵、算法、超參以針對問題建立最佳模型的探索過程。在得到用例的理想模型前,訓練數百種模型而一無所獲也是常有的事。雖然這些失敗的模型最終不能用於生產,但它們可以指導工程師們更好地進行模型配置,從而獲得更好的性能。追蹤這些訓練過的模型(例如誰、何時訓練了它們,用了什麼數據集、什麼超參等),對它們的性能進行評估、互相對比,可以為平臺帶來更多的價值與機會。不過要處理如此之多的模型,也是一個極大的挑戰。
米開朗基羅平臺中訓練的每個模型都需要將以下信息作為版本對象存儲在 Cassandra 的模型庫中:
✔ 誰訓練的模型。
✔ 訓練模型的開始時間與結束時間。
✔ 模型的全部配置(包括用了什麼特徵、超參的設置等)。
✔ 引用訓練集和測試集。
✔ 描述每個特徵的重要性。
✔ 模型準確性評價方法。
✔ 模型每個類型的標準評價表或圖(例如 ROC 曲線圖、PR 曲線圖,以及二分類的混淆矩陣等)。
✔ 模型所有學習到的參數。
✔ 模型可視化摘要統計。
用戶可以通過 Web UI 或者使用 API 輕鬆獲取這些數據,用以檢查單個模型的詳細情況或者對多個模型進行比較。
回歸模型的準確率報告會展示標準的準確率指標與圖表;分類模型的準確率報告則會展示不同的分類集合,如圖 4 圖 5 所示:
圖 4:回歸模型的報告展示了與回歸相關的性能指標
圖 5:二分類模型報告展示了分類相關的性能指標
決策樹作為一種重要的模型類型,工程師們為其提供了可視化工具,以幫助建模者更好地理解模型的行為原理,並在建模者需要時幫助其進行調試。例如在一個決策樹模型中,用戶可以瀏覽每個樹分支,看到其對於整體模型的重要程度、決策分割點、每個特徵對於某個特定分支的權重,以及每個分支上的數據分布等變量。用戶可以輸入一個特徵值,可視化組件將會遍歷整個決策樹的觸發路徑、每個樹的預測、整個模型的預測,將數據展示成類似下圖的樣子:
圖 6:使用強大的樹可視化組件查看樹模型
米開朗基羅提供了特徵報告,在報告中使用局部依賴圖以及混合直方圖展示了各個特徵對於模型的重要性。選中兩個特徵可以讓用戶看到它們之間相互的局部依賴圖表,如下所示:
圖 7:在特徵報告中可以看到的特徵、對模型的重要性以及不同特徵間的相關性
米開朗基羅支持使用 UI 或 API 端對端管理模型的部署。一個模型可以有下面三種部署方式:
離線部署。模型將部署於離線容器中,使用 Spark 作業,根據需求或計劃任務進行批量預測。
在線部署。模型將部署於在線預測服務集群(集群通常為使用負載均衡部署的數百臺機器),客戶端可以通過網絡 RPC 調用發起單個或批量的預測請求。
部署為庫。工程師們希望能在服務容器中運行模型。可以將其整合為一個庫,也可以通過 Java API 進行調用(在下圖中沒有展示此類型,不過這種方式與在線部署比較類似)。
圖 8:模型庫中的模型部署於在線及離線容器中用於提供服務
上面所有情況中,所需要的模型組件(包括元數據文件、模型參數文件以及編譯好的 DSL)都將被打包為 ZIP 文件,使用 Uber 的標準代碼部署架構將其複製到 Uber 數據中心的相關數據上。預測服務容器將會從磁碟自動加載新模型,並自動開始處理預測請求。
許多團隊都自己寫了自動化腳本,使用米開朗基羅 API 進行一般模型的定期再訓練及部署。例如 UberEATS 的送餐時間預測模型就由數據科學家和工程師通過 Web UI 控制進行訓練與部署。
一旦模型部署於服務容器並加載成功,它就可以開始用於對數據管道傳來的特徵數據或用戶端發來的數據進行預測。原始特徵將通過編譯好的 DSL 傳遞,如有需要也可以對 DSL 進行修改以改進原始特徵,或者從特徵存儲庫中拉取一些額外的特徵。最終構造出的特徵向量會傳遞給模型進行評分。如果模型為在線模型,預測結果將通過網絡傳回給客戶端。如果模型為離線模型,預測結果將被寫回 Hive,之後可以通過下遊的批處理作業或者直接使用 SQL 查詢傳遞給用戶,如下所示:
圖 9:在線預測服務及離線預測服務使用一組特徵向量生成預測結果
在米開朗基羅平臺中可以同時向服務容器部署多個模型。這也使得從舊模型向新模型進行無痛遷移以及對模型進行A/B 測試成為可能。在服務中,可以由模型的 UUID 以及一個在部署時可指定的 tag(或者別名)識別不同的模型。以一個在線模型為例,客戶端服務會將特徵向量與需要使用的模型 UUID 或者 tag 同時發送給服務容器;如果使用的是 tag,服務容器會使用此 tag 對應的最新部署的模型進行預測。如果使用的是多個模型,所有對應的模型都將對各批次的數據進行預測,並將 UUID 和 tag 與預測結果一同傳回,方便客戶端進行篩選過濾。
如果在部署一個新模型替換舊模型時用了相同的事物(例如用了一些同樣的特徵),用戶可以為新模型設置和舊模型一樣的 tag,這樣容器就會立即開始使用新模型。這可以讓用戶只需要更新模型,而不用去修改他們的客戶端代碼。用戶也可以通過設置 UUID 來部署新模型,再將客戶端或中間件配置中舊模型的 UUID 換成新的,逐步將流量切換到新模型去。
如果需要對模型進行 A/B 測試,用戶可以通過 UUID 或者 tag 輕鬆地部署競爭模型,再使用客戶端服務中的 Uber 實驗框架將部分流量導至各個模型,再對性能指標進行評估。
由於機器學習模型是無狀態的,且不需要共享任何東西,因此,無論是在線模式還是離線模式下對它們進行規模縮放都是一件輕而易舉的事情。如果是在線模型,工程師可以簡單地給預測服務集群增加機器,使用負載均衡器分攤負載。如果是離線預測,工程師可以給 Spark 設置更多的 executor,讓 Spark 進行並行管理。
在線服務的延遲取決於模型的類型與複雜度以及是否使用從Cassandra 特徵庫中取出的特徵。在模型不需要從 Cassandra 取特徵的情況下,P95 測試延遲小於 5 毫秒。在需要從Cassandra 取特徵時,P95 測試延遲仍小於 10 毫秒。目前用量最大的模型每秒能提供超過 250000 次預測。
當模型訓練完成並完成評價之後,使用的數據都將是歷史數據。監控模型的預測情況,是確保其在未來正常工作的重要保障。工程師需要確保數據管道傳入的是正確的數據,並且生產環境沒有發生變化,這樣模型才能夠進行準確的預測。
為了解決這個問題,米開朗基羅系統會自動記錄並將部分預測結果加入到數據 pipeline 的標籤中去,有了這些信息,就能得到持續的、實時的模型精確度指標。在回歸模型中,會將 R^2/決定係數、均方根對數誤差(RMSLE)、均方根誤差(RMSE)以及平均絕對值誤差發布至 Uber 的實時監控系統中,用戶可以分析指標與時間關係的圖標,並設置閾值告警:
圖 10:對預測結果進行採樣,與觀測結果進行比較得到模型準確指標
米開朗基羅系統的最後一個重要部分就是 API 層了,它也是整個系統的大腦。API 層包含一個管理應用,提供了 Web UI 以及網絡 API 兩種訪問方式,並與 Uber 的監控、報警系統相結合。同時該層還包含了用於管理批量數據管道、訓練作業、批量預測作業、模型批量部署以及在線容器的工作流系統。
米開朗基羅的用戶可以通過 Web UI、REST API 以及監控、管理工具直接與這些組件進行交互。
原文地址:https://eng.uber.com/michelangelo/
作者:Jeremy Hermann and Mike Del Balso
譯文地址:https://juejin.im/post/59c8b4d56fb9a00a4843b2a6
譯者:Isvih
米開朗基羅之後的構建工作也一直在進行,平臺各個層次也在不斷成熟,更高層的工具與服務都在開發計劃中,包括AutoML、模型可視化、在線學習、分布式深度學習等。之後本文原作者又發表了一篇「Scaling Machine Learning at Uber with Michelangelo」,介紹更多米開朗基羅的案例和技術。小編也會嘗試編譯給大家,一起看「米開朗基羅」更多神奇之處。
敏捷大數據求小星星啦~
如果您喜歡我們的平臺
就請移步到Github
幫我們點一下Star吧~
您的舉手之勞對我們的鼓勵
可大可大啦!
https://github.com/BriData/DBus
https://github.com/edp963/wormhole
https://github.com/edp963/moonbox
https://github.com/edp963/davinci
同時,也歡迎您加入微信群,和技術大神們點對點交流哦~
長按添加加群小助手
煩請告知小助手您的信息來源哦~如:「微信公眾號」、「知乎專欄」、「CSDN」、「今日頭條」等等~