RM新时代网站-首页

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內(nèi)不再提示

將TVM用于移動端常見的ARM GPU,提高移動設備對深度學習的支持能力

zhKF_jqr_AI ? 2018-01-18 13:38 ? 次閱讀

編者按:半年前,上海交大陳天奇團隊開源了端到端IR堆棧工具TVM,可以幫用戶優(yōu)化深度學習過程中的硬件配置,緩解了當前大多數(shù)計算機GPU在面對深度學習時表現(xiàn)出來的性能不足。近日,團隊的一名學生鄭憐憫帶來了項目的新進展,他將TVM用于移動端常見的ARM GPU,提高了移動設備對深度學習的支持能力。

以下是論智對原文的翻譯:

隨著深度學習不斷取得進展,開發(fā)者們對在移動設備上的部署神經(jīng)網(wǎng)絡的需求也與日俱增。和我們之前在桌面級GPU上做過的嘗試類似,把深度學習框架移植到移動端需要做到這兩點:夠快的inference速度和合理的能耗。但是,現(xiàn)在的大多數(shù)DL框架并不能很好地支持移動端GPU,因為它們和桌面級GPU在架構(gòu)上存在巨大差異。為了在移動端做深度學習,開發(fā)者們往往要對GPU做一些特殊優(yōu)化,而這類額外工作也加大了對GPU的壓力。

TVM是一個端到端的IR堆棧,它可以解決學習過程中的資源分配問題,從而輕松實現(xiàn)硬件優(yōu)化。在這篇文章中,我們將展示如何用TVM/NNVM為ARM Mali GPU生成高效kernel,并進行端到端編譯。在對Mali-T860 MP4的測試中,我們的方法在VGG-16上比Arm Compute Library快了1.4倍,在MobileNet上快了2.2倍。這些提升在圖像處理和運算上均有體現(xiàn)。

Mali Midgard GPU

目前,移動領域最常見的3大圖形處理器高通Adreno、英國PowerVR和ARM的嵌入式圖形處理器Mali。我們的測試環(huán)境是配有Mali-T860 MP4 GPU的開發(fā)板Firefly-RK3399,所以下面我們主要關注Mali T8xx的表現(xiàn)。

架構(gòu)

T860和T880是Mali系列的兩款高端GPU,下圖是具體配置。它們有16個著色器核心(Shader Core),每個核心內(nèi)包含2—3條運算管道、1條加載/存儲管道和1條紋理管道(即Triple Pipeline架構(gòu))。其中運算管道中的ALU(算數(shù)邏輯單元)又包含4個128-bit的矢量單元和一個標量單元。

我們用OpenCL編寫程序。當映射到OpenCL模型時,每個著色器核心會執(zhí)行一個或多個工作組,它們的上限是并行執(zhí)行384個線程,通常一個工作組對應一個線程。Mali系列GPU使用的是VLIW架構(gòu)(超長指令集架構(gòu)),因此每個指令包含多個操作;同時,它也用了SIMD(單指令流多數(shù)據(jù)流),所以大多數(shù)運算運算指令可以同時執(zhí)行多個數(shù)據(jù)流。

將TVM用于移動端常見的ARM GPU,提高移動設備對深度學習的支持能力

和NVIDIA GPU的區(qū)別

在用TVM優(yōu)化GPU前,我們先看一看Mali GPU和NVIDIA GPU的區(qū)別:

NVIDIA GPU的存儲系統(tǒng)架構(gòu)一般分為全局內(nèi)存、共享內(nèi)存、寄存器三層,在實踐中我們通常會把數(shù)據(jù)復制到共享內(nèi)存;而Mali GPU只有一個統(tǒng)一的全局內(nèi)存,它不需要制作副本提升性能,因為這個內(nèi)存是和CPU共享的,所以CPU和GPU之間也不需要復制;

Mali Midgard GPU基于SIMD設計,所以需要用到矢量;而在NVIDIA CUDA中,GPU的并行處理是通過SIMT實現(xiàn)的,所以它對矢量沒有那么高的要求。需要注意的是,Mali Bifrost架構(gòu)的圖形處理器新添加了Quad based vectorization技術,即允許四個線程一起被執(zhí)行,它也不太需要矢量;

Mali GPU中的每一個線程都有獨立的程序計數(shù)器,即warp size=1,所以Branch Divergence不是問題。

優(yōu)化:以卷積層為例

卷積層是許多深度神經(jīng)網(wǎng)絡的核心,也占用了大部分計算資源。所以我們以卷積層為例,談談TVM在pack、tile、unroll、向量化中的優(yōu)化應用。

im2col+GEMM

im2col是卷積計算的一種常用方法,它會把問題轉(zhuǎn)換成一個矩陣,然后調(diào)用GEMM完成矩陣乘法運算。這種方法的優(yōu)點是便于和高度優(yōu)化的BLAS庫結(jié)合,缺點是會耗費大量內(nèi)存。

Spatial Packing

所以我們換了一種方法,先計算卷積,再逐步應用優(yōu)化技術。以VGG-16中的卷積層為例(如下圖所示),inference的batch size=1。

將TVM用于移動端常見的ARM GPU,提高移動設備對深度學習的支持能力

為了提供一個對照組,我們列出了Arm Compute Library的數(shù)據(jù)。

將TVM用于移動端常見的ARM GPU,提高移動設備對深度學習的支持能力

pack和tile是兩個調(diào)整內(nèi)存的常見指令。其中tile是把數(shù)據(jù)劃分成片,使每一片適合共享內(nèi)存的使用;而pack則是對輸入矩陣重新布局(內(nèi)存對齊),方便我們按順序讀取數(shù)據(jù)。

我們在輸入圖像的寬度和filter矩陣的CO維上使用了tile(tvm.compute):

# set tiling factor

VH = 1

VW = VC = 4

# get input shape

_, CI, IH, IW = data.shape

CO, CI, KH, KW = kernel.shape

TH = IH + 2 * H_PAD

TW = IW + 2 * W_PAD

# calc output shape

OH = (IH + 2*H_PAD - KH) // H_STR + 1

OW = (IW + 2*W_PAD - KW) // W_STR + 1

# data shape after packing

dvshape = (N, TH // (VH*H_STRIDE), TW // (VW*W_STRIDE), CI, VH*H_STRIDE+HCAT, VW*W_STRIDE+WCAT)

# kernel shape after packing

kvshape = (CO // VC, CI, KH, KW, VC)

ovshape = (N, CO // VC, OH // VH, OW // VW, VH, VW, VC)

oshape = (N, CO, OH, OW)

# define packing

data_vec = tvm.compute(dvshape, lambda n, h, w, ci, vh, vw:

data_pad[n][ci][h*VH*H_STRIDE+vh][w*VW*W_STRIDE+vw], name='data_vec')

kernel_vec = tvm.compute(kvshape, lambda co, ci, kh, kw, vc:

kernel[co*VC+vc][ci][kh][kw], name='kernel_vec')

# define convolution

ci = tvm.reduce_axis((0, CI), name='ci')

kh = tvm.reduce_axis((0, KH), name='kh')

kw = tvm.reduce_axis((0, KW), name='kw')

conv = tvm.compute(ovshape, lambda n, co, h, w, vh, vw, vc:

tvm.sum(data_vec[n, h, w, ci, vh*H_STRIDE+kh, vw*W_STRIDE+kw].astype(out_dtype) *

kernel_vec[co, ci, kh, kw, vc].astype(out_dtype),

axis=[ci, kh, kw]), name='conv')

# unpack to correct layout

output = tvm.compute(oshape, lambda n, co, h, w:

conv[n][co//VC][h/VH][w//VW][h%VH][w%VW][co%VC],

name='output_unpack', tag='direct_conv_output')

用以下命令檢查定義的IR:

print(tvm.lower(s, [data, kernel, output], simple_mode=True))

選擇卷積的部分:

produce conv {

for (co, 0, 64) {

for (h, 0, 56) {

for (w, 0, 14) {

for (vw.init, 0, 4) {

for (vc.init, 0, 4) {

conv[((((((((co*56) + h)*14) + w)*4) + vw.init)*4) + vc.init)] = 0.000000f

}

}

for (ci, 0, 256) {

for (kh, 0, 3) {

for (kw, 0, 3) {

for (vw, 0, 4) {

for (vc, 0, 4) {

conv[((((((((co*56) + h)*14) + w)*4) + vw)*4) + vc)] = (conv[((((((((co*56) + h)*14) + w)*4) + vw)*4) + vc)] + (data_vec[(((((((((h*14) + w)*256) + ci)*3) + kh)*6) + kw) + vw)]*kernel_vec[((((((((co*256) + ci)*3) + kh)*3) + kw)*4) + vc)]))

}

}

}

}

}

}

}

}

}

Kernel 1:綁定線程

在TVM中,我們先計算,再計劃(schedule),這便于分離算法和實現(xiàn)細節(jié)。

如代碼所示,我們簡單把axes坐標軸對應到GPU線程,之后就能在Mali GPU上跑代碼了。

# helper function for binding thread

def tile_and_bind3d(s, tensor, z, y, x, z_factor=2, y_factor=None, x_factor=None):

""" tile and bind 3d """

y_factor = y_factor or z_factor

x_factor = x_factor or y_factor

zo, zi = s[tensor].split(z, z_factor)

yo, yi = s[tensor].split(y, y_factor)

xo, xi = s[tensor].split(x, x_factor)

s[tensor].bind(zo, tvm.thread_axis("blockIdx.z"))

s[tensor].bind(zi, tvm.thread_axis("threadIdx.z"))

s[tensor].bind(yo, tvm.thread_axis("blockIdx.y"))

s[tensor].bind(yi, tvm.thread_axis("threadIdx.y"))

s[tensor].bind(xo, tvm.thread_axis("blockIdx.x"))

s[tensor].bind(xi, tvm.thread_axis("threadIdx.x"))

# set tunable parameter

num_thread = 8

# schedule data packing

_, h, w, ci, vh, vw = s[data_vec].op.axis

tile_and_bind3d(s, data_vec, h, w, ci, 1)

# schedule kernel packing

co, ci, kh, kw, vc = s[kernel_vec].op.axis

tile_and_bind(s, kernel_vec, co, ci, 1)

# schedule conv

_, c, h, w, vh, vw, vc = s[conv].op.axis

kc, kh, kw = s[conv].op.reduce_axis

s[conv].reorder(_, c, h, w, vh, kc, kh, kw, vw, vc)

tile_and_bind3d(s, conv, c, h, w, num_thread, 1, 1)

_, co, oh, ow = s[output].op.axis

tile_and_bind3d(s, output, co, oh, ow, num_thread, 1, 1)

雖然有了這個schedule,我們現(xiàn)在可以運行代碼了,但它的性能要求還是相當可怕。

將TVM用于移動端常見的ARM GPU,提高移動設備對深度學習的支持能力

Kernel 2:unroll

循環(huán)展開(loop unrolling)是一個常用的優(yōu)化方法,它能通過減少循環(huán)控制指令降低循環(huán)本身的開銷,同時因為能消除分支以及一些管理歸納變量的代碼,它也可以攤銷一些分支開銷,此外,它還能掩蓋讀取內(nèi)存的延遲。在TVM中,你可以調(diào)用s.unroll(axis)實現(xiàn)循環(huán)展開。

# set tunable parameter

num_thread = 8

# schedule data packing

_, h, w, ci, vh, vw = s[data_vec].op.axis

tile_and_bind3d(s, data_vec, h, w, ci, 1)

"""!! ADD UNROLL HERE !!"""

s[data_vec].unroll(vw)

# schedule kernel packing

co, ci, kh, kw, vc = s[kernel_vec].op.axis

tile_and_bind(s, kernel_vec, co, ci, 1)

"""!! ADD UNROLL HERE !!"""

s[kernel_vec].unroll(kh)

s[kernel_vec].unroll(kw)

s[kernel_vec].unroll(vc)

# schedule conv

_, c, h, w, vh, vw, vc = s[conv].op.axis

kc, kh, kw = s[conv].op.reduce_axis

s[conv].reorder(_, c, h, w, vh, kc, kh, kw, vw, vc)

tile_and_bind3d(s, conv, c, h, w, num_thread, 1, 1)

"""!! ADD UNROLL HERE !!"""

s[conv].unroll(kh)

s[conv].unroll(kw)

s[conv].unroll(vw)

s[conv].unroll(vc)

_, co, oh, ow = s[output].op.axis

tile_and_bind3d(s, output, co, oh, ow, num_thread, 1, 1)

將TVM用于移動端常見的ARM GPU,提高移動設備對深度學習的支持能力

Kernel 3:向量化(vectorization)

如前所述,為了在Mali GPU上實現(xiàn)最佳性能,我們還要把數(shù)字轉(zhuǎn)成矢量。

# set tunable parameter

num_thread = 8

# schedule data packing

_, h, w, ci, vh, vw = s[data_vec].op.axis

tile_and_bind3d(s, data_vec, h, w, ci, 1)

# unroll

s[data_vec].unroll(vw)

# schedule kernel packing

co, ci, kh, kw, vc = s[kernel_vec].op.axis

tile_and_bind(s, kernel_vec, co, ci, 1)

# unroll

s[kernel_vec].unroll(kh)

s[kernel_vec].unroll(kw)

"""!! VECTORIZE HERE !!"""

s[kernel_vec].vectorize(vc)

# schedule conv

_, c, h, w, vh, vw, vc = s[conv].op.axis

kc, kh, kw = s[conv].op.reduce_axis

s[conv].reorder(_, c, h, w, vh, kc, kh, kw, vw, vc)

tile_and_bind3d(s, conv, c, h, w, num_thread, 1, 1)

# unroll

s[conv].unroll(kh)

s[conv].unroll(kw)

s[conv].unroll(vw)

"""!! VECTORIZE HERE !!"""

s[conv].vectorize(vc)

_, co, oh, ow = s[output].op.axis

tile_and_bind3d(s, output, co, oh, ow, num_thread, 1, 1)

將TVM用于移動端常見的ARM GPU,提高移動設備對深度學習的支持能力

如何設置可調(diào)參數(shù)

上文中涉及的一些可調(diào)參數(shù)是可以被計算出來的,如向量vc,如果是float32,|vc|=128/32=4;如果是float16,則是128/16=8。

但由于運行時間過長,很多時候我們會無法確定最佳值。TVM使用的是網(wǎng)格搜索,所以如果用的是python,而不是OpenCL的話,我們也能快速找到最佳值。

端到端的Benchmark

在這一節(jié)中,我們比較了一些流行深度神經(jīng)網(wǎng)絡在不同后端上的綜合性能,測試環(huán)境是:

Firefly-RK3399 4G

CPU: dual-core Cortex-A72 + quad-core Cortex-A53

GPU: Mali-T860MP4

ArmComputeLibrary : v17.12

MXNet: v1.0.1

Openblas: v0.2.18

我們使用NNVM和TVM進行端到端編譯。

性能

將TVM用于移動端常見的ARM GPU,提高移動設備對深度學習的支持能力

ImageNet上不同后端的inference速度

如上圖所示,我們在ImageNet測試了移動端神經(jīng)網(wǎng)絡的inference速度,發(fā)現(xiàn)在Firefly-RK3399上,Mali GPU可以比6核big.LITTLE CPU快2—4倍,我們的端到端編譯速度比Arm Compute Library快了1.4—2.2倍。在Arm Compute Library中,我們比較了用GEMM計算卷積和直接計算卷積,發(fā)現(xiàn)前者速度始終更快,所以在圖中只展示了GEMM方法的成果。

上圖中也有一些數(shù)據(jù)缺失,如第二幅圖不包含Arm Compute Library上的resnet18。這是因為Arm Compute Library的graph runtime目前不支持跳轉(zhuǎn)連接,并且Neon在上面的實現(xiàn)性能不太好。這也從側(cè)面反映了NNVM軟件棧的優(yōu)勢。

半精度性能

深度神經(jīng)網(wǎng)絡對精度要求不高,尤其是對于計算資源捉襟見肘的移動設備,降低精度可以加快神經(jīng)網(wǎng)絡的inference速度。我們還計算了Mali GPU上的半精度浮點數(shù)。

將TVM用于移動端常見的ARM GPU,提高移動設備對深度學習的支持能力

mageNet上FP16的inference速度

從理論上講,F(xiàn)P16既可以實現(xiàn)雙峰計算,又可以將內(nèi)存消耗減半,從而使速度提高一倍。但是如果涉及較長的向量化和某些參數(shù)的微調(diào),它也需要良好的輸入形態(tài)。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • ARM
    ARM
    +關注

    關注

    134

    文章

    9081

    瀏覽量

    367308
  • gpu
    gpu
    +關注

    關注

    28

    文章

    4723

    瀏覽量

    128873
  • 深度學習
    +關注

    關注

    73

    文章

    5497

    瀏覽量

    121094
  • TVM
    TVM
    +關注

    關注

    0

    文章

    19

    瀏覽量

    3659

原文標題:上海交大團隊:如何用TVM優(yōu)化ARM架構(gòu)GPU,在移動端實現(xiàn)快速深度學習

文章出處:【微信號:jqr_AI,微信公眾號:論智】歡迎添加關注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關推薦

    FPGA在深度學習應用中或取代GPU

    對神經(jīng)網(wǎng)絡進行任何更改,也不需要學習任何新工具。不過你可以保留你的 GPU 用于訓練。” Zebra 提供了深度
    發(fā)表于 03-21 15:19

    移動互聯(lián)網(wǎng)的發(fā)展需要移動電源的支持

    可以降低同時間的電能使用量,比如像iPad,節(jié)約了一切可以節(jié)約的耗電方式,節(jié)省一切可以節(jié)省的空間,但這對于飛速發(fā)展的IT產(chǎn)品而言委實不適。另一種方法就是提高電池的效能,為產(chǎn)品可以提供更加持續(xù)的續(xù)航能力移動互聯(lián)網(wǎng)的發(fā)展需要
    發(fā)表于 12-10 17:47

    移動互聯(lián)網(wǎng)的發(fā)展需要移動電源的支持

    移動互聯(lián)網(wǎng)的發(fā)展需要移動電源的支持,在這一領域主要有薄膜電池技術、壓電材料技術、無線充電技術。 在移動互聯(lián)網(wǎng)時代,客戶的使用很重要的一
    發(fā)表于 01-09 16:24

    三地聯(lián)動 Qualcomm邀您探索移動應用圖像進階之路

    ,并以其視聽感觀元件營造一種在虛擬世界中真實存在之感。憑借Qualcomm的高級計算機視覺功能,包括支持獲取、處理、分析和理解圖像,以提高移動設備中畫面的視覺效果。AdrenoGPU技
    發(fā)表于 08-11 11:41

    動態(tài)分配多任務資源的移動深度學習框架

    的最佳運行時資源,以同時最大化整體推斷準確率,最小化所有并行應用程序的總體處理延遲。據(jù)我們所知,NestDNN 是第一個支持資源感知的多重租賃設備深度
    發(fā)表于 10-31 16:32

    TVM主要的編譯過程解析

    `  TVM主要的編譯過程如下圖:    Import:tensorflow,onnx,pytorch等構(gòu)建的深度學習模型導入,轉(zhuǎn)化成TVM
    發(fā)表于 01-07 16:59

    TVM整體結(jié)構(gòu),TVM代碼的基本構(gòu)成

    圖:    Frontend:這個就是將來自不同深度學習框架中的神經(jīng)網(wǎng)絡轉(zhuǎn)化成TVM自己的IR表示。神經(jīng)網(wǎng)絡模型的輸入是protoBuf文件,比如在tensorflow中就是pbtxt文件,這個文件中
    發(fā)表于 01-07 17:21

    如何實現(xiàn)嵌入式平臺與深度學習的智能氣象監(jiān)測儀器的設計

    基于嵌入式平臺與深度學習的智能氣象監(jiān)測儀器設計方案一、概述二、整體框架三、人工智能部分:四、嵌入式部分4.1安卓主控4.2協(xié)處理器五、人機交互一、概述以目前常見移動
    發(fā)表于 11-09 09:14

    Mali GPU支持tensorflow或者caffe等深度學習模型嗎

    Mali GPU 支持tensorflow或者caffe等深度學習模型嗎? 好像caffe2go和tensorflow lit可以部署到ARM
    發(fā)表于 09-16 14:13

    什么是深度學習?使用FPGA進行深度學習的好處?

    ) 來解決更復雜的問題,深度神經(jīng)網(wǎng)絡是一種這些問題多層連接起來的更深層網(wǎng)絡。這稱為深度學習。目前,深度
    發(fā)表于 02-17 16:56

    基于GPU實現(xiàn)的深度學習的數(shù)據(jù)庫

    項目組基于深度學習實現(xiàn)了視頻風格化和人像摳圖的功能,但這是在PC/服務端上跑的,現(xiàn)在需要移植到移動,因此需要一個移動
    發(fā)表于 09-28 20:02 ?0次下載
    基于<b class='flag-5'>GPU</b>實現(xiàn)的<b class='flag-5'>深度</b><b class='flag-5'>學習</b>的數(shù)據(jù)庫

    小米自研開源移動深度學習框架MACE

    MACE,是指小米公司自研的移動深度學習框架Mobile AI Compute Engine。2017年12月,這一深度
    的頭像 發(fā)表于 07-26 14:06 ?3712次閱讀

    小米AI移動深度學習框架MACE開源了!

    MACE,是指小米公司自研的移動深度學習框架Mobile AI Compute Engine。2017年12月,這一深度
    的頭像 發(fā)表于 07-26 14:06 ?5012次閱讀

    TVM學習(三)編譯流程

    TVM主要的編譯過程如下圖:Import:tensorflow,onnx,pytorch等構(gòu)建的深度學習模型導入,轉(zhuǎn)化成TVM的中間層表示
    發(fā)表于 01-26 09:23 ?13次下載
    <b class='flag-5'>TVM</b><b class='flag-5'>學習</b>(三)編譯流程

    GPU深度學習應用案例

    能力,可以顯著提高圖像識別模型的訓練速度和準確性。例如,在人臉識別、自動駕駛等領域,GPU被廣泛應用于加速深度
    的頭像 發(fā)表于 10-27 11:13 ?374次閱讀
    RM新时代网站-首页