王子曦,邵培南,鄧 暢
(中國電子科技集團公司第三十二研究所,上海 201808)
隨著計算機硬件性能提升,多核心CPU 已經成為主流,越來越多云服務器開始使用GPU 加速機器學習等計算任務.性能較高的個人計算機一般是多核CPU+單個獨立GPU的模式.依靠計算機性能的發展,擅長圖形相關機器學習任務的深度學習發展迅速,不僅在云服務器上作為API 提供,在用戶客戶端上也已出現使用預訓練模型進行數據處理的需求和實現[1],例如相冊根據圖片內容進行分類、相機檢測拍攝場景類型等[2].
由于深度學習一般運算量大且處理的數據多是圖像等復雜數據,所以有必要讓程序充分并行化且盡可能利用硬件加速,來提升運算速度和用戶使用體驗.為了提高硬件利用率,需要同時使用CPU的多個核心和GPU執行任務.由于在實際應用中GPU 在執行不同類型任務時相對CPU的速度并不成固定比例,如果將任務簡單地按照固定比例分配給CPU和GPU,無法在不同類型的任務上均能充分利用硬件,所以需要使用恰當的任務調度算法在運行時進行任務分配以均衡硬件的負載.
Caffe[3]是一款使用廣泛的深度學習框架,主要面向圖像分類任務,主要優點是速度極快.在目前的主流深度學習框架中,Caffe的速度、編程工作量、穩定性比較均衡[4],而且模塊化設計便于調用和擴展.通過部署已經提前訓練好的Caffe 模型,可以在毫秒級對輸入的新數據完成推理.Caffe的使用流程是先用已標注的數據進行較慢的訓練,然后使用訓練結果進行較快的推理.在實際使用中,生產環境和普通用戶終端一般都是使用預訓練模型執行推理任務.如果已經有訓練好的Caffe 模型,需要使用Caffe的Python 或者C++、Matlab 接口[5]編寫程序,然而在默認情況下只能使用單個GPU 或者單個CPU 核心進行推理.在使用BLAS編譯Caffe 后可以提升多CPU 核心上的并行效果.不過直接部署Caffe 無法簡單同時使用多核心CPU和GPU 甚至多CPU、GPU 加速推理速度.
為了提高Caffe 在異構并行計算設備上的表現,目前有一些提高Caffe 并行表現的研究.例如英特爾的修改版Caffe 可以在多處理器多核多線程(NUMA 架構)CPU 計算平臺,尤其是使用特定Xeon Phi 處理器的平臺上大幅提升Caffe的性能[6].英偉達的gpu-rest-engine項目[7]可以讓使用英偉達GPU 進行運算的Caffe 提供低延遲的REST API 圖像分類微服務.還有AMD 修改的OpenCL 版Caffe[8],經過AMD 優化并測試,在AMD的CPU、GPU、APU 等多核異構的計算設備上訓練和推理的速度都有提升,且訓練速度的提升倍數更大[9].還有結合特定平臺上的編譯工具進行編譯并擴展到分布式服務器來提高Caffe 運算速度的研究[10].這些提高Caffe 并行表現的方法對于平臺有一定限制,且很多需要自行編譯,使用難度較高,無法簡單充分利用異構并行計算硬件的計算性能.
為了使部署的Caffe 能充分使用異構并行計算平臺上的所有計算設備,本文做了以下工作.
(1)為了使部署的Caffe 調用更靈活,本文封裝了Caffe的部署程序接口[11],并擴展了功能,使之可以在初始化運行后通過本地環回提供服務,接收并根據預訓練模型執行推理任務.
(2)分析并總結了現有的幾種異構調度算法,將這些算法應用到在異構并行計算平臺上加速Caffe 執行典型圖像分類任務.通過分析實驗數據和觀察已有調度算法的不足之處,提出了兩種新的調度算法,并進行了相應的實驗和數據分析.
對于并行化的任務,任務調度算法決定了負載均衡的效果和各個計算節點的利用率.由于GPU和CPU執行不同任務的速度之比并非固定且GPU 性能隨著負載變化性能會有微小變化[12],還考慮到任務調度、同步帶來的開銷,需要合適的任務調度算法才能進一步提高模型的推理速度.當前使用的幾種主流調度算法[13]如下.
靜態調度是一種簡單的調度算法,此算法直接將任務按照固定比例分配到不同的運算核心.假設總任務數量為W,用戶指定的n個計算設備工作量比例r=[r1,r2,···,rn],則第i個計算設備在開始時分配任務數量wi為:

由于通常無法知道各個設備在未知任務上的計算能力,所以只能將任務均勻分配給各個設備,此時第i個計算設備在開始時分配的任務數量wi為:

由于CPU 核心和GPU 之間的運算速度比例在不同運算任務上不同,所以不可能存在一個固定的比例在所有運算任務上都能自始至終充分利用所有核心.
考慮到靜態調度無法根據不同運算核心的性能區別分配任務,快速調度將任務執行分成以下兩步.
第1 步為小規模測試,給所有計算核心分配相同的數量較小的任務,并等待這些核心執行完畢.
第2 步為正式執行,根據之前第1 步各個核心的執行時間,可以計算出各個核心的執行速度.根據核心的速度之比將剩下的所有任務按照這個比例分配給相應核心.
假設第1 步小規模測試得出各個設備的計算性能v=[v1,v2,···,vn],此時剩余任務數量為w剩余,則第2 步正式執行中第i個設備分配到的任務數量wi為:

這種調度方法優點是任務沒有劃分很多,所以引入的額外開銷很小.缺點是第1 步分配的任務數量會影響到最終效果.如果分配過少,偶然誤差更大,更有可能因為速度估測不準導致第2 步分配效果不好;如果分配過多,雖然估測更加精準,但是等待第1 步結束的同步時間更長,浪費了速度更快的計算設備的計算能力.
分片調度將任務分成等量的小塊,第一次將小塊任務等量分配給各個計算單元.之后每一次等待前一次所有運算完成得出運算速度后按照相應比例分配后續小塊.
假設某次同步時得出上一輪各個設備的計算性能v=[v1,v2,···,vn],每一個小塊包含的任務數量為w,則第i個設備分配到的任務數量wi為:

此算法優點是對于各個計算設備的計算能力估測更準確.缺點是如果小塊偏小,等待計算完畢同步的時間會積少成多;如果小塊偏大,剛開始各個設備之間任務完成的時間差距更大,導致計算能力的浪費.
HAT 調度相比分片調度,在每一次分片時考慮上一次的任務執行情況,如果上一次各個計算設備的任務執行時間已經很接近或者剩下任務不夠多,就直接把剩余所有任務按照比例分配,否則把分片大小擴大一倍按照比例分配.
此方法的優點是減少了同步開銷,還避免了開始時各個計算設備計算能力的差異導致完成時間差距過大.
目前已有的快速調度、分片調度、HAT 調度算法,由于存在等待各個計算設備任務完成來統計計算性能這一同步步驟,會帶來開銷.為減少同步開銷,本文提出以下兩種無需等待同步的調度算法.
此調度算法設計思想來自常見的先進先出算法.將固定任務數量的小塊分配給各個計算設備.假如用戶定義的小塊大小是c,則第i個設備分配到的任務數量wi為:

如果某個設備計算完畢則立即再分配任務小塊,直到所有任務完成.此方法沒有等待各個設備同步的開銷,能充分利用所有設備的計算能力.
先進先出調度中的小塊始終大小相等,對于前期來說分片過多會造成更多開銷,而在最后結尾部分很容易各個設備結束時間差別過大.因此,本文進一步提出下面的快速分塊調度算法.
此算法同時吸收了分片算法估測計算設備性能準確的優點和HAT 分塊數量少的優點.首先將固定的任務小塊ws分給各個計算設備,如果某設備完成了小塊任務但此時不是所有設備都完成過至少一次小塊任務,就再次給該設備相同任務數量的小塊,直到所有設備都至少完成過一次小塊任務.每次小塊任務完成,都統計出該設備的計算性能vi.之后按照設備計算性能給每個空閑設備分配剩余任務的固定比例.考慮到后期任務會分配過少,所以剩余任務少于100 時則分配全部剩余任務.假設已得出所有設備的計算性能v=[v1,v2,···,vn],固定比例為r,當前剩余工作量為w剩余.則給空閑設備分配的任務數量為:

每個計算設備的程序流程如圖1所示.

圖1 快速分塊調度流程圖
Caffe的使用流程是先用已標注的數據進行較慢的訓練,然后使用訓練結果進行較快的推理.在實際使用中,生產環境和普通用戶終端需求的多是推理任務.Caffe 默認只能使用GPU 或者單個CPU 進行推理.為了解決重復初始化Caffe 帶來的開銷和提高Caffe 推理對異構并行硬件的利用率,本文編寫了封裝的Caffe部署程序(后續簡稱服務端),提供簡潔高效的調用接口且易于部署.
為了能夠一次初始化Caffe 并載入預訓練模型后多次推理,且可以通過程序分配任務便于后續使用自定義調度算法,采用了本地環回網絡通信,服務端通過UDP和調用程序通信.通信時通過UDP 發送JSON 數據,數據可以包括執行的命令和參數等,便于擴展.
為了使服務端的部署更加便捷,使用了Caffe的Docker 版.運行時,可以通過Docker 啟動參數直接使用某個特定的CPU 核心[14].由于即使使用GPU 版進行Caffe 推理也需要CPU 分配任務處理數據,會大量占用一個CPU 核心,所以服務端需要預留一個CPU核心用于工作在GPU 模式的Caffe.
使用本文編寫的服務端,自定義程序可以便捷地調用Caffe 進行推理.本節給出有關測試結果,實驗環境配置參數列于表1.

表1 實驗環境配置表
實驗使用MNIST[15]和Cifar-10[16]這兩個經典的圖像分類任務數據集.MNIST 數據集為單通道灰度28×28 圖片,Cifar-10 數據集為三通道彩色32×32 圖片.測試時這兩個數據集均預處理為Caffe 推理支持的numpy 格式的.npy 文件且載入內存,避免磁盤讀取緩存帶來的誤差.
首先,測試了不使用并行化而只使用CPU 單核或者單個GPU 在MNIST和Cifar-10 數據集上進行推理的速度,總任務數量為10 000,得到的每秒執行推理任務數列在表2中.

表2 每秒執行的推理任務數
結果表明,每次提交的任務數過少會因為開銷導致性能下降.而且,對于不同任務,CPU和GPU的性能之比不是恒定的.
根據表2數據,得到Caffe 推理速度與每次提交任務數的變化關系,見圖2.可以看到,無論是CPU和GPU,如果每次提交任務數偏少都會因為開銷導致性能下降,且GPU 下降更明顯.從圖2中可以看出,如果任務拆分到1 000 個左右作為一次提交,對性能的影響不大,如果小于100 個左右,影響就較大,出現性能明顯下降.因此,后面實驗測試異構并行計算平臺的Caffe推理調度算法時,避免將任務拆分到小于100 個任務的小塊.

圖2 Caffe 推理速度和每次提交任務數的關系圖
接下來在異構并行平臺測試了幾種調度算法對MNIST和Cifar-10 數據集上的Caffe 推理任務的加速效果.考慮到某些算法的參數可變,實驗中針對這些參數的意義,在其合理范圍內取了多個典型值,以測試不同參數下的運行效果.不同算法中可變參數的含義和取值列于表3.

表3 調度算法的參數和實驗取值
分別使用上文中的各種調度算法及按表3的參數取值,在MNIST和Cifar-10 數據集上進行Caffe 推理(測試的任務數均為100 000)并計時,根據完成任務所用時間計算出每秒推理數,即推理速度,總結在圖3和圖4中.圖中同一調度算法從左到右的幾個推理速度分別對應表3中從左到右的參數取值.為了便于比較,同樣任務數下只使用CPU 單核和單個GPU的推理速度也畫在圖中.
從圖3和圖4都能看到,使用能在運行時根據運算設備性能動態分配任務的調度算法,例如快速調度、分片調度、HAT 調度、先進先出調度、快速分塊調度算法,相比不將推理過程并行化或者簡單地靜態分配,都能大幅提升推理速度.實驗中發現,計算機的各個計算設備占用率基本維持在滿載,且各個設備任務完成的時間差異不大,說明上述能在運行時動態分配任務的調度算法都成功使用異構并行設備的計算能力,提高了Caffe 推理的速度.
圖3和圖4也給出了對于同一算法改變可調參數后的推理速度的變化.可以看出,對于分片調度、HAT調度和快速分塊調度這3 種算法,參數改變產生的差異更小.分析其算法原理可以知道,這幾種算法通過更多分片能更準確地度量各個計算設備的當前計算能力,從而更加準確地分配任務.相比之下,快速調度由于只通過一次小規模測試來度量各個計算設備的計算能力,無法適應隨著計算設備負載變化而出現的性能變化.先進先出調度由于分塊大小固定,如果分塊過小,會帶來更多開銷;如果分塊過大,每個計算設備最后任務完成時間可能差異較大導致某個設備任務完成時間遠晚于其他設備.

圖3 不同調度算法下Caffe 在MNIST數據集上的每秒推理數

圖4 不同調度算法下Caffe 在Cifar-10數據集上的每秒推理數
比較性能表現較好的幾個調度算法,本文提出的快速分塊調度算法不僅性能表現頂尖,而且即使改變可變參數,性能變化不大,更不會出現明顯下降.說明快速分塊調度算法不僅具有提升推理速度的優勢,還有很好的魯棒性,不容易因為缺乏經驗對可變參數的設定不準而導致推理性能明顯下降.根據算法原理,可以推測出,由于快速分塊調度算法前期分塊較大后期分塊較小,相比HAT 算法更不容易造成每個計算設備最后任務完成時間較大差異,同時分塊不會過多,所以性能和HAT 算法一樣較為優秀且總體表現好于HAT 算法.
根據實驗數據,將同一算法在實驗中取不同參數得到的推理速度數據求平均值作為該算法的平均推理速度,比較各算法在兩個數據集上的平均推理速度,總結在表4和表5中.表中數據是所在列的算法和所在行的算法平均推理的速度的比較,例如127.7%對應的意思是單GPU 推理速度比單CPU 快127.7%.可以看出使用能在運行時根據運算設備性能動態分配任務的調度算法對Caffe 深度學習推理速度的提升很大,其中快速分塊調度算法表現最好.

表4 各種調度算法在MNIST 數據集上推理速度表現比較(%)

表5 各種調度算法在Cifar-10 數據集上推理速度表現比較(%)
以CPU和GPU 單核計算性能乘以相應核心數量,作為理論最高性能.定義某一算法的性能與理論最高性能的差別為:差別=(理論最高性能?某種算法性能)/理論最高性能.差別越小,表示該算法的表現性能越好.圖5將實驗中得到的幾種在運行時分配任務的調度算法的性能數據與理論最高性能的差別做了比較.結果表明,快速分塊調度表現最好,與其余4 個調度算法中表現最好的HAT 算法相比,快速分塊調度算法與理論最高性能的差別在MNIST和Cifar-10 這兩個數據集上分別減小了7.4%和21.0%,表明該算法對計算設備性能的利用率更高.

圖5 不同調度算法性能相比理論最高性能的差別百分比
為了在異構并行計算平臺上提升Caffe 框架的深度學習推理速度,本文擴展了Caffe的部署程序,使用戶可以自定義編程調用Caffe 推理.然后將已有的異構調度算法擴展了多設備支持.針對已有調度算法的不足,提出了能夠減少同步等待的先進先出算法、能夠同時減少同步等待且減少分塊次數的快速分塊調度算法.測試結果表明使用擴展的Caffe 部署程序,已有的快速調度、分片調度、HAT 調度等算法,以及本文提出的先進先出調度、快速分塊調度算法都能大幅提高推理時異構并行計算硬件的利用率.其中快速分塊調度表現優秀穩定,在MNIST和Cifar-10 數據集上推理速度相比CPU 單核分別提升了378%和736%,相比單GPU 分別提升了110%和34%;相比已有最好的HAT 調度算法,在MNIST和Cifar-10 這兩個數據集上分別減小了7.4%和21.0%的計算性能浪費.
在將來的研究中,可以探索深度學習模型中使用的神經網絡類型或者輸入數據規模如何造成CPU和GPU的推理速度差異.根據神經網絡類型、輸入數據規模等信息更快地選擇出合適的調度算法參數來優化推理速度的提升.