人工智能人人通生态雲平台

河南人民出版社有限責任公司

2019年12月28日 星期六

咨詢熱線

400-6908-558

在線學習
153 人
雲校學校
220 所
雲校老師
158 人
雲校學生
451 人
雲校家長
51 人

立即報名

平台動态

Platform Dynamics

您的位置:币安币官网 > 平台動态 > 新聞詳情

如何評價 7 月 31 日一流科技開源的深度學習框架 OneFlow?


都2020年了,為什麼我們相信OneFlow會成功


利益相關。

作為OneFlow的一名工程師,我來談談為什麼我認為OneFlow有機會在深度學習框架的競争中勝出。

本文的主要内容如下:

  1. 自我介紹
  2. OneFlow的設計思路,它的獨特性
  3. OneFlow的特色一:Actor機制
  4. OneFlow的特色二:SBP機制
  5. 我對人工智能/深度學習未來的看法
  6. 對OneFlow開源的感想
  7. 總結

一、 自我介紹

我是OneFlow的一名工程師,在公司創業之初就加入了。研究生就讀于清華軟院,讀研期間在OneFlow實習了兩年,畢業之後正式入職一年。我對OneFlow的整體設計是比較熟悉的,對深度學習框架也有一點小小的見解。OneFlow剛剛開源,我相信OneFlow的設計和實現可以給大家一種眼前一亮的感覺,也相信在衆多深度學習框架的競争中,OneFlow有機會勝出。

二、 OneFlow是獨特的

時至今日,一個框架有沒有機會成功,要看它有沒有差異化的特點。OneFlow是有其獨特的設計理念和技術路線的。目前市面上已有的衆多開源框架,用戶最多的是PyTorch和TensorFlow,除此之外還有各大公司的自研框架:PaddlePaddle、MXNet、MindSpore、MegEngine等等。其中TensorFlow的特點是最完備,推理、serving、XLA、tensorboard等一應俱全,工業部署的主流還是TensorFlow;PyTorch的特點是易用性最好,eager執行、動态圖、跟python的交互方式等等,非常受科研人員喜歡。

可以說完備性易用性這兩極分别被TF和PyTorch占據,OneFlow作為一個小團隊打造的框架,如果單純的模仿别的框架,跟TF比完備性,跟PyTorch比易用性,那是絕對沒戲的。但深度學習框架還有第三極:性能。OneFlow的特點就是追求極緻的性能,而且是分布式多機多卡環境下的橫向擴展性。OneFlow的核心設計理念就是從分布式的性能角度出發,打造一個使用多機多卡就像使用單機單卡一樣容易,且速度最快的深度學習框架。

為什麼OneFlow要聚焦于分布式場景的性能和易用性呢?因為深度學習是吞沒算力的巨獸,單卡的算力和顯存遠遠不能滿足深度學習模型訓練的需求。多機多卡的理想很豐滿,現實很骨感,普通用戶在使用其他框架時常常會發現多機多卡難以使用且效率低下、BERT/GPT-3等參數量巨大的模型無法實現等問題。别的框架一般都是先聚焦于單卡的視角和用戶體驗,對于多機多卡的處理就是把單卡的計算圖鏡像複制到多機多卡上,各個卡和機器之間輔助于模型同步的模塊。業界不僅僅改進深度學習框架自身,還研發了多種第三方插件,譬如NCCL, Horovod, BytePS,HugeCTR,Mesh-tensorflow, Gpipe等等。但是,仍隻滿足一小部分需求。對于普通用戶而言,使用其他框架做分布式訓練常常需要更高的學習成本,還需要關心多機多卡之間模型是怎麼同步的。但OneFlow不一樣,OneFlow在框架最核心的設計上就在考慮分布式訓練如何高效的協同運轉,同時要讓用戶在多機多卡的訓練體驗上就像單卡一樣簡單容易

下面我就分别介紹兩點OneFlow相較于其他框架的獨特設計,來體現OneFlow是如何看待分布式場景下的深度學習訓練的。


三、 Actor——用一套簡潔的機制解決所有令人頭秃的技術難題

(關鍵特性: 去中心化調度 流水線 數據搬運是一等公民 傳輸被計算掩蓋 控制邏輯被執行邏輯掩蓋)

在OneFlow的設計中,分為Compile和Runtime兩個時期,Compile時期把用戶定義的神經網絡、分布式環境信息等編譯成一個靜态圖的執行計劃Plan,Plan由執行單元Actor的描述信息組成;Runtime時期,各個機器根據Plan裡的Actor描述信息真實得創建屬于自己機器的衆多Actor實例,然後啟動Actor運行系統。整個深度學習訓練期間,OneFlow的執行基本單元就是Actor,Actor對應靜态執行圖上的節點,Actor之間生産、消費的數據存儲在Register中,Actor之間通過消息傳遞來協作運行。

3.1 Actor機制實現去中心化調度

OneFlow的運行時去中心化調度就是用Actor機制實現的。在整個由Actor構成的靜态圖中,沒有一個中心的調度節點,每個Actor都隻需要關心自己所需數據的生産者(上遊Actor)和自己生産的數據的消費者(下遊Actor)即可。這樣在超大規模的分布式訓練場景下,完全的去中心化調度可以避免中心調度的單點性能瓶頸問題。

每個Actor内部都有一個狀态機,Actor收發的消息、執行的情況都會改變自己的狀态。需要注意的是,Register是存儲塊,存放了Actor生産出來的數據,而消息是包含了Register存儲塊的内存地址的輕量級數據,Actor之間傳遞的是消息,而不是Register,這樣就實現了zero-copy。當Actor收到了新消息,判斷它執行所需要消費的Register已經就緒,且它生産的數據有空閑的Register可以寫入時,這個Actor就執行(Act)一次,生産出一個Register。生産完以後,該Actor就向需要消費這個Register的那些消費者Actor們發消息,表示你們可以來讀取我生産的數據了;同時該Actor還需要把它消費完的那些Register還給這些Regsiter的生産者Actor們,表示我用完了你們的數據,你可以回收了。Actor内部的狀态機如圖1所示。

在Actor啟動之後,會根據與其他Actor之間收發消息來切換自己的兩個狀态:等待狀态 和 執行狀态。

一個Actor收到的消息一般分為幾個類型:a) 上遊的生産者Actor發來消息說你可以來讀我生産的數據了;b) 下遊的消費者Actor發來消息說我用完你生産的數據了。當這個數據被所有消費者都用完以後,就可以回收成為空閑塊等待下一次被該Actor重新生産一份新的數據。

一個Actor收到消息以後都會去嘗試判斷當前是否滿足執行條件,執行條件一般有兩個:a) 需要讀取的數據是否都到齊了;b) 是否有空閑塊可以拿來被生産。當滿足執行狀态以後Actor就開始調用自己内部的Kernel真實的去讀寫數據。

執行完畢後Actor會向上下遊發消息:a) 向下遊的消費者Actor發消息說我剛生産了一塊數據,你可以來讀了;b) 向上遊的生産者Actor發消息說我剛用完了你之前發給我的數據了。

Actor隻需要關心上下遊的消息就能判斷自己能不能執行。每個Actor都通過自己内部的狀态機和收發消息機制實現了完全去中心化的分布式協同工作。

3.2 Actor機制實現流水線

上面我們介紹了Actor的内部狀态機,Actor之間的消息傳遞和數據傳遞是依賴Register實現的。一個Actor是否能執行,隻跟兩個條件相關:1)自己消費的那些Register是否可讀;2)自己生産的那些Register是否有空閑塊可寫。對于一個Register,如果我們運行時給它分配多個空閑塊,那麼相鄰的兩個Actor就可以同時工作,工作時間重疊起來,這樣就實現了各個Actor之間的流水線。理想狀态下整個靜态執行圖的執行時間就是整個系統中是性能瓶頸的那個Actor運行的總時間,其餘Actor的執行時間都被流水線掩蓋起來了。

我們舉一個例子來解釋Actor機制下的流水線是如何運轉起來的。圖2是一個由3個Actor(a,b,c)組成的計算圖的執行時序圖。其中深綠色的Regst方塊表示正在被使用的Register塊,白色的Regst方塊表示同一個Register的備用空閑塊。

圖 2 Actor生産消費關系和執行時序圖

1) 在Time0時刻,Actor a産出了一個Regst_a_0,Actor b 和 Actor c由于沒有可讀的Register,所以處在等待狀态。假設每個Actor的執行時間都是單位時間。

2) 到Time1時刻,Actor a給Actor b發消息說你可以來讀我産出的Regst_a_0了,Actor b收到了消息,并檢查自己生産的Register b是否有空閑Regst塊可用,發現有可用的Regst_b_0,于是Time1時刻Actor b執行,讀取Regst_a_0,寫Regst_b_0;同時Actor a還會去看自己是否有空閑塊可寫,發現有,Time1時刻Actor a也在執行,寫Regst_a_1。(這裡需要說明的是,Regst_a_0和Regst_a_1邏輯上是屬于同一個Register,隻是空間上分成了不同的空閑塊備份而已。在深度學習訓練任務中,Regst_a_0和Regst_a_1裡存放的是同一個operator産出的不同batch的數據。)于是Actor a和Actor b就并行工作起來了。Actor c由于沒有數據可讀,仍在等待。

3) 到Time2時刻,Actor b 生産出了Regst_b_0,于是給下遊的消費者Actor c發消息說你可以來讀我生産的Regst_b_0,同時給上遊的生産者Actor a發消息說我用完了你的Regst_a_0。此時Actor a 已經把剛剛生産的Regst_a_1又發給了Actor b,Actor b檢查自己仍有Regst_b_1空閑,于是Actor b開始讀Regst_a_1,寫Regst_b_1;Actor c收到Regst_b_0,發現自己有Regst_c_0空閑,于是Actor c開始執行,讀Regst_b_0, 寫Regst_c_0;Actor a收到了Actor b用完還回來的Regst_a_0,檢查Regst_a_0所有的消費者都用完了,于是将Regst_a_0回收,标記為空閑塊,同時Actor a還可以繼續執行,寫Regst_a_2。

在上面的例子中,到了Time2時刻,其實Actor a、b、c都在工作,在深度學習訓練任務中,Time2時刻Regst_b_0、Regst_c_0存放的是Batch 0的數據,Regst_a_1、Regst_b_1存放的是Batch 1的數據,Regst_a_2存放的是Batch 2的數據。通過一個Register有多個空閑塊的設計,Actor機制就實現了流水并行。

在這裡我抛出一個更進一步深入的問題:整個數據流的執行像一個網絡,數據在網絡中的流動就完成了計算,如何避免生産者生産太快,消費者消費不及,以及如何避免生産者生産太慢,消費者感到饑餓的問題,這涉及到對計算、内存、傳輸帶寬的規劃,盡可能使系統的瓶頸之處最寬,需要解決流控(flow control)的問題以及資源分配問題(如每個Actor的Register到底分配幾個内存塊配額),這是非常關鍵的問題,也是OneFlow系統已解決的。

3.3 數據搬運是一等公民

在多機多卡的分布式環境中,各個機器和各個設備之間的數據傳輸往往是影響系統的橫向擴展性的最重要因素,如果傳輸開銷可以被計算開銷掩蓋,那麼分布式深度學習訓練就可以達到理想的線性加速比。相較于其他的框架,OneFlow把數據搬運視為跟數據計算同等地位的操作,提出“數據搬運是一等公民”的思想。

已有框架在編譯期的關注焦點是數據計算,認為數據搬運是背後隐式發生的,因此在靜态分析計算圖時略過計算和搬運的重疊編排,OneFlow在計算圖中顯式表達了數據搬運,而且在靜态分析時同等對待數據搬運和數據計算,以最大化重疊搬運和計算。

在最終的執行圖中,數據搬運操作也是一個個Actor。除了在設備上做數據計算用的Actor以外,還有計算機内存到GPU顯存之間的數據拷貝Actor,機器之間做網絡通信的網絡Actor,負責數據的切分、合并、複制的Actor,負責讀取磁盤數據的Actor,負責加載保存模型的Actor等等。很多其他框架都把數據加載、多卡模型梯度的同步、網絡、模型加載更新等分别做成一個單獨的模塊,而OneFlow的設計是所有的功能都在一張由Actor組成的靜态執行圖裡實現了。OneFlow這樣的設計不僅簡潔、優雅,還非常高效。

圖 3 數據是如何從一個設備搬運到另一個設備上的

圖3表示了沒有GPU-Direct的況下,在OneFlow的Runtime階段,一個設備上的計算節點如果消費了另一個設備的計算節點,數據是如何搬運過去的。

3.4 盡可能并行

在OneFlow的設計中,所有的出發點都是希望可以盡可能并行,從而達到最優的分布式性能。比如考慮到分布式訓練模型梯度同步時,顯存到内存的傳輸帶寬高于機器之間的網絡傳輸帶寬,OneFlow會做兩級的scatter和gather操作(本機的和各個機器之間的),用于增加locality,提高整體性能;又比如在異步啟動深度學習訓練時,python端用戶的控制邏輯跟OneFlow運行時的執行圖是并行執行的,同時OneFlow有一套互斥臨界區的設計保證執行的高效性和正确性;數據加載部分無論是從磁盤讀數據還是從python端喂數據,OneFlow都能保證盡可能并行,使得計算設備不會因為要等數據而導緻性能下降。已有框架如果想要盡可能重疊數據搬運和計算,一般借助多層回調(callback)函數,當嵌套層次過多時,會遇到所謂的callback hell麻煩,正确性和可讀性都可能下降。但在OneFlow中,以上的這些并行并發特性,都是在這一套簡潔的Actor機制下實現的,解決了令人頭秃的callback hell問題。

此外,在多機的網絡通信部分,OneFlow底層的網絡通信庫原生支持RDMA的高性能通信,也有一套基于epoll的高效通信設計。而目前最流行的Pytorch,多機還需要通過RPC來做數據同步。


四、 Placement+SBP——OneFlow是如何做到分布式最易用的

OneFlow是目前分布式場景中支持數據并行、模型并行、流水并行等最易用的深度學習框架。用戶隻需要像單卡一樣去搭建網絡模型,并告訴OneFlow有哪些機器哪些卡,OneFlow就會用最高效的方式把這些機器和設備使用起來。

這源于OneFlow的一套獨特的設計:ConsistentView(一緻性視角)。對于多機多卡,OneFlow會把它抽象成一個超級大的設備,我們稱之為邏輯上的設備,這個邏輯設備的顯存是實際多個物理設備的顯存之和,這個邏輯設備的算力也是實際多個物理設備的算力之和。用戶隻需要定義在這個邏輯上的超級設備裡,深度學習模型是如何構建的,其餘的便不需要用戶來操作,由OneFlow來完成邏輯上的設備到物理上的設備的映射。

這裡先明确兩個概念:“邏輯上的”和“物理上的”。“邏輯上的”表示OneFlow把分布式集群抽象成一個超級計算機之後的計算和數據,“物理上的”表示那些真實的部署到各個機器和設備上的計算和數據。深度學習網絡是由Op構成的計算圖,Op之間生産消費Tensor數據。在多機多卡的環境下,一個邏輯上的Op會對應多個真實的物理上的Op,每個物理上的Op實際執行的計算都是這個邏輯Op計算的一部分,一個邏輯上的Tensor也會對應多個物理上的Tensor,每個物理上的Tensor都是邏輯Tensor的一部分。

對于其他的框架定義的分布式訓練,每張卡是一個“world”,多卡之間根據暴露出來的接口來同步模型梯度;而對于OneFlow而言,多機多卡也都是一個“world”,我們使用一套Placement+SBP的方式做全局的統籌管理。

4.1 Placement

在OneFlow的計算圖搭建過程中,每個計算Op都有一個屬性叫做Placement,表示了該邏輯上的Op,是要部署到哪些機器哪些設備上的。對于常見的數據并行,就是所有的Op都部署到所有的設備上。但OneFlow也支持用戶指定Op的Placement,比如當網絡過大單卡根本放不下的時候,在OneFlow可以讓網絡的前一部分在一張卡上,後一部分在另一張卡上,用一種“接力”的方式工作,實現流水并行。

圖 4 一個流水并行的Placement示例圖

圖4展示了一種可能的Placement例子。用戶定義了一個由3個Op組成的網絡:Op_0 -> Op_1 -> Op_2。其中Op_0和Op_1的Placement是Device 0,Op_2的Placement是Device 1,這就是一個流水并行的例子,Oneflow會自動在Op_1和Op_2之間插入需要的數據搬運的Copy Op。

4.2 SBP

SBP是OneFlow獨有的概念,他是三個單詞的首字母組合:Split、Broadcast、PartiaSum(以PartialSum為例,實際上還可以是PartialMin, PartialMax等reduce操作),全稱叫SbpParallel,表示一種邏輯上的Tensor跟物理上的多個Tensor的映射關系。其中Split表示物理上的Tensor是邏輯Tensor按照某一維度切分後得到的, Split有個參數axis,表示切分的維度,如果把多個物理上的Tensor按照Split的維度進行拼接,就能還原出邏輯Tensor;Broadcast表示物理上的Tensor是跟邏輯上的Tensor完全相同的;PartialSum表示物理上的Tensor雖然跟邏輯上的Tensor形狀一緻,但是物理上的Tensor裡的值是邏輯Tensor裡對應位置的一部分,如果把物理上的多個Tensor按照對應位置相加,即可還原出邏輯上的Tensor。圖5展示了SBP的簡單示例。

圖 5 幾種SbpParallel的簡單情形

SbpSignature是一個SbpParallel的集合,在OneFlow的設計裡是Op的屬性,它描繪了一個邏輯上的Op被映射成各個設備上的多個物理上的Op以後,這些物理上的Op是如何看待他們輸入輸出Tensor在邏輯上和物理上的映射關系的。一個Op會有多個合法的SbpSignature,一個最簡單的合法signature就是輸入輸出都是Broadcast,這表示了這個Op需要整個邏輯上的Tensor數據。當用戶構建的邏輯上的計算圖确定以後,OneFlow在Compiler生成分布式的物理上的執行圖時,會考慮每個Op的Placement和該Op允許的合法SbpSignature列表,在其中選擇一個傳輸開銷最小的SbpSignature作為本次訓練的SbpSignature,用于指導Compiler生成最高效的執行圖。

關于Op的合法SbpSignature的列表,我舉一個矩陣乘法(matmul)的Op的例子。定義: Y = matmul(A,B) , A, B, Y都是Tensor,表示 Y = AB。那麼至少存在兩種合法的SbpSignature:

1) Y: Split(0), A:Split(0), B:Broadcast

2) Y: Split(1), A:Broadcast, B: Split(1)

兩種合法的signature在兩個設備上的示意圖如圖6所示。假設邏輯上的MatMul的輸入輸出Tensor的形狀是:A(64, 10) X B(10, 50) -> Y(64, 50)。 且該Op分布在兩個設備上。在第一種SbpSignature下,0号設備上的A是邏輯上A的前一半,1号設備上的A是邏輯A的後一半(按照第0維切分),而兩個設備上的B跟邏輯上的B完全一緻,兩個設備輸出的Y分别是邏輯上的Y的前一半和後一半。同樣可以分析第二種SbpSignature。

圖 6 MatMul的兩種合法SbpSignature

值得一提的是,當A是數據,B是模型的時候,第一種SbpSignature就是數據并行,第二種SbpSignature就是模型并行。如果兩個相鄰的MatMul op,前一個使用第一種SbpSignature,後一個使用第二種SbpSignature,整個網絡就實現了混合并行

圖7是一個混合并行的示例,定義了 Y0 = MatMul_0(A0, B0) , Y1 = MatMul_1(Y0, B1)這樣一個由兩個op組成的計算圖,其中A0, Y0, Y1是數據Tensor,B0, B1是模型Tensor。

圖 7 混合并行示例

在圖7中MatMul_0産出的Y0被MatMul_1消費,但是這兩個op對同一個Tensor的SBP看待方式是不一樣的,MatMul_0認為Y0是Split(axis=0)切分,但是MatMul_1需要一個Broadcast的Y0輸入。這時候OneFlow會自動插入一個“萬能”的Boxing Op做必要的數據裁剪、拼接、搬運和求和等操作,使得所有的Op都可以在分布式環境下高效的拿到自己想要的數據。

另外在數據并行的時候,訓練的前向模型Tensor的是Broadcast,對應反向傳播的梯度就是PartialSum,當Optimizer需要全部的梯度來更新模型時,就會觸發OneFlow的Boxing機制進行高效的梯度同步工作。

4.3 最易用的分布式并行框架

OneFlow的這套Placement + SBP + Boxing的機制,可以使得用戶定義的計算圖中的Op、Tensor以任意的方式分布在各個機器和各個設備上,無論是數據并行、模型并行還是流水并行,對于OneFlow而言,都隻是一個特定Placement下的特定SbpSignature的組合而已,用戶可以方便的配置,也可以交給OneFlow來做自動的處理。

另外,早在微軟推出ZeRO-2框架之前,OneFlow就已經支持了類似的功能,多機多卡情況下,每個模型Tensor都隻保存在其中一個設備上,降低梯度計算中的内存占用。

綜上,在編譯期,OneFlow通過在一套數學上嚴謹的形式系統來表示所有合法的并行模式,并支持編譯器較方便地自動搜索最優并行方案;在運行期,則通過Actor系統最優地、靈活地支持并行、并發執行。OneFlow的内核具有簡潔、高效和高擴展性的優點


五、 淺談人工智能和深度學習的未來

OneFlow區别于其他深度學習框架的核心就是對于分布式訓練的思考和設計,OneFlow緻力于分布式訓練最快,且分布式訓練跟單卡一樣簡單易用。為什麼OneFlow這麼看重分布式的性能和易用性呢?這源于我們團隊對人工智能和深度學習的未來的看法。

我們認為随着深度學習的發展,模型會越來越大,訓練深度學習模型所需的算力會越來越高,同時模型增大的速度要大于GPU單卡顯存擴容的速度;訓練對算力的增長要求要大于GPU單卡算力增長的速度。所以分布式深度學習訓練會越來越常見、越來越重要。BERT、GPT-3等模型的出現印證了我們的判斷。單個芯片的能力總是受到物理約束,我們相信算力增長的解決之道在于橫向擴展,而這必須從系統軟件的角度去求解,一旦解決,即使是把性能“一般”的芯片互聯起來,隻要系統軟件可以讓它們協同工作好,就可以滿足任何算力需求。

在分布式深度學習訓練中,性能至關重要。我們認為性能和橫向擴展性是深度學習框架的核心競争力。我們在2017年就是這樣認為的,也是這樣做的,這就是OneFlow這個小團隊能存活至今的原因。

私以為,如果深度學習的未來是單機單卡就能搞得定的規模的話,那麼深度學習也就隻能做做目前已知的一些簡單任務,深度學習的浪潮也會褪去。

六、 開源,OneFlow還有很長的路要走

OneFlow的團隊是一個小團隊,OneFlow作為一個開源框架還有很多不足。我們框架的易用性和完善性跟Pytorch和TensorFlow相比還有一定的差距。我們團隊還在努力補上OneFlow的短闆,同時也非常需要開源社區的支持。如果以爬山來打比方,OneFlow相當于從先難後易的南坡爬珠峰,其它框架相當于從先易後難的北坡爬珠峰。

OneFlow是獨特的,有區别于其他框架的技術路線,如果您也認同OneFlow的設計理念的話,歡迎您來幫助我們一起完善OneFlow。

我們相信,從技術上看,OneFlow 是更接近完美的那一個框架。

七、 寫在最後

以上就是我對OneFlow這個深度學習框架的一點粗淺的理解,肯定有很多理解不到位的地方,希望大家批評指正。

附上OneFlow的相關鍊接,感興趣的同學可以去關注一下~

OneFlow的代碼倉庫:github.com/Oneflow-Inc/

OneFlow官網: oneflow.org/

OneFlow文檔:docs.oneflow.org/

OneFlow模型庫:github.com/Oneflow-Inc/

OneFlow API Reference:oneflow-api.readthedocs.io