一個雲端計算平臺主要解決三大類問題:計算、儲存和網路。在計算方面,愛奇藝大量使用虛擬化計算和容器雲端計算。相比於虛擬化技術,容器更加簡單便捷,不需要額外的硬體支援,近乎無損的提供GPU計算能力,可以快速的提供不同軟體環境,啟動時間短,成為首選的GPU計算承載方式。
訓練任務場景
我們的第一次嘗試從訓練任務容器化開始。一個典型的訓練任務和普通資料處理任務類似:訓練程式設定引數,從資料來源讀取資料,使用框架提供的API進行計算,輸出儲存點和最終模型,同時也會輸出日誌和一些事件資訊。
訓練任務容器化demo很快就完成了,我們拿著demo去和演算法同事溝通:
A:“首先需要把訓練框架和程式碼做成一個Docker映象,然後登入到我們容器雲平臺,啟動容器……”
B:“什麼是Docker/容器?可以直接跑訓練任務嗎?”演算法同事問。
A:“我們兩個星期後要上線,什麼時候可以給訓練任務服務?”
B:”有沒有一個方案可以讓演算法使用者在不瞭解容器的情況下使用訓練服務?最好兩個星期內做出來!“
PS:這個時候發現我們忽略了終端使用者的基礎情況:演算法工程師專注與演算法,關心平臺的易用性和實際訓練時間。通常沒有興趣瞭解容器、儲存等基礎服務,對計算效能幾乎沒有概念。
Runonce訓練服務
兩個星期後,我們開始測試了Runonce訓練服務。Runonce的最初設計目的是,讓使用者像使用虛擬機器一樣使用容器。Runonce底層設施是基於mesos容器雲環境。計算資源已容器方式的提供,所有容器使用統一映象。為了儲存使用者資料,容器使用了Ceph RBD網路塊儲存裝置作為RootFS。容器啟動點是一個sshd服務,作為使用者的登入入口。我們提供了特殊的檔案注入工具幫助使用者管理ssh key。
Runonce訓練服務功能簡單,開發量小,短時間完成上線。Runonce服務的使用者體驗沒有發生根本新的變化,可以很快上手。但是,缺點也很明顯。使用者對軟體環境完全控制,常常出現錯誤修改系統檔案引發的問題。這些問題很難跟蹤和調查,帶來很高的運維開銷。使用者是在使用shell來互動操作資源,通常會進行大量程式碼修改和除錯,實際使用GPU時間不多,最終體現是整體GPU利用率較低。由於塊儲存裝置不能進行共享,RUNONCE不支援資料集共享,也不能支援並行多工訓練,更加不支援分散式訓練。
因為Runonce服務存在無法修復的缺陷,我們決定開發一個新的訓練平臺。透過大量觀察使用者使用Runonce服務行為,我們總結出典型使用步驟:資料集上傳,編寫訓練程式碼,執行訓練任務,獲取訓練結果。這些步驟後面的核心是資料,而支援資料讀取的儲存方案是最關鍵的方案。
儲存選擇
如果需要進行資料共享,那麼網路儲存是最好的選擇。在對網路儲存選擇過程中,我們關注下面這些設計和指標:健壯性,伸縮性,吞吐量,併發,延遲。由於多數訓練框架都支援檔案系統介面,所以提供檔案介面是儲存的必須功能。綜合各個因素後,Jarvis使用的首選儲存平臺是Ceph物件儲存(RWG)。Ceph物件儲存有很好的併發效能,可以很容易的進行水平擴充套件,但物件儲存提供的介面是基於HTTP的S3介面,需要進行檔案API的封裝。
Jarvis儲存
Jarvis在S3上採用fuse檔案系統,用於支援檔案讀寫。S3 fuse對讀操作很友好,但是在寫功能上有很多限制,例如:不支援隨機寫,任何檔案修改都需要重新上傳整個檔案。Jarvis使用本地檔案作為快取,然後定期同步到Ceph物件儲存。因為同步會造成大量重複寫操作,Jarvis對寫操作做了劃分,一類是寫日誌這樣的小檔案操作,一類是模型同步等的大檔案操作。小檔案使用較短的同步週期,大檔案使用較長的同步週期。
Jarvis執行環境
在Jarvis上,訓練任務容器使用的是定製的映象,軟體環境是精確定義。映象啟動指令碼將訓練資料透過S3 fuse接入到容器內部,然後拉取gitlab程式碼,執行使用者訓練任務,同時將輸出資料同步到物件儲存上。這裡我們做一個小小的最佳化,軟體環境劃分為基礎映象和執行時指令碼映象。在基礎映象上,注入執行時指令碼映象內容。每次修改執行指令碼,可以不必更新基礎映象,大大加快了開發效率。
但是Jarvis很大程度的改變了使用者使用方法,使用者普遍反應使用更不方便。我們在除錯和狀態查詢上下了很大的功夫,提供了實時日誌展現網頁,同時還提供Tensorboard這樣的圖形化狀態檢視的功能。Tensorboard功能強大,但是記憶體消耗也比較大。於是,我們開發了輕量化指標收集器,將指標直接投遞到資料後臺,由資料後臺介面來進行展現。
在Jarvis平臺執行一段時間之後,我們沒有觀察到GPU利用率顯著提升。這樣結果讓我們很驚訝。我們發現,GPU利用率低的主要原因是,大多數任務沒有對最佳化資料讀取。這個問題在網路儲存環境下會更加突出。
儲存最佳化
網路儲存有以下這些特點:
· 高吞吐:讀寫速度很高
· 高併發:可以支援很高的併發讀寫
· 高延遲:發去請求到拿到第一個位元組的時間相對較長
· 掉隊現象:某些請求可能會過很長時間才返回
在網路儲存環境下,我們需要增加處理資料讀取和處理的併發數,儘量避免使用小檔案,放寬讀取資料順序的限制。
如果訓練資料檔案都是比較小的圖片,應該合併若干小檔案為一個tfrecord的大檔案,降低請求次數。目前,tensorflow在併發資料讀取處理支援做好,建議閱讀 Data Input Pipeline Performance。
申請容器時,使用者應該注意CPU資源的數量。如果CPU申請較少,資料處理速度慢,GPU處於等待資料空閒狀態。
同時,還應該做好資料的預處理。我們遇到一個案例,使用純文字的輸入資料,大量CPU時間花費在字串到數字轉換上。在將文字資料處理成二級制資料之後,訓練任務幾乎跑滿了GPU計算能力。
深度學習技術發展迅速,大量變革正在發生。很多端到端的平臺正在開發,例如Kubeflow,OpenPAI。這些平臺都想把深度學習做成完整的閉環功能,讓演算法工程師專注於資料和演算法。要實現這樣的功能,我們還有很長的路要走。