領英(LinkedIn)高度依賴人工智慧技術為其超過 5.75 億的會員提供原創內容,並創造賺錢的機會。隨著最近深度學習技術的快速發展,我們的人工智慧工程師們已經開始在由相關性驅動的領英產品中使用深度神經網路,包括 feed 流訂閱和智慧回覆(Smart Replies)。許多這類用例都是構建在 TensorFlow 平臺上的,TensorFlow 是一個由谷歌編寫的流行的深度學習框架。
起初,我們內部的 TensorFlow 使用者在小型、缺乏管理的「裸機」叢集上執行這套框架。但是,我們很快意識到,我們需要將 TensorFlow 與基於 Hadoop 的大資料平臺的強大計算和儲存能力結合在一起。在我們的 Hadoop 叢集中儲存了數百 PB 的資料,這些資料可以被用於深度學習。因此,我們需要一種可擴充套件的方式處理所有這些資訊。幸運的是,TensorFlow 支援分散式訓練,這是一種有效的處理大型資料集的技術。然而,構建分散式 TensorFlow 框架並非易事,也不是所有資料科學家和相關的工程師都具備所需的專業知識,或想要這樣做——尤其是因為這項工作必須手動完成。我們想要一種靈活、可持續的方式將分散式 TensorFlow 的分析能力和 Hadoop 的擴充套件能力結合起來。
開源 TonY
為了滿足以上需求,我們在 YARN 上構建了 TensorFlow on YARN(TonY),同時我們也知道很多對分散式機器學習感興趣的人正在執行大型 Hadoop 部署,所以我們決定將該專案開源。使用細節見 TonY 專案 Github 連結。
地址:https://github.com/linkedin/TonY。
下面將介紹 TonY 的內部細節、我們實施並用來在 Hadoop 上擴充套件分散式 TensorFlow 的功能以及實驗結果。
現有的解決方案
在 Hadoop 上執行分散式 TensorFlow 的初步探索中,我們找到了幾個現有的解決方案,但最終發現沒有一個方案可以滿足自己的需求,因此我們決定構建 TonY。
TensorFlow on Spark 是來自 Yahoo 一種開源解決方案,使得使用者可以在 Apache Spark 計算引擎上執行 TensorFlow。我們得以在這一框架上搭載我們的內部深度學習應用,但也遇到了幾個問題,最顯著的問題是缺乏 GPU 排程和異構容器排程。此外,我們將來想要做的任何排程和應用程式生命週期增強都必須在 Spark 中完成,這比在獨立的 YARN 應用程式中進行更改要困難得多。
另一個開源解決方案是 Intel BigData 組研發的 TensorFlowOnYARN。但是,這一專案的容錯支援和可用性不能滿足我們的需要。而且,該專案已經終止。
出於以上種種原因,我們決定構建 TonY 以實現我們對 Hadoop 群集資源的完全控制。此外,由於 TonY 直接在 YARN 上執行,而且執行時屬於輕量級依賴,我們可以輕鬆地使其與 YARN 堆疊的較低階部分或 TensorFlow 中的較高階部分一起進化。
TonY 是如何工作的?
類似於 MapReduce 提供的在 Hadoop 上執行 Pig/Hive 指令碼的引擎,Spark 提供使用 Spark API 執行 scala 程式碼的引擎,TonY 旨在通過處理資源協商和容器環境設定等任務,為在 Hadoop 上執行 TensorFlow 作業提供同樣頂級的支援。
在 YARN 的 TonY 上執行 TensorFlow
- TonY 主要包含三個要素:Client、ApplicationMaster 和 TaskExecutor。執行 TonY 作業的端到端處理過程如下:
- 使用者向 Client 提交 TensorFlow 模型訓練程式碼、引數及其 Python 虛擬環境(包含 TensorFlow 依賴)。
- Client 設定 ApplicationMaster(AM)並將其提交給 YARN 叢集。
- AM 與 YARN 基於使用者資源請求的資源管理(Resource Manager)進行資源協商(引數伺服器及執行緒、記憶體和 GPU 的數量)。
- 一旦 AM 收到分配,它就會在分配的節點上生成 TaskExecutor。
- TaskExecutor 啟動使用者的訓練程式碼並等待其完成。
- 使用者的訓練程式碼啟動,TonY 定期在 TaskExecutor 和 AM 之間跳動,以檢查其活性。
TonY 的架構
除了支援在 Hadoop 上執行分散式 TensorFlow 作業的基本功能之外,TonY 還實現了各種功能來改善執行大規模訓練的體驗:
- GPU 排程:最近,YARN 增加了對 GPU 排程和隔離的本地支援。這意味著使用者可以確保一旦從 YARN 接收到容器分配,他們就能可靠地獲取自己請求的 GPU 數量。TonY 搭建在 YARN 基礎上,於是也有 GPU 資源意識,因此它能夠利用 Hadoop 的 API 從叢集中請求 GPU 資源。
- 細粒度的資源請求:由於 TonY 支援請求不同的實體(如引數伺服器和執行緒)作為單獨的元件,使用者可以對每種型別進行不同的資源請求。例如,引數伺服器和執行緒可能有不同的記憶體需求。使用者還可能想在 GPU 或其它一些專用硬體上執行訓練,但是在引數伺服器上使用 CPU 就足夠了。這意味著更多地控制使用者應用程式的資源需求,對於叢集管理來說,這有助於避免昂貴硬體的資源浪費。
- TensorBoard 支援:TensorBoard 是一種工具,可以使 TensorFlow 程式更易理解、調優和優化。由於 TensorBoard 是由一個執行緒在應用程式未知的地方啟動的,因此我們通常無法從 Hadoop UI 中看到 TensorBoard。我們最近向 YARN 提供了程式碼,允許我們將 Hadoop 應用程式的跟蹤 URL 重定向至 TensorBoard,這樣僅需點選一下就可以檢視 TensorBoard 了。
- 容錯:TensorFlow 訓練可能需要幾個小時或幾天,要使用大量機器。因此,長時間執行的 TensorFlow 作業比短時間執行的作業更容易受到瞬時錯誤或搶佔的影響。TensorFlow 包含容錯 API,用於將檢查點儲存到 HDFS,並根據以前儲存的檢查點恢復訓練狀態。TonY 通過提供一個彈性分散式基礎設施來從節點故障中恢復,從而促進了這一過程。如果一個執行緒沒有跳躍到 AM 或者超時,TonY 將重新啟動應用程式,並從以前的檢查點恢復訓練。
實驗結果
我們在 TonY 上執行了 Inception v3 模型,有 1 到 8 個執行緒,每個執行緒有一個 GPU,使用非同步訓練(也有一個執行在八個執行緒上使用 CPU 訓練)。該模型是 ImageNet 的一個著名的深層神經網路,而 ImageNet 資料集包含了數百萬幅用於訓練影像分類模型的影像。正如在 Inception v3 分散式訓練示例中一樣,我們測量了批大小為 32 時,達到 10 萬步所需的時間。結果如下:
這些結果是在 RHEL 6.6 和 TensorFlow 1.9 上得出的,每個執行緒上一個 CPU 的記憶體是 40G,使用的 GPU 是 Tesla K80 GPU。接受 GPU 訓練的 8 個執行緒在達到 10 萬步後,最終的前 5 名錯誤率為 26.3 %。
由於 TonY 在編排分散式 TensorFlow 的層中,並且不干擾 TensorFlow 作業的實際執行,我們預計這部分不會有開銷。實際上,我們看到,對於 GPU 訓練,執行時間線性擴充套件。我們還發現,執行 GPU 訓練的速度比 CPU 訓練快了大約四倍,考慮到模型的複雜性和深度,這種結果不出所料。
原文連結:https://engineering.linkedin.com/blog/2018/09/open-sourcing-tony—native-support-of-tensorflow-on-hadoop