天天看點

從NNVM看2016年深度學習架構發展趨勢

雷鋒網(公衆号:雷鋒網)按:本文作者潘汀,合肥工業大學計算機專業大三大學生,中科院深圳先進院內建所mmlab通路學生。原acm-icpc算法競賽選手,2015年獲ccpc銅牌。2015年初開始研究機器學習,研究興趣集中于對深度學習理論、應用(cv&nlp)及系統架構設計的綜合探索。關于深度學習在面部情感分析方面應用的論文被《自動化學報》錄用。

| 虛拟架構殺入

從NNVM看2016年深度學習架構發展趨勢

從發現問題到解決問題

半年前的這時候,暑假,我在siat mmlab實習。看着同僚一會兒跑torch,一會兒跑mxnet,一會兒跑theano。

siat的伺服器一般是不給sudo權限的,我看着同僚掙紮在編譯這一坨架構的海洋中,開始思考是否可以寫一個架構:

從NNVM看2016年深度學習架構發展趨勢

這樣,利用工廠模式隻編譯執行部件的做法,隻需編譯唯一的後端即可,架構的不同僅僅在于前端腳本的不同。

caffe2keras的做法似乎是這樣,但keras本身是基于theano的編譯後端,而我們的更希望theano都不用編譯。

當我9月份拍出一個能跑cifar10的大概原型的時候:

從NNVM看2016年深度學習架構發展趨勢

我為這種怪異的寫法取名叫cgvm(computational graph virtual machine)然後過了幾天,在微網誌上看到了陳天奇在mxnet的進一步工作nnvm的釋出 (o(╯□╰)o)......

nnvm使用2000行模拟出了tensorflow,我大概用了500行模拟出了caffe1。

vm(virtual machine)的想法其實是一個很正常的想法,這幾年我們搞了很多新架構,名字一個比一個炫,但是本質都差不多,架構的使用者實際上是苦不堪言的:

這篇paper使用了a架構,我要花1天配置a架構。

這篇paper使用了b架構,我要花1天配置b架構。

.......

正如llvm不是一種編譯器,nnvm也不是一種架構,看起來更像是架構的屠殺者。

nnvm的可行性恰恰證明了現行的各大架構底層的重複性,而上層的多樣性隻是一個幌子。

我們真的需要為僅僅是函數封裝不同的架構買單嗎?這是值得思考的。

| 計算圖走向成熟

從NNVM看2016年深度學習架構發展趨勢

1、計算圖的兩種形式

計算圖最早的出處應該是追溯到bengio在09年的《learning deep architectures for ai》,bengio使用了有向圖結構來描述神經網絡的計算:

從NNVM看2016年深度學習架構發展趨勢

如圖,符号集合{*,+,sin} 構成圖的結點,整張圖可看成三部分:輸入結點、輸出結點、從輸入到輸出的計算函數。

随後在bengio組的theano架構執行中,graph就被隐式應用于op的連接配接。不過這時候,op還是執行時-動态編譯的。

caffe1中計算圖其實就是net,因為net可以被graph模拟出來(cgvm和caffe2keras都實作了)。

賈揚清在caffe1中顯式化了計算圖的表示,使用者可以通過編輯net.prototxt來設計計算圖。

caffe1在jonathan long和evan shelhamer接手後,他們開發了pycaffe。pycaffe通過python天然的工廠(__getattr__),實作了net.prototxt的隐式生成。

之後的caffe2,也就直接取消了net.prototxt的編輯,同樣利用python的(__getattr__)擷取符号類型定義。

caffe1帶來一種新的計算圖組織op的描述方式,不同于theano直接翻譯op為c執行代碼,然後動态編譯,軟體工程中的進階設計模式——工廠模式被廣泛使用。

計算圖被劃分為三個階段,定義階段、構造階段、執行階段:

1、定義階段:定義layer/op的name、type、bottom(input),top(output)及預設參數。 2、構造階段:通過工廠模式,由字元串化的定義腳本構造類對象。 3、執行階段:根據傳入的bottom(input),得到額外參數(如shape),此時計算圖才能開始執行。階段劃分帶來的主要問題是限制了編譯代碼的完整性和優化程度。

在theano中,c代碼生成是最後一步,編譯前你可以組合數個細粒度符号,依靠編譯器做一次硬體執行上的優化。

而工廠模式編譯符号時隻考慮了單元,編譯器沒有上下文可供參考優化,故最終隻能順序執行多個預先編譯的符号單元。

當符号粒度過細時,一個layer的實作就會變成連續執行多個子過程,導緻“tensorflowslow”。

2、計算圖作為中間表示(ir)

pycaffe和caffe2将定義階段移到python中,而将構造和執行階段保留在c++中做法,是計算圖作為ir的思想啟蒙。

python與c++最大的不同在于:一個是腳本代碼,用于前端。一個是本地代碼,用于後端。

腳本代碼建立/修改模型友善(無需因模型變動而重新編譯)、執行慢,本地代碼則正好相反。

兩者取長補短,是以深度學習架構在2016年,迎來了前後端開發的黃金時代。

從NNVM看2016年深度學習架構發展趨勢

如上圖,無論是9月份先提出的nnvm,還是最近intel曝光的nervana,都分離了前後端。

後端的獨立,不僅減少了編譯工作,最大的優勢在于降低了傳統架構做跨裝置計算的代碼耦合度。

在paper每周都有一大堆的現在,如果後端的每一次變動都要大量修改前端,那麼架構的維護開銷是非常大的。

在前端定義用于描述輸入-輸出關系的計算圖有着良好的互動性,我們可以通過函數和重載腳本語言的操作符,定義出媲美matlab的運算語言,這些語言以顯式的tensor作為資料結構,operator作為計算符和函數,theano和mxnet都是這樣隐蔽處理由表達式向計算圖過渡的。

而caffe2則比較直接,你需要先建立一個graph,然後顯示地調用graph.addoperator(xxx) tensorflow同樣可以顯式化處理graph。

與使用者互動得到的計算圖描述字串是唯一的,但是與使用者互動的方式卻是不唯一的。

是以ir之上,分為兩派:

第一派要搞自己的api,函數封裝非常有個性,宣示這是自己的專利、獨門語言。

第二派不搞自己的api,反而去模拟現有的api,表示我很低調。

顯然,使用者更喜歡用自己熟悉架構的寫法去描述模型,不喜歡天天背着個函數速查手冊。

3、計算圖優化

用于中間表示得到的計算圖描述最好不要直接構造,因為存在備援的求解目标,且可共享變量尚未提取。

當限制計算圖描述為有向無環圖(dag)時,一些基本的圖論算法便可應用于計算圖描述的化簡與變換。

陳天奇在今年的msr talk:programming models and systems design for deep learning中,總結了計算圖優化的三個點:

從NNVM看2016年深度學習架構發展趨勢

①依賴性剪枝

分為前向傳播剪枝,例:已知a+b=x,a+b=y,求x?

反向傳播剪枝,  例:a+b=x,a+b=y,求x、y,dx/da?

根據使用者的求解需求,可以剪掉沒有求解的圖分支。

②符号融合

符号融合的自動實作是困難的,因為kernel基本不再實時編譯了,是以更多展現在符号粗細粒度的設計上。

粗粒度的符号融合了數個細粒度的符号,一次編譯出連續多個執行步驟的高效率代碼。

粗粒度和細粒度并無好壞區分,一個速度快,一個更靈活。

從貪心角度,vm架構通常會提供粗細粒度兩種實作給使用者,因而需要更多人力維護編譯後端。

③記憶體共享

caffe1對于激活函數大多使用的inplace處理——即bottom和top是同一個blob。

inplace使用新的輸出y立即覆寫的輸入x,需要以下兩個條件:

1、bottom和top數量都為1,即:計算圖中構成一條直線路徑,

2、d(y)/d(x)與x是無關的,是以x被y覆寫不影響求導結果。

常見的激活函數都符号以上兩個條件,因而可以減少記憶體的開銷。

但是caffe1在多網絡記憶體共享優化上極其糟糕的,以至于caffe1并不适合用來跑gan,以及更複雜的網絡。

一個簡單例子是交叉驗證上的優化:訓練網絡和驗證網絡的大部分layer都是可以共享的,但是由于caffe1錯誤地将blob獨立的放在每個net裡,使得跨net間很難共享資料。

除此之外,caffe1還錯誤地将臨時變量blob獨立放在每個layer裡,導緻列卷積重複占用幾個g記憶體。

讓net和layer都能共享記憶體,隻需要将tensor/blob置于最頂層,采用mvc來寫架構即可。

caffe2引入了workspace來管理tensor,并将工作空間的指針傳給每一個op、每一個graph的構造函數。

| 新的風暴已經出現

從NNVM看2016年深度學習架構發展趨勢

1、vm的側重點

cgvm和nnvm的側重點是不太一樣的,cgvm更強調前端上的擴充化,後端上的唯一化。是以cgvm不會去支援torch編譯後端,也不會去支援caffe編譯後端。

在nnvm的知乎讨論帖中,有一種觀點認為vm是輕視operator的實作。但實際上,我們手裡的一堆架構,在operator、kernel、math級别的不少實作是沒有多少差別的。

但恰恰折磨使用者的正是這些沒有多少差別的編譯後端:各種依賴庫、裝linux、編譯各種錯。

是以我個人更傾向整個dl社群能夠提供一份完善的跨平台、跨裝置解決方案,而不是多而雜的備選方案。

從這點來看,cgvm似乎是一個更徹底的架構殺手,但在icml'15上, jürgen schmidhuber指出:

真正運作ai 的代碼是非常簡短的,甚至高中生都能玩轉它。不用有任何擔心會有行業壟斷ai及其研究。 簡短的ai代碼,未必就是簡單的架構提供的,有可能是自己熟悉的架構,這種需求展現在前端而不是後端。

vm指出了一條多架構混合思路:功能a,架構x寫簡單。功能b,架構y寫簡單。

功能a和功能b又要end-to-end,那麼顯然混起來用不就行了。隻有使用頻率不高的架構才會消亡,vm将架構混合使用後,熟悉的味道更濃了,那麼便構不成”架構屠殺者“。

強大的ai代碼,未必就是vm提供的,有可能是龐大的後端提供的。随着paper的快速疊代,後端的擴充仍然是最繁重的程式設計任務。

vm和後端側重點各有不同,難分好壞。但分離兩者的做法确實是成功的一步。

2、vm的形式

vm及計算圖描述方式是連接配接前後端的橋梁。

即便後端是唯一的,根據支援前端的不同,各家寫的vm也很難統一。實際上這就把架構之間的鬥争引向了vm之間的鬥争。兩人見面談笑風生,與其問對方用什麼架構,不如問對方用什麼vm。

3、vm的主要工作

合成計算圖描述的過程是乏味的,在caffe1中,我們恐怕已經受夠了人工編輯prototxt。

api互動方面,即便是mxnet提供給使用者的api也是複雜臃腫的,或許仍然需要一個handbook。

tensorflow中的tensorboard借鑒了webos,vm上搞一個互動性更強的作業系統也是可行的。

除此之外,我可能比較熟悉一些經典架構,那麼不妨讓vm去實作那些耳熟能詳的函數吧!

1)模拟theano.function

theano的function是一個非常貼近數學表達計算圖掩飾工具。function内部轉化表達式為計算圖定義,同時傳回一個lambda函數引向計算圖的執行。總之這是一個百看不膩的api。

2)模拟theano.grad

結合計算圖優化,我們現在可以指定任意一對求導二進制組(cost, wrt)。因而,放開手,讓自動求導在你的模型中飛舞吧。

3)模拟theano.scan

theano.scan是一個用來搭建rnn的神器。盡管最近caffe1更新了rnn,但是隻支援固定循環步數的rnn。而theano.scan則可以根據tensor的shape,為rnn建動态的計算圖,這适合在nlp任務中處理不定長句子。

4)模拟pycaffe

pycaffe近來在rcnn、fcn、deepdream中得到廣泛應用,成為搞cv小夥伴們的最愛。pycaffe大部分是由c++資料結構通過boost.python導出的,不幸的是,boost.thread導出之後與python的gil沖突,導緻pycaffe裡無法執行c++線程。嘗試模拟移除boost.python後的pycaffe,在python裡把solver、net、layer給寫出來吧。

5)模拟你熟悉的任意架構

.......等等,怎麼感覺在寫模拟器.....當然寫模拟器基本就是在重複造輪子,這個在nnvm的知乎讨論帖中已經指明了。

4、vm的重要性

vm是深度學習架構去中心化、解耦化發展邁出的重要一步。同時暴露了目前架構圈混亂的本質:計算圖之下,衆生平等。計算圖之上,群魔亂舞。

在今年我們可以看多許多架構pk對比的文章,然而大多隻是從使用者觀點出發的簡單評測。對比之下,nnvm關注度不高、反對者還不少這種情況,确實讓人感到意外。

| 回顧與展望

從NNVM看2016年深度學習架構發展趨勢

1、回顧2016:架構圈減肥大作戰的開始

高調宣布開源xxx架構,再封裝一些api,實際上已經多餘了。

vm的出現,将上層接口的編寫引向模拟經典的架構,進而達到減肥的目的。

架構維護者應當将大部分精力主要放在kernel的編寫上,而不是考慮搞一些大新聞。

2、展望2017:dl社群能否聯合開源出跨平台、跨裝置的後端解決方案

後端上,随着arm、神經晶片的引入,我們迫切需要緊跟着硬體來完成繁重的程式設計。

後端是一個敏感詞,因為硬體可以拿來賣錢,是以更傾向于閉源。

除此之外,即便出現了開源的後端,在山寨和混戰之前是否能普及也是一個問題。

3、展望2017:來寫架構吧

vm的出現,帶來另一個值得思考的問題:現在是不是人人應該學寫架構了?

傳統架構編寫的困難在代碼耦合度高,學習成本昂貴。vm流架構分離了前後端之後,前端編寫難度很低,後端的則相對固定。

這樣一來,架構的程式設計層次更加分明,keras地位似乎要危險了。

4、展望2017:更快疊代的架構,更多變的風格,更難的壟斷地位

相比于paper的疊代,架構的疊代似乎更快了一點。

餘凱老師前段時間發出了tensorflow壟斷的擔憂,但我們可以很樂觀地看到:越來越多的使用者,在深入架構的底層。

tensorflow并不是最好的架構,mxnet也不是,最好的架構是自己用的舒服的架構,最好是一行行自己敲出來的。如果你已經積累的數個架構的使用經驗,是時候把它們無縫銜接在一起了。

雷鋒網注:本文由深度學習大講堂授權雷鋒網釋出,如需轉載請注明作者和出處,不得删減内容。

本文作者:深度學習大講堂