內(nèi)存帶寬與計(jì)算能力,誰(shuí)才是決定深度學(xué)習(xí)執(zhí)行性能的關(guān)鍵?
說(shuō)到模型對(duì)于硬件的要求,大家***個(gè)想到的就是計(jì)算量,即一個(gè)深度學(xué)習(xí)模型需要多少次計(jì)算才能完成一次前饋。然而,除了運(yùn)算量之外,模型對(duì)于內(nèi)存帶寬的需求也是影響實(shí)際計(jì)算所需要時(shí)間的重要參數(shù)。我們下面會(huì)看到,在內(nèi)存帶寬有限的情況下,僅僅縮小計(jì)算量并不能讓計(jì)算時(shí)間等比例下降!
內(nèi)存帶寬對(duì)于硬件系統(tǒng)的性能影響如上圖所示。如果把內(nèi)存比做瓶子,運(yùn)算單元比作杯子,那么數(shù)據(jù)就是瓶子里的各色顆粒,而內(nèi)存接口就是瓶口,通過(guò)瓶口數(shù)據(jù)才能進(jìn)入杯子被消費(fèi)(處理)掉。而內(nèi)存帶寬就是瓶口的寬度了。瓶口寬度越窄,則數(shù)據(jù)需要越多時(shí)間才能進(jìn)入杯子(處理單元)。正所謂「巧婦難為無(wú)米之炊」,如果帶寬有限,那么即使處理單元***快,在大多數(shù)時(shí)候也是處理單元在空等數(shù)據(jù),造成了計(jì)算力的浪費(fèi)。
深度學(xué)習(xí)網(wǎng)絡(luò)與 Roofline 模型
對(duì)于工程師來(lái)說(shuō),定性分析并不夠,我們還需要能定量分析算法對(duì)于內(nèi)存帶寬的需求,以及對(duì)于計(jì)算性能的影響。
算法對(duì)于內(nèi)存帶寬的需求通常使用「運(yùn)算強(qiáng)度 (operational intensity,或稱(chēng) arithmetic intensity)」這個(gè)量來(lái)表示,單位是 OPs/byte。這個(gè)量的意思是,在算法中平均每讀入單位數(shù)據(jù),能支持多少次運(yùn)算操作。運(yùn)算強(qiáng)度越大,則表示單位數(shù)據(jù)能支持更多次運(yùn)算,也就是說(shuō)算法對(duì)于內(nèi)存帶寬的要求越低。所以,運(yùn)算強(qiáng)度大是好事!
我們來(lái)舉一個(gè)例子。對(duì)于步長(zhǎng)(stride)為 1 的 3x3 卷積運(yùn)算,假設(shè)輸入數(shù)據(jù)平面大小為 64x64。簡(jiǎn)單起見(jiàn),假設(shè)輸入和輸出 feature 都為 1。這時(shí)候,總共需要進(jìn)行 62x62 次卷積運(yùn)算,每次卷積需要做 3x3=9 次乘加運(yùn)算,所以總共的計(jì)算次數(shù)為 34596,而數(shù)據(jù)量為(假設(shè)數(shù)據(jù)和卷積核都用單精度浮點(diǎn)數(shù) 2byte):64x64x2(輸入數(shù)據(jù))+ 3x3x2(卷積核數(shù)據(jù))= 8210 byte,所以運(yùn)算強(qiáng)度為 34596/8210=4.21。如果我們換成 1x1 卷積,那么總的計(jì)算次數(shù)變成了 64x64=4096,而所需的數(shù)據(jù)量為 64x64x2 + 1x1x2=8194。顯然,切換為 1x1 卷積可以把計(jì)算量降低接近 9 倍,但是運(yùn)算強(qiáng)度也降低為 0.5,即對(duì)于內(nèi)存帶寬的需求也上升了接近 9 倍。因此,如果內(nèi)存帶寬無(wú)法滿(mǎn)足 1x1 卷積計(jì)算,那么切換成 1x1 卷積計(jì)算雖然降低了接近 9 倍計(jì)算量,但是無(wú)法把計(jì)算速度提升 9 倍。
這里,我們可以看到,深度學(xué)習(xí)計(jì)算設(shè)備存在兩個(gè)瓶頸,一個(gè)是處理器計(jì)算能力,另一個(gè)是計(jì)算帶寬。如何分析究竟是哪一個(gè)限制了計(jì)算性能呢?可以使用 Roofline 模型。
典型的 Roofline 曲線(xiàn)模型如上圖所示,坐標(biāo)軸分別是計(jì)算性能(縱軸)和算法的運(yùn)算強(qiáng)度(橫軸)。Roofline 曲線(xiàn)分成了兩部分:左邊的上升區(qū),以及右邊的飽和區(qū)。當(dāng)算法的運(yùn)算強(qiáng)度較小時(shí),曲線(xiàn)處于上升區(qū),即計(jì)算性能實(shí)際被內(nèi)存帶寬所限制,有很多計(jì)算處理單元是閑置的。隨著算法運(yùn)算強(qiáng)度上升,即在相同數(shù)量的數(shù)據(jù)下算法可以完成更多運(yùn)算,于是閑置的運(yùn)算單元越來(lái)越少,這時(shí)候計(jì)算性能就會(huì)上升。然后,隨著運(yùn)算強(qiáng)度越來(lái)越高,閑置的計(jì)算單元越來(lái)越少,***所有計(jì)算單元都被用上了,Roofline 曲線(xiàn)就進(jìn)入了飽和區(qū),此時(shí)運(yùn)算強(qiáng)度再變大也沒(méi)有更多的計(jì)算單元可用了,于是計(jì)算性能不再上升,或者說(shuō)計(jì)算性能遇到了由計(jì)算能力(而非內(nèi)存帶寬)決定的「屋頂」(roof)。拿之前 3x3 和 1x1 卷積的例子來(lái)說(shuō),3x3 卷積可能在 roofline 曲線(xiàn)右邊的飽和區(qū),而 1x1 卷積由于運(yùn)算強(qiáng)度下降,有可能到了 roofline 左邊的上升區(qū),這樣 1x1 卷積在計(jì)算時(shí)的計(jì)算性能就會(huì)下降無(wú)法到達(dá)峰值性能。雖然 1x1 卷積的計(jì)算量下降了接近 9 倍,但是由于計(jì)算性能下降,因此實(shí)際的計(jì)算時(shí)間并不是 3x3 卷積的九分之一。
顯然,一個(gè)計(jì)算系統(tǒng)的內(nèi)存帶寬如果很寬,則算法不需要運(yùn)算強(qiáng)度很大也能輕易碰到計(jì)算能力上限決定的「屋頂」。在下圖中,計(jì)算能力不變,而隨著內(nèi)存帶寬的上升,達(dá)到計(jì)算力屋頂所需的運(yùn)算強(qiáng)度也越低。
Roofline 模型在算法-硬件協(xié)同設(shè)計(jì)中非常有用,可以確定算法和硬件優(yōu)化的方向:到底應(yīng)該增加內(nèi)存帶寬/減小內(nèi)存帶寬需求,還是提升計(jì)算能力/降低計(jì)算量?如果算法在 roofline 曲線(xiàn)的上升區(qū),那么我們應(yīng)該增加內(nèi)存帶寬/減小內(nèi)存帶寬需求,提升計(jì)算能力/降低計(jì)算量對(duì)于這類(lèi)情況并沒(méi)有幫助。反之亦然。
我們來(lái)看一個(gè)實(shí)際的例子,比較一下各種機(jī)器學(xué)習(xí)算法在 roofline 模型上所處的位置。下圖取自 Google 的 TPU 論文《In-Datacenter Performance Analysis of a Tensor Processing Unit》。由圖中可見(jiàn),LSTM 算法的運(yùn)算強(qiáng)度***,所以被卡在了 roofline 模型的上升區(qū)中間的地方,即 TPU 在執(zhí)行 LSTM 算法的時(shí)候,由于內(nèi)存帶寬限制所以性能只有 3TOPS 左右,僅為峰值性能(90TOPS)的三十分之一。經(jīng)典全聯(lián)接神經(jīng)網(wǎng)絡(luò)(multi-layer perceptrons, MLP)的運(yùn)算強(qiáng)度略好于 LSTM,也被卡在 roofline 曲線(xiàn)的上升區(qū),實(shí)際執(zhí)行性能大約在 10TOPS 左右。而卷積神經(jīng)網(wǎng)絡(luò)模型,尤其是 CNN0,由于卷積神經(jīng)網(wǎng)絡(luò)中能實(shí)現(xiàn)卷積核復(fù)用,因此運(yùn)算強(qiáng)度非常高,于是可以非常接近 TPU roofline 曲線(xiàn)的屋頂(86 TOPS)。CNN1 模型雖然運(yùn)算強(qiáng)度也很高,但是由于種種其他原因(論文中表示是由于 CNN1 模型的特征深度較淺無(wú)法完全利用 TPU 的計(jì)算單元)無(wú)法到達(dá)屋頂。這個(gè)例子又讓我們看到了硬件-算法協(xié)同設(shè)計(jì)時(shí)的另一個(gè)要點(diǎn):除了內(nèi)存帶寬之外還有「其他原因」可能讓算法無(wú)法到達(dá)屋頂,我們要盡量減小這些「其他因素」!