百度深度學習平臺PaddlePaddle框架解析

飛槳PaddlePaddle發表於2018-03-19
PaddlePaddle 的迭代速度非常快,同時也廣受社群的關注。剛開源的時候,PaddlePaddle 的設計思想是基於 Layer 的設計。後來推出了「v2」和「Fluid」兩次迭代:其中 v2 增加了 operators 的概念,把 layers「打碎」成更細粒度的 operators,同時支援更復雜的網路拓撲「圖」;Fluid 類似 PyTorch,但是不依賴 Python 的控制流(if-else、for 等),而是提供自己的直譯器甚至編譯器,因此不受限於 Python 的執行速度。

我們今天就從 PaddlePaddleFluid 講起,隨後講述為了能更方便利用叢集而提供的在瀏覽器端訓練的 PaddlePaddleCloud,也著重講解叢集訓練的原理、配置、和實驗結果,也就是 PaddlePaddleEDL 部分。最後,講解 PaddlePaddleVisualDL,這個非常強大的訓練日誌解析和視覺化工具。

PaddlePaddleFluid

PaddlePaddleFluid 提供類似於高階語言中的控制流結構(例如 while 、 if 、if-else、 for 等),不僅能利用編譯優化技術保證計算效能,提升使用者的開發效率。

PaddlePaddleFluid 的設計思路非常領先,不再沿用層(layer)結構和操作(operator)結構的模式。也就是說不再有「模型」的概念,也就不再有「圖」(graph of operators)或者「串」(sequence of layers)。而只有「程式」的概念。同時,程式是可以匯出一個圖的,從程式中可以匯出成 ONNX 檔案格式的模型。

深度學習基礎架構是最快速發展的技術之一,在四年之內,已經發明瞭三代技術。從下表可以看出,深度學習技術架構設計的方向正是逐漸擺脫模型的。

百度深度學習平臺PaddlePaddle框架解析

基於 Python 語言強大的生態,PyTorch 和 Eager Execution 中的控制流都是用的 Python,但面臨的一個瓶頸是 Python 執行速度慢且難以提速。解決 PyTorch 和 Eager Execution 程式的執行速度受限於 Python 的執行速度的問題,Fluid 有一個比 PyTorch 和 Eager Execution 更激進的技術思路。在 Fluid 的設計上,執行會把編寫的 Python 程式輸出成一個 protobuf message,隨後呼叫 Fluid 直譯器(而不是 Python 直譯器)來解釋執行這個 protobuf message。Fluid 直譯器極大地加快了執行圖的速度。同時,在編譯執行的方式上,通過寫一個 transpiler 把 protobuf message 翻譯成 C++ 程式,然後用 nvcc、icc、gcc 編譯成二進位制程式碼,可以直接執行在伺服器和手機上。

PaddlePaddleCloud

PaddlePaddle 有一個 Web-based IDE,支援使用者在瀏覽器用 JupyterNotebook 程式設計來開發 AI 應用,隨後可以把程式傳送到雲端(Kubernetes 叢集上)除錯或者執行,程式執行時的輸出會實時地顯示在瀏覽器裡。這樣使用者就不需要在個人電腦和叢集等多個程式設計環境之間切換並且維護多個環境的版本和配置的一致性,極大地提升了工作效率。

PaddlePaddleEDL

PaddlePaddle EDL 對標的是 Google KubeFlow。PaddlePaddle EDL 通過與 Kubernetes 合作來實現彈性作業排程,是全球首個支援彈性作業排程的開源 AI 雲解決方案。

儘管現在很多深度學習應用用一個幾臺機器的小叢集就可以解決,但是 隨著資料量的增加和 AI 應用場景的不斷擴大,例如 Web scaled 應用(廣告、搜尋、推薦等),以及通過感測器採集海量資料的無人車,都需要大規模深度學習計算能力的。

這裡主要為了解決深度學習面臨的兩大挑戰。其一是需要大量的計算能力。研究室和公司經常構建由 SLURM,MPI 或 SGE 管理的 GPU 叢集。這些叢集要麼執行一個提交的作業(假定它需要的比閒置的資源要少)或者將作業掛起一段難以預估的時間。但是這種方法有個缺點:在有 99 個可用節點和一個需要 100 個提交作業的任務時,作業必須等待而不能執行。

PaddlePaddle EDL 彈性排程體現在可以空閒的時候一個訓練作業多用一些資源,忙碌的時候少用一些,但是資源的變化並不會導致作業失敗;這是優於 KubeFlow 的特點之一。同時,EDL 也彈性排程其他作業(比如 Nginx、MySQL 等),從而極大地提升叢集總體利用率。[2] 這樣在公有云和私有云上的推廣和部署時,就很容易節省幾倍的機器,為公司一年節省的計算成本可以高達百萬、甚至數百萬美元。

另一個挑戰是,工業使用者傾向於將深度學習作業作為完整資料管道的子集階段,例如日誌採集器等。這種通用叢集需要基於優先順序的彈性排程。比如網路開銷較高的時間段內深度學習任務少執行,在網路流量較低時優先進行深度學習任務。這就需要了解全域性的情況,並協調與各種工作有關的程式的數量。

PaddlePaddleEDL 的測試實驗

面對上述這兩種挑戰,PaddlePaddle 作業都可以輕鬆應對程式數量忽高忽低的變化。這裡有 Fluid EDL 的兩種測試用例:

  • Kubernetes 叢集只執行 PaddlePaddle 作業;

  • 叢集執行 PaddlePaddle 和 Nginx 作業。

在第一個測試中,我們開始了 20 個 PaddlePaddle 作業,間隔 10 秒。每個作業有 60 個 trainers 和 10 個引數服務程式,並將持續數小時。我們重複實驗 20 次:關閉 Fluid EDL 10 次,開啟 Fluid EDL 10 次。在下圖中,實線對應於前 10 個實驗,其餘的是虛線。在圖的上半部分,我們看到未處理作業的數量在沒有 EDL 的情況下單調遞增。但是,當 EDL 開啟時,資源將平均分配給所有作業。Fluid EDL 殺死了一些現有的程式,為新的其他任務騰出空間,並在晚些時候任務開始執行。在這兩種情況下,叢集都被平等利用(見圖的下半部分)。

百度深度學習平臺PaddlePaddle框架解析

在第二個測試中,每個實驗都執行了 400 個 Nginx Pods,其優先順序高於 6 個 PaddlePaddle 作業。最初,每個 PaddlePaddle 工作有 15 個 trainers 和 10 個引數服務。我們每 90 秒殺死 100 個 Nginx Pods,直到剩下 100 個,然後我們開始將 Nginx 工作的數量每 90 秒增加 100 個。下圖的上半部分顯示了這個過程。圖中的中間顯示,Fluid EDL 通過減少 Nginx Pods 來自動啟動一些 PaddlePaddle 程式,並在稍後增加 Nginx Pods 來殺死 PaddlePaddle 程式。結果,該叢集維持在 90%左右的利用率,如圖所示。當 Fluid EDL 被關閉時,沒有 PaddlePaddle 程式自動增加,並且利用率隨著 Nginx Pods 數量的變化而波動。

百度深度學習平臺PaddlePaddle框架解析

PaddlePaddleEDL 的設計和實現

那上面這種深度學習服務和其它雲端服務共享計算資源的過程,以及各個任務的優先順序動態地調整和伸縮的過程,從而充分地利用叢集 CPU/GPU 是如何實現的呢?

EDL 和 HPA

Horizontal Pod Autoscaling(HPA)是 Kubernetes 提供的一種彈性排程機制。它的設計出發點是通過公平分配計算資源給某一個單一的計算任務中的各個 Pod 來實現分散式系統資源針對單一任務的最優化利用。但我們的訓練任務可能多種多樣(語音、影象等)、部署時間有先有後,對資源的需求也不通,因此我們希望這種彈性排程機制能對每一種訓練任務所需的系統資源有個全域性的瞭解,然後按需分配。但目前 HPA controller 還沒有實現。

同時,HPA 的彈性排程是針對同種型別的計算任務(homogenous computing task)下的 Pods。但深度學習系統裡的計算節點和引數伺服器往往是在不同型別的 Pods 裡 的。

上述特有的需求導致使用 Kubernetes 的時候需要有特定的彈性排程解決方案,而不能直接採用 HPA。因此更好的解決方案是 PaddlePaddle EDL。

PaddlePaddleEDL 的具體設計和實現

  • 1. 讓 Kubernetes 支援定製的彈性排程機制

Kubernetes 本身就支援定製的資源管理機制。使用者可以通過提交定製的 resource declaration file 和 controller file 來實現對某種 Pods 的彈性排程。以下圖為例,這個 training_job.yaml 保證了 controller 會自動監管 pservers,並且保證它們的數量在 min-instance 和 max-instance 之間。

百度深度學習平臺PaddlePaddle框架解析

在 Kubernetes 叢集上,這個定製的資源可以通過 kubectl create -f training_job.yaml 命令獲得。接下來,我們需要有個定製的 training job controller 來排程這個資源。

定製的 training job controller 跑在一個 Pod 裡,對叢集資源有一個統一的瞭解,它通過 Kubernetes API 對叢集資源起到監控和排程的作用。下圖是 training job controller 配置檔案的一個例子。

百度深度學習平臺PaddlePaddle框架解析

在 Kubernetes 叢集上,這個定製的資源管理 Pod 可以通過 kubectl create -f training_job_controller.yaml 命令啟動。

  • 2. 控制程式的實現

上面提到的定製化資源在 Kubernetes 裡面目前有兩種實現方式。一種是 Custom Resource Definition (CRD),由 Kubernetes 1.7 版本引入;另一種是 Third Party Resource (TRP)。PaddlePaddle 專案現在用的是 Kubernetes 1.6 版本,所以實現的是 TRP 模式,今後將整合 CRD 模式。

當前 PaddlePaddle 假設只有一個單獨的 training job controller 在執行。當前的 training job controller 依照下面的邏輯管理資源:

百度深度學習平臺PaddlePaddle框架解析

  • 3. 彈性排程演算法

PaddlePaddle 根據定製資源的配置檔案(training_job.yaml)來判斷某個 job 需不需要彈性排程,而判斷的標準是 trainer 和 pserver 的 min-instance =/ max-instance。

叢集中 GPU 的排程

controller 知道叢集中全部 GPU 個數,以及當前閒置的 GPU 的個數,並試圖把閒置的 GPU 全部分配給當前訓練任務。PaddlePaddle 給需求 GPU 的訓練任務定義一個「滿足程度」的評分(fulfillment score),此評分的範圍是 [0,1]。PaddlePaddle 會優先分配 GPU 資源給滿足程度評分最低的訓練任務。如果有分數相同的情況,則分別優先考慮 GPU 需求數,CPU 需求數,記憶體需求數。如果有某個訓練任務的 GPU min-instance 沒有滿足(除非 cur-instance=min-instance),那麼 PaddlePaddle 會把一個滿足程度最高分的訓練任務裡的 GPU 資源拿出來分給它。如果滿足程度分數最高的訓練任務 cur-instance=min-instance,則整個叢集不再執行新的訓練任務,新來的任務需等待。

叢集中 CPU 的排程

CPU 資源的分配和 GPU 思路相同。controller 知道叢集中一共有多少個 CPU,記憶體,它們的負載情況;同時也知道訓練任務對 CPU 的需求。同樣的,CPU 資源根據滿足程度評分被按需分配。

PaddlePaddle 容錯機制

這裡討論 PaddlePaddle 的容錯機制。在一個分散式訓練任務裡,如果 master 程式或者所有的引數服務程式都死掉了,那麼整個訓練任務會被停掉,過一段時間被 Kubernetes 整個重啟。如果具體訓練程式沒有都死掉,則整個訓練任務繼續。

PaddlePaddle 用 etcd 來記錄訓練程式的狀態。etcd 是高可靠性的分散式 key-value 儲存,訓練程式會定時把自身狀態寫進 etcd,而這些資訊將會在必要的時候用來恢復訓練程式。具體過程如下圖:

百度深度學習平臺PaddlePaddle框架解析

當 master 程式被 Kubernetes 啟動時,它進行如下操作:

1. 從 etcd 中取一個唯一的 master lock,以此避免多個 master 例項存在

2. 檢視 etcd 中是否存在任務佇列。如果不存在,則新建一個任務佇列;否則得到這個任務佇列中的資訊

3. 把自身的 ip 地址寫進 etcd 中/master/addr 這個 key 中,便於後來的訓練程式和自己通訊

4. 開埠監聽訓練程式的任務需求,如果收到來自訓練程式的任務請求,從任務佇列中取任務分配之,並且更新任務佇列。

如果 master 程式因為任何原因死掉了,Kubernetes 會將它重啟,從被重啟到獲取 etcd 的資訊,獲取訓練程式的任務,這個過程一般是幾分鐘。

  • 訓練程式

當訓練程式被 Kubernetes 啟動時,它進行如下操作:

1. 檢視 etcd 中包含引數服務字首 /ps/ 獲取當前引數服務程式的數量並等待,直到該數量達到配置檔案中的要求

2. 從 etcd 的/master/addr key 中獲取 master 程式地址

3. 向 master 發起任務請求,根據任務開始訓練程式

當訓練程式死掉之後,Kubernetes 會將它重啟,新起來的程式會重複上述工作直到開始新的訓練工作。

  • 引數服務程式

當引數服務程式被 Kubernetes 啟動時,它進行如下操作:

1. 從 etcd /ps_desired 中讀取訓練任務所需求的引數服務程式個數

2. 在 etcd /ps/<index>(/ps/0, /ps/1, ...)裡找一個小於所需程式數裡最大的還不存在的 id,並在 etcd 裡建立這個 entry,以此作為自身的 id。(如下圖)

百度深度學習平臺PaddlePaddle框架解析

當第三個引數伺服器加入時:

百度深度學習平臺PaddlePaddle框架解析

3. 引數服務程式會從自身對應的 etcd path 中找到已有的訓練結果引數並且將它讀入

4. 引數服務程式開始接收來自訓練程式的請求。

PaddlePaddle 的視覺化—PaddlePaddleVisualDL

PaddlePaddleVisualDL 是 PaddlePaddle 自帶的一個強大的視覺化工具,也是一個 Web 應用程式套件。PaddlePaddleVisualDL 目前支援 4 種視覺化,即 SCALARS、IMAGES、GRAPHS、HISTOGRAMS。這 4 種視覺化的主要功能如下。

● SCALARS:展示訓練過程中的準確率、損失值、權重/偏置的變化情況。

● IMAGES:展示訓練過程中記錄的影象。

● GRAPHS:展示模型的資料流圖,以及訓練在各個裝置上消耗的記憶體和時間。

● HISTOGRAMS:展示訓練過程中記錄的資料的柱狀圖。

PaddlePaddleVisualDL 通過執行一個本地伺服器,來監聽 8080 埠。在瀏覽器發出請求時,分析訓練時記錄的資料,繪製訓練過程中的影象。而且 VisualDL 相容 ONNX, 通過與 python SDK 的結合,VisualDL 可以相容包括 PaddlePaddle, pytorch, mxnet, Caffe2 在內的大部分主流 DNN 平臺。而 Tensorboard 目前僅適用於 Tensorflow、Pytorch、MXNet 等。

百度深度學習平臺PaddlePaddle框架解析

PaddlePaddleVisualDL 的視覺化介面如下圖所示。

百度深度學習平臺PaddlePaddle框架解析

VisualDL 的使用

VisualDL 的使用方式非常簡單,只需要下面三個過程:

百度深度學習平臺PaddlePaddle框架解析

VisualDL 的特性

VisualDL 的特性主要有下面 4 點:

  • 支援 Scalar 打點折線圖展示,方便觀察訓練整體趨勢

百度深度學習平臺PaddlePaddle框架解析

  • 支援 Image 檢視資料樣本的質量和訓練中間結果

百度深度學習平臺PaddlePaddle框架解析

  • 支援 Histogram 檢視引數分佈展示和變化趨勢

百度深度學習平臺PaddlePaddle框架解析

  • 支援 Graph 檢視深度神經網路的模型結構

百度深度學習平臺PaddlePaddle框架解析

總結

隨著 PaddlePaddle 新特性的不斷增加,相信在科研和使用中能給廣大使用者帶來很多幫助。這裡從 PaddlePaddleFluid 講起,隨後講述為了能更方便利用叢集而提供的在瀏覽器端訓練的 PaddlePaddleCloud,也著重講解叢集訓練的原理、配置、和實驗結果,也就是 PaddlePaddleEDL 部分。最後,講解 PaddlePaddleVisualDL,這個非常強大的訓練日誌解析和視覺化工具。百度深度學習平臺PaddlePaddle框架解析

相關文章