高性能零存儲開銷直接卷積論文及其理解

論文下載地址:http://proceedings.mlr.press/v80/zhang18d.html

簡略翻譯

? ??????????????????????????????????????????????????????????????????????????高性能零存儲開銷直接卷積

摘要

計算中的卷積神經網絡的深層通常是依賴于高性能的程序時使用額外的貿易空間的內存或任何所需的一部分。用于包裝用途的算法來提高性能。這樣的方法存在兩個問題。首先,這些例程會引起額外的內存開銷,從而減少能夠適合于具有有限內存容量的嵌入式設備的網絡的總體大小。其次,這些高性能例程沒有針對執行卷積進行優化,這意味著獲得的性能通常低于常規預期。在本文中,我們證明,當正確實現時,直接卷積消除了所有的內存開銷,并且產生的性能比傳統和嵌入式CPU架構上卷積層的現有高性能實現高10%到400%。我們還表明,當增加線程數量時,高性能直接卷積具有更好的伸縮性能,即性能下降較小。

1 .導言

傳統觀點認為,通過直接卷積計算深層神經網絡中的卷積層不是有效的。因此,在深層神經網絡中計算卷積層的許多現有方法(.等人,2014;Cho & Brand,2017)基于在諸如基本線性代數子程序(BLAS)(.arra等人,a)等計算庫中發現的高度優化的例程(例如,矩陣矩陣矩陣乘法)。L,1990)。為了利用矩陣-矩陣乘法例程,這些框架重塑并選擇性地復制原始輸入數據的一部分(統稱為打包)。從而為性能帶來額外的內存空間。

這種方法存在兩個問題:首先,重新整形和復制輸入數據的元素的額外工作是一個帶寬受限的操作,這會導致額外的操作,和非平凡的時間懲罰對整個系統性能的影響。第二,更重要的是,卷積層產生的矩陣通常具有與傳統高性能計算(HPC)應用程序產生的矩陣不同的維度。因此,矩陣矩陣乘法例程在卷積矩陣上的性能通常不如HPC矩陣好。

為了說明現有方法的這些缺點,考慮使用圖1所示的AMD Piledriver體系結構在AlexNet中的各種卷積層上獲得的4線程性能。在這個圖中,我們展示了:1)一個傳統的基于矩陣乘法的卷積實現與OpenBLAS1 (OpenBLAS)(藍色)和2)我們提出的高性能直接卷積實現(黃色)相關聯的性能。這兩種實現的性能都標準化為僅矩陣-矩陣乘法例程(虛線)的性能。這條虛線是在無填充的情況下矩陣-矩陣乘法所獲得的性能。注意,OpenBLAS +填料的性能僅達到矩陣乘法本身性能的不到80%。這意味著包裝程序使整體性能下降了20%以上。相比之下,我們的自定義直接卷積實現的性能超過了專家實現的矩陣-矩陣乘法例程,即使打包是免費的。此外,我們在沒有任何額外內存開銷的情況下實現了性能。

隨著基于深度神經網絡的機器學習任務越來越多地被放置在邊緣設備上,重新研究卷積層的計算方法是及時的(Schuster, 2010;Lee & Verma, 2013)。這些設備往往在計算能力和內存容量方面受到限制(Gokhale et al., 2014;Dundar等)。這意味著以內存容量換取性能的現有方法不再是這些設備的可行解決方案。提高性能和減少內存開銷也能帶來更好的能源效率(Zhang et al., 2014)。雖然許多工作都集中在通過近似(Kim et al., 2015)、量化(Gong et al., 2014)或權重的稀疏化(Han et al., 2016)來減少卷積層的內存占用(memory footprint),但是很少有工作解決為了使用高性能例程所需要的額外內存需求。

以下是本文的貢獻:

高性能直接卷積。我們證明了直接卷積的高性能實現可以在實際性能、并行性和減少內存開銷方面勝過基于專家實現的矩陣-矩陣乘法卷積。這說明直接卷積是一種可行的計算卷積層的方法。

輸入/輸出特征圖和內核權重的數據布局。我們提出了新的數據布局,用于存儲使用直接卷積算法計算卷積層所需的輸入、輸出和核權值。這些新的數據布局所需的空間與現有的數據存儲方案相同,用于存儲輸入、輸出和內核權重,而不是對元素進行打包或復制。



圖1。高性能直接卷積實現比高性能矩陣乘法例程獲得更高的性能,而基于矩陣乘法的卷積實現受到封裝開銷的影響并且受矩陣乘法例程的性能限制。

非直接卷積的無效率

在本節中,我們將重點介紹在許多深度學習框架中使用的現有方法計算卷積的低效性

快速的基于傅立葉變換的實現

基于快速傅立葉變換(FFT)的實現(Vasilache et al., 2014;Mathieu et al., 2013)提出了一種在頻域計算卷積時減少浮點運算次數的方法。然而,為了使計算進行內核的重量必須填充輸入圖像的大小,導致內存明顯多于必要的,特別當內核本身很小(例如3×3)

人們提出了其他方法來將圖像細分為更小的塊或塊(Dukhan)。然而,這種方法還需要將內核權重填充到方便的大小(通常是2的冪),以獲得性能。即使將內核權重填充到架構寄存器大小的小倍數(例如8或16),也會導致內存需求增加7到28倍。這種額外的填充和將內核轉換為頻域可以通過實時執行FFT(卷積層計算的一部分)來最小化。然而,正如我們將在性能部分(第5部分)中展示的那樣,這會帶來顯著的性能開銷,尤其是在嵌入式設備上。

矩陣Multiplication-based實現

另一種常見的方法是將輸入(圖像和內核權重)轉換為矩陣,并利用第3級基本線性代數子程序(BLAS) (Dongarra et al., 1990)中發現的高性能矩陣-矩陣乘法例程進行計算。這種方法有兩個主要的低效之處:

額外的內存需求。為了將圖像轉換成一個矩陣,需要執行一個降低操作將三維圖像轉換成一個二維矩陣。通常情況下,這是通過一個操作執行傳統稱為im2col復制圖像變成矩陣然后用作輸入矩陣*矩陣的乘法中調用。在這個降低過程中,適當的元素也會被復制。所需的額外內存隨問題大小呈二次增長(Cho & Brand, 2017)。

Cho和Brand (Cho & Brand, 2017)提出了一種替代的降低機制,即通過減少包裝過程中需要的重復數量來提高內存效率。在它們的降低例程中,內存占用比im2col平均減少3.2倍。這是通過消除所需的重復數量,以犧牲額外的矩陣-矩陣乘法調用來實現的。盡管如此,這仍然是一個額外的內存需求,而且它們的計算仍然依賴于矩陣-矩陣乘法,對于由卷積產生的矩陣來說,這種乘法通常不是最優的。

????????????????????????????(Sub-optimal matrix matrix multiplication.)次優矩陣矩陣乘法。

在大多數BLAS庫(如GotoBLAS (Goto &van de Geijn,2008)、OpenBLAS (OpenBLAS)、BLIS (van Zee &van de Geijn, 2015)中,矩陣-矩陣乘法例程在內部維即。兩個輸入矩陣之間共有的維數,輸入矩陣的維數與輸出矩陣的總體維數相比很小。這種特殊的矩陣形狀集合通常在科學和工程代碼中找到,這些代碼對這些庫進行了優化。然而,這種特殊的形狀集只適用于六種矩陣乘法算法中的一種(goto&van de Geijn, 2008)。

記得im2col重塑輸入矩陣。這意味著輸入矩陣的內部維度通常大于兩個維度(參見圖2)。因此,矩陣乘法在這組特定輸入形狀上的性能通常明顯低于最佳可實現性能。已經證明,對于與卷積層產生的形狀相似的形狀,應該尋求計算矩陣乘法的替代算法(gunnel et al.,2001)。

矩陣-矩陣乘法在卷積層中效率低下的另一個原因是,現有BLAS庫中的并行性是通過對輸入矩陣的行和列進行分區得到的(Smith et al., 2014)。矩陣的這種劃分使矩陣形狀偏離矩陣-矩陣乘法例程所期望的形狀更遠。因此??,隨著線程數量的增加,例程的效率會受到影響。

高性能直接卷積計算

直接卷積(參見算法1)的一個簡單實現實質上是圍繞計算單個輸出元素的乘積計算語句的六個完全嵌套循環。循環排序的任何排列都會產生正確的結果。然而,為了獲得直接卷積的高性能實現,必須將這些循環及其順序適當地映射到給定的體系結構。

將循環映射到體系結構的策略

我們將循環映射到模型架構的策略類似于高性能矩陣矩陣乘法的分析模型(Low等人,2016)。(1)首先介紹了高性能矩陣矩陣乘法的模型結構。(2)接下來,我們確定有效利用可用計算單元的循環。(3)最后,為了改善數據重用,我們識別外部循環的順序,這反過來將減少引入計算中的性能降低的停頓量。在本討論中,我們使用算法1中所示的索引變量(i,j,k,l,m,n)來區分循環。

模型架構

我們使用了用于高性能矩陣乘法的分析模型的模型體系結構(Low et al., 2016)。假定模型體系結構具有以下特征:

向量寄存器。我們假設我們的模型架構使用單個指令多個數據(SIMD)指令集。這意味著每個操作同時對標量輸出元素執行其操作。我們還假設是2的冪。當為1時,這意味著只有標量計算可用。此外,所有的邏輯寄存器都是可尋址的。

FMA指令集,我們假設存在可以計算融合多添加指令(FMA)的單元。每個FMA指令計算一個乘法和一個加法。每個單元可以在每個周期(即但是每條FMA指令都有周期的延遲。這意味著周期必須通過,因為FMA指令發出后才能發出后續依賴的FMA指令。

加載/存儲體系結構。我們假設該體系結構是一個加載/存儲體系結構,在對加載的數據執行操作之前,必須將數據加載到寄存器中。在具有直接從內存計算指令的體系結構上,我們假定這些指令沒有使用。

循環飽和計算

當所有單元在每個周期中計算一個FMA時,我們的模型體系結構上的最大性能將得到滿足。但是,由于每個FMA指令都有周期的延遲,這意味著至少必須有獨立于的FMA指令被發送到每個計算單元。由于每個FMA指令都可以計算輸出元素,這意味著:

其中是為了達到最大可達到的性能,每個循環中必須計算的獨立輸出元素的最小數量。


圖2。5×5輸入圖像與三種不同渠道(用不同的顏色表示)與兩個獨立的內核卷積得到一個3×3和兩個輸出通道輸出。為了利用高性能的矩陣乘法例程,將三維輸入圖像(左)轉換為二維矩陣(右)。由于As Co and/or (Ho× Wo) are often less than Hf × Wf × Ci,在許多BLAS庫中,標準矩陣-矩陣乘法的性能通常不是最優的


在確定在每個周期中必須計算至少個輸出元素之后,下一步是確定這些輸出元素在卷積層的總體輸出內的布置。注意,輸出具有三維,其中主要是輸入大小的函數,而是卷積層的設計參數。由于必須是的倍數,即2的冪,并且可以選擇(在實踐中也是這種情況)為2的冪,所以j環被選擇為最里面的環。

由于最小數高度依賴于FMA計算單元的數量和能力,我們希望確保有足夠的輸出元素來完全飽和計算。這樣,對輸出圖像的同一行中的元素進行迭代的k循環被選擇為圍繞j循環2的循環。

循環以優化數據重用

后續循環的順序是盡可能有效地將數據引入計算單元。

回想一下,內部兩個循環(j和k)在多個輸出元素上迭代,以確保能夠執行足夠的獨立FMA操作,以避免計算單元中的停頓。由于我們的模型體系結構是加載/存儲體系結構,這意味著這些輸出元素已經在寄存器中。因此,我們希望引入數據,使我們能夠累積到這些輸出元素中。


回想一下,計算單個輸出元素,所有權重從輸入圖像中乘以適當的元素累積到輸出元素。這自然意味著接下來的三個循環按順序從最里面到最外面依次是i、m、n個循環。這個循環的順序是根據大多數卷積層的輸入是另一個卷積層的輸出來決定的。這意味著,如果以相同的順序訪問來自輸入和輸出的數據,將是可取的。因此,我們希望在行(n)之前訪問通道(i)中的輸入元素,這就給出了循環的i、n、m順序。在最初的6個循環中決定了5個,這意味著最外層的循環必須是l循環。這個循環通過輸出的不同行遍歷其余行。原循環順序如算法1 (i, j, k, l, m, n)所示,轉換為(l, n, m, i, k, j)循環順序如算法2所示。

內存層次結構塊

寄存器阻塞。聰明的讀者將認識到,我們已經方便地忽略了這樣一個事實,即是維持峰值性能所需的最小輸出元素的數量,它由寄存器數量上限,如以下不等式所述:

???????????????????????????????????????(2)

可用寄存器的數量強加的這個上限意味著最多NregNvec元素可以保存在寄存器中。這意味著,不是對所有元素進行迭代,而是必須將塊大小為和的循環阻塞/平鋪(Wolfe,1989)應用于兩個最內部的循環,以避免會降低性能的寄存器溢出。

對原始j和k循環應用循環阻塞將每個輸出通道中的一行分解為更小的輸出圖像,每個輸出圖像分別具有行寬度和和的輸出通道。由于循環阻塞將整個卷積分解為較小的卷積,因此前面描述的循環排序仍然適用。然而,我們現在需要確定如何在較小的卷積上遍歷。

循環j0和k0分別對輸出的通道維度和行維度中的塊進行迭代。此外,循環JJ和KK與相應的通道和行塊迭代。我們對訪問同一行中的輸入元素的觀察將要求我們還訪問同一行中的內核權重。這表明循環的排序應該類似于遍歷內核權重的循環。這樣,K0循環嵌套在l和n循環之間。j0循環被設置為最外面的循環,因為它是促進并行化的并行循環。


緩存塊。在具有內存層次結構中更多級別的架構(即具有緩存的架構)上,我們可以進一步將輸入數據集劃分成更小的分區,以便它們適合于緩存的適當級別。回想一下,圍繞jj和kk的循環將中間結果累積到寄存器中存儲的輸出中。由于和,即內核權重的大小,通常小于,因此我們選擇對i循環進行分區,該i循環在輸入通道上迭代,用于內存層次結構中的下一級。

高性能直接卷積的最終算法如算法3所示。


并行性

為了識別可能的并行算法,我們首先觀察到所有輸出元素都可以并行計算。由于輸出是一個三維對象,這意味著并行性,可以提煉出至少三個不同的維度。

我們的直接卷積實現提取了輸出通道維的并行性。每個線程分配一塊來計算輸出元素,其中每個塊輸出元素的大小,是使用線程的數量.

卷積計算友好的數據布局

我們為輸入數據和內核數據提出了新的數據布局,以便盡可能以單位步幅訪問數據。這改進了數據訪問,并避免了從較低內存層次結構訪問數據時出現代價高昂的停頓。修改布局的一個關鍵條件是輸出圖像和輸入圖像應該具有相同的數據布局。是因為大多數卷積層的輸入是另一個卷積層的輸出。保持它們在相同的數據布局將避免卷積層之間代價高昂的數據重塑。但是,為了保證與原始輸入圖像的兼容性,我們沒有將所提出的布局強加于第一個卷積層的輸入。

4.1輸入/輸出布局

我們希望以單元跨度訪問輸出數據。因此,我們通過考慮如何使用算法3中所示的循環順序訪問元素來確定輸出數據布局。在內部循環中訪問的數據應該比在外部循環中訪問的數據更緊密地排列在內存中。五個循環在輸出數據上迭代,這意味著一個五維的數據布局。然而,如果我們要將其用于輸入數據,這就不是最優的。這是因為輸入行中的元素需要計算一個輸出元素。在五維布局中,輸入的一行被分成元素的塊。這意味著,需要來自兩個獨立的塊的輸入元素的輸出元素將會產生很大的損失,因為這些輸入元素在內存中間隔了很大的距離。因此,我們不根據kk循環布局數據。建議的輸入/輸出布局如圖3(左)所示。輸出數據被組織成的順序塊,在每個塊中,首先在通道尺寸中布置元素,然后被組織成長度為的鉛筆的行-主序矩陣。

4.2.內核配置

類似于輸入/輸出布局,我們使用循環排序來確定如何將內核權重排序到順序存儲器中。注意,算法3中的循環在單個輸出通道中迭代輸出的高度和寬度。由于同一輸出通道中的所有輸出元素共享相同的內核權重,因此這些循環不提供關于應該如何存儲內核權重的信息。因此,我們只考慮剩下的六個循環。

剩余的六個循環所提出的內核布局如圖3(右)所示。內核布局中最快的尺寸是塊的輸出通道尺寸,并且由最里面的循環指定。從最快到最慢的其余維度是塊輸入通道(),接著是內核的列和行、輸入通道?以及最后是輸出通道。

4.3.向后兼容

鑒于卷積神經網絡(CNN)在現場的成功部署,所提出的數據布局的改變將意味著訓練好的網絡不能直接從我們提出的直接卷積實現中受益。然而,為了使訓練后的網絡使用我們提出的算法,將核權重重新排列到建議的數據布局中只需要一次的成本.其他網絡層,如skip layers (He等人,2015)和激活層是點式操作,在實現中不需要任何重大改變。然而,重新排序用于計算這些層的循環將可能產生更好的性能。

結果

在本節中,我們將針對各種體系結構上的現有卷積方法展示直接CNN實現的性能結果。選擇傳統的CPU體系結構(Intel和AMD)和在嵌入式設備上發現的嵌入式處理器(ARM)的混合物。

實驗裝置

平臺我們在Intel Core i7-4770K、AMD FX(tm)-8350、ARM Cortex-A57架構上進行了實驗。這些平臺的架構細節列于表中。


軟件。我們使用HPC社區的技術來實現我們的直接卷積(Velas等人,2016)。我們將直接卷積實現的性能與鏈接到高性能BLAS庫的基于矩陣乘法的卷積的性能進行比較。對于基于矩陣乘法的卷積,首先使用Caffe的im2col例程將輸入數據打包到適當的矩陣中,然后調用高性能的單精度矩陣乘法(SGEMM)例程。所使用的SGEMM例程依賴于體系結構。關于Intel架構,我們鏈接到Intel的數學內核庫(MKL)(Intel,2015),而OpenBLAS(OpenBLAS)用于其他兩個架構。我們還提供了與NNPACK(Dukhan)提供的基于FFT的卷積實現的比較,NNPACK(Dukhan)是一個軟件庫,它支持Caffe 2(caffe2)中基于FFT的卷積。由于NNPACK提供了多個基于FFT(包括Winograd)的實現,因此我們只報告最佳(最快)實現所獲得的性能。我們使用NNPACK提供的基準程序來執行我們的測試.

基準。所有實現都是針對AlexNet(Krizhevsky等人,2012)、GoogLeNet(Szegedy等人,2015)和VGG(Simonyan & Zisserman,2014)中所有的卷積層運行的。這三個CNN中的不同卷積層跨越輸入、輸出和核權重的大小范圍。它們還通常用作演示卷積實現的性能的基準。

Performance

標準化為SGEMM+打包方法的不同實現的相對性能如圖4所示。我們的直接卷積實現在所有架構上都比所有基于SGEMM的卷積執行至少10%和400%。即使BLAS庫(MKL)對卷積產生的適當矩陣形狀進行了優化,我們的直接卷積的性能也優于SGEMM。相對于只對HPC矩陣進行優化的BLAS庫(OpenBLAS),我們看到在4個線程上的性能增益至少為1.5倍。

與NNPack提供的基于FFT的實現相比,直接卷積實現在ARM上的所有層上都明顯優于基于FFT的實現。由于FFT是內存帶寬受限的,我們懷疑FFT可能是較小體系結構(如ARM)的瓶頸,其中可用帶寬可能受到限制。在Intel架構上,結果類似于直接卷積優于基于FFT的實現。然而,在這種情況下,只有當數據集“足夠大”以攤銷執行FFT本身的成本時,基于FFT的實現才能超過基于SGEMM的方法。NNPACK不支持AMD體系結構。


圖3。輸入/輸出(左)和內核權重(右)的卷積友好布局。輸出數據被組織成的順序塊,在每個塊中,最快的維數是通道維數,其次是輸出的列和行維數。將核權組織成塊,最快維數是塊輸出通道,接著是被塊的輸入通道、內核的寬度和高度、輸入通道和輸出通道。

并行性能

在圖5中,我們通過將實現與越來越多的線程并行化來比較卷積性能的可伸縮性。

在所有體系結構上,我們報告標準化為在一個線程上獲得的性能的多線程實現的每核性能。注意,現有基于矩陣乘法的卷積的每個核的性能隨著線程數量的增加而顯著降低。這表明,隨著線程數量的增加,現有基于矩陣乘法的實現對處理器的利用效率降低。我們的直接CNN實現表明,隨著線程數量的增加,每個核的性能下降最小。

只有當線程的數量是物理內核數量的兩倍時,我們實現的每個內核的性能才會顯著下降。這是預期和重要的,因為它表明我們的實現有效地利用了計算單元,并且增加了線程的數量,超過了物理計算單元的數量,從而造成了對計算資源的過度爭用,從而導致每個芯片性能急劇下降.

6 .結論

本文證明了直接卷積是一種在計算卷積層時被忽略的計算技術,它與現有的卷積層計算技術具有競爭力。我們證明了一個高性能的直接卷積實現不僅消除了所有額外的內存開銷,而且獲得了比專家實現的基于矩陣乘法的卷積更高的性能。我們還表明,我們的實現規模更大的處理器數量我們的實現利用了具有最高并行性的內核維度,因此性能不會降低。相比之下,當前基于矩陣乘法的高性能實現不能很好地擴展到更大數量的處理器。

我們的直接卷積實現目前達到了Intel、AMD和ARM體系結構理論峰值的87.5%、58.2%和88.9%,而HPC矩陣上的SGEMM達到相同體系結構89%、54%和92%的峰值。雖然我們已經表明我們的直接卷積實現是有競爭力的(在峰值SGEMM性能的3%以內),但我們相信通過采取自動調優(Bilmes等人,1997;Whaley & .arra,1998)或用于識別不同回路的塊參數的分析方法(Yotov等人,2005;Low等人,2016)。這些方法還允許探索并行性的不同組合,以確定合適的并行策略。這是我們在不久的將來要追求的目標。

這項工作產生的另一個可能的方向是使用類似的設計技術來優化反向過程,從而在圖像和內核中進行更新。考慮到前向和后向過程的相似性,我們認為只需要對循環排序進行少量更改。

最后,我們相信我們的直接卷積算法可以移植到GPU。我們提議的數據布局類似于StridedBatchedGemm操作所需的布局(Shi等人,2016)。由于這種操作和數據布局目前由使用cuBLAS 8.0(Nvidia,2017)的Nvidia GPU支持,因此這支持了我們的信念,即我們的算法可以很容易地移植到GPU。


圖4。針對現有基于FFT和基于SGEMM的高性能卷積實現的直接卷積的性能。所有實現的性能歸一化到SGEMM+IM2COL例程的性能。直接卷積是很高的與所有其他實現相比,即使在對卷積層產生的矩陣形狀進行優化的BLAS庫(Intel MKL)的情況下,性能也提高了10%到400%。


圖5。縮放行為隨著線程數量的增加。當我們將線程數量從1增加到可用核的數量時,我們的直接卷積實現保持了每核的高GFLOP。這是一個有效的并行化算法的指示器。當線程數量超過內核數量時,過多的爭用會導致每個內核的性能顯著下降。相反,即使在線程數較低(例如2)時,SGEMM仍具有較差的可擴展性。

確認

這項工作是由NSF通過獎勵1116802和DARPA根據協議HRUN111-13-2-007贊助的。本文件的內容、觀點和結論不一定反映NSF或DARPA的立場或政策。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容