分佈式TensorFlow:在Spark上將谷歌的深度學習圖書館進行尺度變換

介紹

Arimo的日益增長的數據科學團隊包括研究和開發機器學習和深入學習新的方法和應用。

我們正在調查的一個主題是分佈式的深度學習。當數據集和模型非常大時,我們就會發現與深度學習相融合的模式和預測值的價值和品種。然而,如果數據或模型不適合機器的內存,培養大型模型可能就會很慢或很難。我們高興地看到谷歌開源了TensorFlow深度學習庫,這樣我們能夠在分佈式Spark環境中運行TensorFlow。

這篇文章是對Arimo的演講題目的概述:Spark的分佈式TensorFlow:2016年Spark東部峰會上提出了調試谷歌深度學習圖書館。

TensorFlow

2015年後期,谷歌大張旗鼓的開源了其深度學庫TensorFlow。在谷歌,TensorFlow生產從搜索到地圖、翻譯的各種產品應用,因此圖書館可以廣泛的開展大規模測試。一個谷歌白皮書介紹了進入TensorFlow設計的各種系統的考慮。該開源庫僅包含單機實現,可能是由於全分佈式版本對谷歌的基礎設施的依賴。 (註:谷歌現在已經開源其分佈式代碼)

為了研究TensorFlow的分佈式版本的功能,我們將單機版TensorFlow改編到Apache

Spark。 Apache Spark帶來了內存計算和可擴展的分佈式計算。我們的目標是要回答:“TensorFlow和Apache Spark能不能協同工作去提供一個強大的、可擴展的分佈式深度學習平台。”

體系架構

我們怎麼做?

TensorFlow有一個Python API用來構建計算圖表,然後再執行C++和用Scala編寫的Spark,並具有Java和Python的API,所以把Python作為實現語言是自然選擇。

對於Spark上的TensorFlow基本問題是如何分配的Spark神經網絡訓練。對於迭代map-reduce問題Spark是極好的解決方案,但訓練神經網絡不是map-reduce問題(見并行計算的13個矮人)。從谷歌中找一個線索,我們模仿他們的DownpourSGD架構。該DownpourSGD架構是一個數據并行設置,這意味着每個工人具有一個完整的模型,並且運行與其他工人不同的數據(數據并行),而不是在不同的機器上運行模型的不同部分(型號平行)。

分佈式TensorFlow:在Spark上將谷歌的深度學習圖書館進行尺度變換 |emailtry.com

分佈式TensorFlow:在Spark上將谷歌的深度學習圖書館進行尺度變換 |emailtry.com

圖1:左邊是來自谷歌的Distbelief紙圖,右邊是我們實現的示意圖

從本質上講,我們採取梯度下降法,並把它分為兩類:“計算梯度”并行“應用梯度(下降)”和在它們之間插入一個網絡邊界。

分佈式TensorFlow:在Spark上將谷歌的深度學習圖書館進行尺度變換 |emailtry.com

圖2:示意圖為司機和工作人員扮演的角色。

司機和工作人員發送並通過WebSockets接收數據。

Spark工人用不同步的計算梯度,周期性地發送它們的梯度回驅動程序(參數服務器),這個結果是結合了所有工人的梯度並把所得到的參數按工人的要求發送回給工人。

“DownpourSGD”這個名字來自於直覺,如果我們把梯度下降視為從山上流下來水滴,那麼工人的異步性就代表許多臨近的水滴都沿着不同的路徑通向相同的山谷。

分佈式TensorFlow:在Spark上將谷歌的深度學習圖書館進行尺度變換 |emailtry.com

實驗裝置

我們通過下列型號測試執行的伸縮能力

1.數據集大小

2.型號規格

3.計算面積

4.CPU VS GPU

數據集大小

Dataset Name Rows Columns Cells Description
MNIST 60,000 784 >39.2M 60K 28×28 images
Higgs 10,000,000 28 280M https://archive.ics.uci.edu/ml
Molecular 150,000 2,871 430M https://www.kaggle.com/c/

注意,大的兩個數據集之間,希格斯數據集中的行數大得多,而分子集是在數據點(行×列)的總數目比較大。這使模型在訓練過程中產生了一些有趣的結果。

型號規格

我們為每一個模型採用前饋網絡,主要用於簡單計算模型的大小,即重量和偏見的變量總數。

Dataset Hidden Layers Hidden Units Total Parameters
MNIST 2 1,024 1.8M
Higgs 3 2,048 14.3M
Molecular 3 2,048 8.5M

計算面積

我們單一機器的配置有12個CPU內核,以及24個節點的有4個CPU沒有GPU的一個AWS集群。我們使用Docker容器,以確保所有的節點具有相同的結構,各節點的硬件如下:

每台機器4核

每台機器1個執行人

每個執行人10GB內存

Spark 1.6.0

CPU VS GPU

最後,我們有8個節點的集群具有上述相同配置,但另外每個有一個GPU。 12核單一機器的配置也有4個GPU,可以根據需要被導通,但是TensorFlow默認只使用一個GPU。

結果

數據并行有益處,但網絡通信開銷迅速限制了其可擴展性。

擴展集群

我們證明了TensorFlow在Spark可以利用增加集群大小,但是集群型號所給予的更高的性能只能達到一個點。似乎網絡通信瓶頸性能和作用需要被明確,以確定瓶頸是否可以克服。

在一個側面說明,我們發現,只要數據足夠小,就適合在一台GPU性能優於其它架構的機器上運行,因為它不具備處理網絡開銷問題的功能,可以充分利用GPU的優勢為數學運算。

下圖總結了我們運行的各種模型的關鍵測試結果。一些關鍵的趨勢是明顯的:

分佈式TensorFlow:在Spark上將谷歌的深度學習圖書館進行尺度變換 |emailtry.com

關鍵信息:工人同步性有影響:使工人異步有幫助,但如果他們太不同步,就可能會減緩甚至阻止聚合。

分佈式TensorFlow:在Spark上將谷歌的深度學習圖書館進行尺度變換 |emailtry.com

關鍵信息:增加模型的大小減少了從數據并行中取得的成果。

分佈式TensorFlow:在Spark上將谷歌的深度學習圖書館進行尺度變換 |emailtry.com

關鍵信息:網絡通信與模型的大小成正比例變化。這使得隨着模型尺寸的增大訓練速度可預見的比例增速放緩。

分佈式TensorFlow:在Spark上將谷歌的深度學習圖書館進行尺度變換 |emailtry.com

關鍵信息:直到超過16個工人(在這裡64個內核)被介紹,它會成為網絡綁定系統。

總的來說,我們的實現提供有限的可擴展性因素。我們正在研究方法來減輕這些瓶頸,從而使訓練性能能夠與擴展并行。這仍然是一個有趣的研究方向,利用使用商業級Spark技術的優勢來分發TensorFlow。

GPU性能測試

分佈式TensorFlow:在Spark上將谷歌的深度學習圖書館進行尺度變換 |emailtry.com

圖4:培訓速度(行/分鐘)橫跨每個數據集的架構

在以上圖中,我們比較了各種實現的速度,包括本地和分佈式的GPU實現。這裡基本上有兩種相互競爭力,本地實現沒有數據并行且沒有網絡開銷。當我們看向右邊,數據集的行數方面變得更大,我們看到當地的GPU擊敗當地的CPU和GPU的集群,最終擊敗了沒有GPU實現的集群。這證實了我們已經知道的GPU加速數學運算。但是隨着數據庫變得更大,地方GPU實現使所有其他實現大大遜色。由於所有的數據集足夠小,可以適應內存,網絡成為了分佈式實現的瓶頸,而當地GPU沒有這樣的瓶頸,得到了兩全其美。

總結

我們的研究目標是開發一個可擴展、分佈式計算實現的深度學習。目前的項目證明, TensorFlow上的Apache Spark有實現的可能性,但我們還沒有達到我們的目標。

這種實現最適合於大型數據集、小型號,因為模型大小與網絡開銷線性相關。大型數據集讓我們充分利用了系統中的數據并行的優勢。

對於適合單台計算機上的數據,單機GPU提供了最快的速度。

對於大型數據集,使用有GPU的Spark集群包攬了速度和規模。

該項目是開源:https://github.com/adatao/tensorspark

未來的工作

l對於較大的模型,我們正在研究模型的并行和型號的壓縮,以提高性能。

l我們正在研究用更聰明的方式來更新計算參數,例如使用坐標下降或共軛梯度。

l更有效地擴展這個架構的一個重要的方法是,使用多個參數服務器分裂模型,該模型事實上是在TensorFlow以及DistBelief白皮書中所講述過的。我們當前的實現很容易造成駕駛員瓶頸。

附錄

在這個項目中,我們遇到了許多挑戰,我們用研究、試驗和錯誤以及純粹的執着克服了這些挑戰。我們分享我們所發現的,如果你願意的話就可以加入我們的工作。

GPU很快,但它不是萬能葯

GPU可以輕鬆獲得本地配置幾乎10倍的加速,同時由於網絡開銷GPU在Spark獲取2-3倍的速度提升。因此,一旦數據不再適用於單台機器的內存容量,Spark配置就變得有意義。

然而,GPU有自己的內存,如果矩陣大到無法適應有限的典型GPU內存,GPU內存就可能成為瓶頸。如果你的模型不適合於GPU內存,型號并行可能比數據并行更有意義。

我們使用AWS GPU實例(NVIDIA K680卡添加的內存 – 1536支持CUDA核心,4GB內存)。該GPU實例使用NVIDIA計算環境3.0,這個環境TensorFlow本身並不支持。為的是支持AWS的GPU從源代碼編譯TensorFlow,並把一組TF_UNOFFICIAL_SETTING旗幟放在配置階段。此版本技術顯著增加TensorFlow在某些系統要求的虛擬內存的數量,因此被警告。當試圖設置-executor-核心=8,而我們得到“虛擬內存不足”的錯誤時,我們才發現了這一點。 [https://github.com/adatao/tensorspark/blob/master/gpu_install.sh# L17]

序列化

l由於Tensorflow只有一個Python和C API,我們不得不使用PySpark去使Spark實施工作。這就導致對象在Scala、Java、Python和C ++中轉換,而造成不是最佳的性能。

lTensorFlow的對象不能挑選,所以我們建議把它們排序為numpy數組。

l解析大JSON非常緩慢,所以避免它。

錯誤三岔口

我們的第一個執行涉及每個工人用隨機重量和偏見創造一個新的TF模型,然後開始與司機溝通。這很快出現了一個問題。

分佈式TensorFlow:在Spark上將谷歌的深度學習圖書館進行尺度變換 |emailtry.com

圖5:意味着測試集平方誤差VS可見訓練樣本數

我們可以看到測試誤差只在14000樣本后開始爆發。由於誤差表面有多個局部最優,每個工人從不同的起點開始訓練可能導致參數從不聚集和錯誤的建立。回到我們DownpourSGD類比,在山上出現降雨,有些水滴從一邊流下,其他水滴下從另一邊流下(見下圖),所以正確的參數集沒有聚集。

分佈式TensorFlow:在Spark上將谷歌的深度學習圖書館進行尺度變換 |emailtry.com

圖6:不同的局部最優間的尖端的可視化

我們發現,我們可以通過熱身階段來降低這個影響,其中一些單獨的數據驅動整個火車,有效地將其彙集到山的一側。其結果是,由於山的尖端導致分散的概率下降,因為有多個這樣的尖端而有限的熱身只消除了其中的一些。

发表评论