引言
神經(jīng)網(wǎng)絡(luò)中涉及到大量的張量運(yùn)算,比如卷積,矩陣乘法,向量點(diǎn)乘,求和等。神經(jīng)網(wǎng)絡(luò)加速器就是針對(duì)張量運(yùn)算來設(shè)計(jì)的。一個(gè)神經(jīng)網(wǎng)絡(luò)加速器通常都包含一個(gè)張量計(jì)算陣列,以及數(shù)據(jù)收發(fā)控制,共同來完成諸如矩陣乘法,卷積等計(jì)算任務(wù)。運(yùn)算靈活多變的特性和硬件的固定架構(gòu)產(chǎn)生了矛盾,這個(gè)矛盾造成了利用硬件執(zhí)行計(jì)算任務(wù)的算法多變性。不同的硬件架構(gòu)實(shí)現(xiàn)相同的計(jì)算,可能具有不同的算法。我們今天討論基于脈動(dòng)陣列的計(jì)算架構(gòu),脈動(dòng)陣列的低延遲,低扇出特性使其得到廣泛應(yīng)用,比如TPU中。我們今天就從矩陣計(jì)算講起,談一談矩陣計(jì)算的幾種不同方式,矩陣的一些特性,再講一講CNN中的卷積運(yùn)算,最后談?wù)勥@些張量計(jì)算在硬件中的實(shí)現(xiàn)形式。
矩陣計(jì)算
假設(shè)有兩個(gè)矩陣:
![](https://file.elecfans.com/web1/M00/C7/D5/o4YBAF9t7taACnCsAAAN3LbQKus151.png)
計(jì)算這兩個(gè)矩陣的乘積
![](https://file.elecfans.com/web1/M00/C7/D5/o4YBAF9t7teAfX4vAAAL-BQuKXU487.png)
根據(jù)矩陣計(jì)算形式,我們可以看出有三級(jí)循環(huán)。根據(jù)排列組合,可以有6種計(jì)算形式。我們使用ijk分別表示A對(duì)應(yīng)的行,列(B的行),以及B的列的標(biāo)號(hào)。這六種循環(huán)計(jì)算方式為:ijk, jik, ikj, jki, kij, kji。這六種方式在硬件上(脈動(dòng)陣列)實(shí)現(xiàn)起來,考慮到緩存和計(jì)算結(jié)構(gòu),實(shí)際上可以分為2種方式。
1) 矩陣x向量
我們用偽代碼表示為:
在這種方式下,通過矩陣x向量的方式可以配合脈動(dòng)陣列的2D結(jié)構(gòu)。這個(gè)時(shí)候片上要先存儲(chǔ)下一個(gè)A矩陣和B矩陣的一列,然后通過一個(gè)周期完成矩陣x向量的計(jì)算,得到了C矩陣的一行。這個(gè)時(shí)候片上A矩陣數(shù)據(jù)可以一直保存不更換,而不斷更換每一列的B數(shù)據(jù),直到完成AB計(jì)算。
這種方式在在語音處理的LSTM等網(wǎng)絡(luò)中比較適用,因?yàn)檎Z音通常都是一些連續(xù)的向量,而且LSTM網(wǎng)絡(luò)決定了連續(xù)的向量之間有依賴關(guān)系,因此矩陣x向量方式可以提高LSTM中權(quán)重的時(shí)間復(fù)用率。所謂時(shí)間復(fù)用率是指權(quán)重可以在片上保持較長(zhǎng)的時(shí)間,而不斷更換輸入。從時(shí)間維度上看,權(quán)重得到了復(fù)用。
這種方式的缺點(diǎn)是權(quán)重加載到片上會(huì)消耗很多時(shí)間,突發(fā)的load需要占據(jù)很大訪問內(nèi)存帶寬。而且對(duì)片上緩存要求容量較高。特別是當(dāng)緩存較小權(quán)重?cái)?shù)量較大的時(shí)候,就要通過不斷加載權(quán)重到片上來滿足計(jì)算需求,這可能會(huì)降低加速器性能。為了滿足計(jì)算的實(shí)時(shí)性,權(quán)重輸出帶寬需要足夠一個(gè)矩陣x向量的計(jì)算。這對(duì)片上帶寬要求也較高。當(dāng)然這些都能夠通過一定手段來緩解,比如通過多batch來增加權(quán)重空間復(fù)用率,降低對(duì)帶寬需求和片上緩存要求。
2) 列向量x行向量
用偽代碼表示如下:
這實(shí)際上是取得A的一個(gè)列向量和B的行向量進(jìn)行矩陣乘法,得到一個(gè)矩陣,所有對(duì)應(yīng)的A的列和B的行乘積的矩陣和就是最終的C矩陣。這種方式利用了A和B的空間復(fù)用率,A的列和B的行的元素彼此求積,也適配了2D的脈動(dòng)陣列結(jié)構(gòu)。
這種方式對(duì)A和B的帶寬需求最低,一般外部DDR的內(nèi)存可以滿足這樣的要求。對(duì)片上緩存需求較低,帶寬也較低。A的列元素和B的行元素分別從脈動(dòng)陣列的左側(cè)和上側(cè)進(jìn)入,相互乘積,達(dá)到了元素最大空間復(fù)用率。這種方式可能會(huì)要求對(duì)某個(gè)矩陣進(jìn)行轉(zhuǎn)置,比如當(dāng)矩陣按行序列排的時(shí)候,B矩陣就需要經(jīng)過轉(zhuǎn)置后送入矩陣運(yùn)算單元進(jìn)行計(jì)算。
但是這種方式也有一定應(yīng)用限制,對(duì)于矩陣x向量的語音識(shí)別來說,只有對(duì)于batch size較大時(shí),效率才會(huì)高,否則會(huì)比較低。而且這種結(jié)構(gòu)不太利于脈動(dòng)陣列在其它方面的應(yīng)用,比如卷積計(jì)算,接下來我們會(huì)講到。
塊矩陣計(jì)算
硬件上計(jì)算陣列通常都是和要進(jìn)行計(jì)算的矩陣大小是不匹配的,一種情況就是計(jì)算陣列維度比矩陣維度小,一種就是大于矩陣的維度。
當(dāng)小于矩陣維度時(shí),可以通過對(duì)矩陣切塊來分別計(jì)算,如果大于矩陣維度,可以對(duì)矩陣進(jìn)行“補(bǔ)塊”。比如硬件上計(jì)算陣列大小是32x32,而A矩陣是64x64,B矩陣是64x64。
如果采用列向量x行向量的方法,我們就可以將A和B分別切分成4個(gè)矩陣快,這些矩陣塊分別進(jìn)行計(jì)算。
先計(jì)算A11xB11(分別將A11按列送入陣列,B11按行輸入陣列,陣列中每個(gè)計(jì)算單元保留結(jié)果繼續(xù)和下一次數(shù)據(jù)求累加和),然后計(jì)算A12xB21(繼續(xù)不斷將矩陣送入計(jì)算陣列,并和上次A11xB11結(jié)果求和),兩者求和就得到了第一個(gè)矩陣塊。
如果采用矩陣x向量的方法,就可以這樣分塊:
我們先在片上緩存下A1矩陣塊,然后分別加載B1矩陣的列和A1進(jìn)行矩陣向量計(jì)算,分別得到了A1B1矩陣的第一列,第二列,…結(jié)果。
矩陣數(shù)據(jù)表示寬度
硬件上進(jìn)行神經(jīng)網(wǎng)絡(luò)加速都采用量化后的數(shù)據(jù),一般將訓(xùn)練的模型定點(diǎn)到16bit,8bit,4bit等對(duì)硬件計(jì)算友好的寬度。因此具有寬bit計(jì)算單元的硬件架構(gòu)可以兼容低bit的神經(jīng)網(wǎng)絡(luò)計(jì)算,但是這樣會(huì)造成計(jì)算資源浪費(fèi)。所以通常有兩個(gè)辦法:一種是針對(duì)不同位寬開發(fā)不同硬件架構(gòu),另外一種是開發(fā)出一種同時(shí)兼容多種bit的架構(gòu)。FPGA可重配置的特點(diǎn),可以在開發(fā)階段考慮多種bit計(jì)算架構(gòu),通過使用參數(shù)化定義來為使用者提供架構(gòu)的可配置選項(xiàng),客戶可以依據(jù)自己需求選擇使用哪種功能。這種方式既滿足了不同bit的計(jì)算需求,同時(shí)又能夠最大化FPGA資源的使用。
如果我們?cè)诘蚥it架構(gòu)的基礎(chǔ)上,增加一些其它模塊,也能夠同時(shí)兼容寬bit計(jì)算任務(wù)。這利用到了數(shù)據(jù)的分解。比如兩個(gè)矩陣A和B分別是8bit,我們要用4bit硬件架構(gòu)加以實(shí)現(xiàn)。將A和B按照4bit進(jìn)行分解:
![](https://file.elecfans.com/web1/M00/C8/4B/pIYBAF9t7uSAIu29AAAh1eIZLY8282.png)
這個(gè)時(shí)候看到存在移位和求和,因此硬件中除了4bit計(jì)算陣列外,還需要有移位模塊,加法模塊,以及數(shù)據(jù)位寬轉(zhuǎn)換模塊。
假設(shè)矩陣乘法模塊輸入位寬4bit,輸出32bit可以滿足一般的矩陣大小的乘法,這輸出的32bit數(shù)據(jù)先通過片上bus緩存到buffer或者給到shift+add模塊,shift+add模塊進(jìn)行移位求和操作,得到的結(jié)果就是正常一個(gè)8bit矩陣乘法的結(jié)果,這個(gè)結(jié)果通常在神經(jīng)網(wǎng)絡(luò)中還會(huì)被進(jìn)一步量化,我們假設(shè)量化到16bit,那么輸出結(jié)果就存放到buffer中。在設(shè)計(jì)片上buffer的時(shí)候,數(shù)據(jù)單位如果是固定的會(huì)使得邏輯簡(jiǎn)單,但是現(xiàn)在存在4種數(shù)據(jù)位寬,所以對(duì)buffer中數(shù)據(jù)的使用就要能靈活處理4bit,8bit,16bit,32bit這樣的大小。這些無疑增加了bufer復(fù)雜度。而且shift+add的結(jié)構(gòu)也會(huì)增加大量的加法和移位邏輯。
矩陣壓縮
神經(jīng)網(wǎng)絡(luò)種含有的參數(shù)很多,大的話都在幾十M甚至上百M(fèi)。為了在FPGA上能容納更多參數(shù),加速計(jì)算任務(wù)。通常有兩種方式來對(duì)權(quán)重進(jìn)行壓縮:一種是對(duì)神經(jīng)網(wǎng)絡(luò)種冗余權(quán)重進(jìn)行剪枝,另外一種是在FPGA上實(shí)現(xiàn)對(duì)參數(shù)壓縮存儲(chǔ)。
剪枝算法有很多,比如針對(duì)LSTM的有權(quán)重矩陣的稀疏化,設(shè)定閾值,去除閾值以下的數(shù)據(jù),然后進(jìn)行fine-tune。這樣得到的矩陣是稀疏矩陣??梢源蟠鬁p少權(quán)重?cái)?shù)量。但是這樣的矩陣結(jié)構(gòu)不太利于硬件進(jìn)行加速,因?yàn)樗慕Y(jié)構(gòu)不夠整齊。
為了得到利于硬件部署的矩陣壓縮結(jié)構(gòu),可以對(duì)權(quán)重進(jìn)行結(jié)構(gòu)化剪枝,即去除一整行或者一整列的數(shù)據(jù),保持權(quán)重整齊的結(jié)構(gòu),有利于硬件上進(jìn)行加速。
Huffman編碼是一種簡(jiǎn)潔無損壓縮的熵編碼,簡(jiǎn)單來講就是通過統(tǒng)計(jì)輸入數(shù)據(jù)的分布概率,然后重新使用字符來表達(dá)原始數(shù)據(jù)。用最少bit的字符來描述出現(xiàn)概率最大的原始數(shù)據(jù),這樣就可以得到一個(gè)最優(yōu)的壓縮比率。編碼可以提前進(jìn)行,F(xiàn)PGA部分主要是完成解碼。Huffman編碼的壓縮率對(duì)于矩陣數(shù)據(jù)壓縮率很高,唯一的問題是解碼邏輯比較大,解碼效率比較低。這也是很少使用的原因。
卷積
CNN網(wǎng)絡(luò)用大量的卷積運(yùn)算來不斷提取圖像特征,使用了LSTM網(wǎng)絡(luò)的語音識(shí)別中也有很多包含了卷積處理。CNN中大部分是2D卷積運(yùn)算,語音識(shí)別中很多是1D卷積。通常在每一層卷積神經(jīng)網(wǎng)絡(luò)中含有多個(gè)輸入通道和輸出通道,本層輸出通道就是下層的輸入通道。每層的輸入通道都有一個(gè)卷積核,這些輸入通道會(huì)在卷積之后求和,得到一個(gè)輸出通道的結(jié)果。
當(dāng)我們采用脈動(dòng)陣列來實(shí)現(xiàn)卷積的時(shí)候,可以有以下幾種方式:
1) 卷積運(yùn)算->稀疏矩陣乘法
我們以一個(gè)1D卷積舉例,假設(shè)有個(gè)卷積核大小為3x1,輸入向量長(zhǎng)度為32。這個(gè)卷積用偽代碼表示為:
我們將卷積核擴(kuò)展為一個(gè)稀疏矩陣,就可以表達(dá)為矩陣向量:
這個(gè)卷積矩陣用圖像更清楚:藍(lán)色是有效數(shù)據(jù),白色是0。用這種方式很簡(jiǎn)單的就可以在脈動(dòng)陣列上進(jìn)行計(jì)算,只需要預(yù)先將卷積轉(zhuǎn)化為矩陣。但是這樣做的缺點(diǎn)就是需要浪費(fèi)很多存儲(chǔ)空間,同時(shí)對(duì)計(jì)算單元的利用率很低,除非卷積核維度比較大,否則如上卷積核和向量的維度比率,利用率只有3/32。
2) 利用輸入輸出通道,將卷積轉(zhuǎn)化為矩陣乘法和求和。
我們假設(shè)1D卷積核為k,輸入輸出通道分別為i和o。則卷積核表示為:K(o,i)
還假設(shè)它是3x1大小。輸入向量是x,假設(shè)它長(zhǎng)度是32,則某個(gè)輸入通道的向量就是:x(i)
我們看出這個(gè)是不是特別像矩陣x向量。如果我們把卷積核分解為三組矩陣,每個(gè)矩陣由卷積核對(duì)應(yīng)某個(gè)元素在i和o方向拓展得到,那么這樣一個(gè)卷積運(yùn)算就可以被我們轉(zhuǎn)化為矩陣x向量+矩陣x向量。假設(shè)這三組卷積核矩陣是K1(o,i),K2(o,i)和K3(o,i)。同時(shí)x按照每個(gè)通道的對(duì)應(yīng)元素展開成一個(gè)輸入通道i的向量,X1(i), X2(i), …X32(i)。那么我們就可以算出輸出結(jié)果是(用第一個(gè)y的結(jié)果舉例):
![](https://file.elecfans.com/web1/M00/C7/D5/o4YBAF9t7veANmTaAAAStxYX4kk390.png)
3) 利用脈動(dòng)陣列結(jié)構(gòu),改動(dòng)控制邏輯,直接進(jìn)行卷積計(jì)算。
這個(gè)時(shí)候需要修改控制邏輯,讓矩陣乘法陣列可以進(jìn)行卷積計(jì)算。其實(shí)還可以在i和o的方向?qū)⒅醋骶仃?,但是每個(gè)計(jì)算單元還存在內(nèi)部循環(huán)讀取卷積核數(shù)據(jù)。
總結(jié)
以上分別總結(jié)了矩陣乘法,卷積運(yùn)算在FPGA加速器上的實(shí)現(xiàn)方式。設(shè)計(jì)一款神經(jīng)網(wǎng)絡(luò)加速器是很多部門的通力合作,算法FPGA編譯器架構(gòu),往往一個(gè)方案對(duì)于某個(gè)部門簡(jiǎn)單,但是令另外一個(gè)部門痛苦。大家在不斷的“拉鋸扯皮”中,一個(gè)方案就出來了。
-
FPGA
+關(guān)注
關(guān)注
1630文章
21803瀏覽量
606489 -
加速器
+關(guān)注
關(guān)注
2文章
809瀏覽量
38134 -
神經(jīng)網(wǎng)絡(luò)
+關(guān)注
關(guān)注
42文章
4785瀏覽量
101250 -
張量
+關(guān)注
關(guān)注
0文章
7瀏覽量
2598
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
人工神經(jīng)網(wǎng)絡(luò)的原理和多種神經(jīng)網(wǎng)絡(luò)架構(gòu)方法
![人工<b class='flag-5'>神經(jīng)網(wǎng)絡(luò)</b>的原理和多種<b class='flag-5'>神經(jīng)網(wǎng)絡(luò)</b>架構(gòu)方法](https://file1.elecfans.com/web3/M00/05/61/wKgZO2d_M_6Ad26pAAAPSvfyTCo490.png)
評(píng)論