網(wǎng)站收錄了但是搜索不到軟文寫作
03–單格乘加運(yùn)算單元PE & 單窗口卷積塊CU
文章目錄
- 03--單格乘加運(yùn)算單元PE & 單窗口卷積塊CU
- 前言
- 單格乘加運(yùn)算單元PE
- 代碼
- 模塊結(jié)構(gòu)
- 時(shí)序邏輯分析
- 對(duì)其上層模塊CU的要求
- 單窗口卷積塊CU
- 代碼
- 邏輯分析
前言
? 第一和第二篇日志已經(jīng)詳細(xì)闡述了"半精度浮點(diǎn)數(shù)"的加法和乘法模塊了。需要注意,他們的輸入和輸出均是16bit的半精度浮點(diǎn)數(shù)?,F(xiàn)在我們自下而上,向著更頂層進(jìn)發(fā),用floatMult16和floatAdd16模塊搭建基本的卷積運(yùn)算模塊。
? 另外,對(duì)于卷積神經(jīng)網(wǎng)絡(luò)中基本的卷積運(yùn)算方法、卷積核、卷積層結(jié)構(gòu)和參數(shù)等基礎(chǔ)知識(shí)這里不會(huì)贅述,默認(rèn)讀者已經(jīng)掌握。
單格乘加運(yùn)算單元PE
? 在進(jìn)行Image與filter的完整卷積運(yùn)算之前,我們需要更小的模塊去支持這樣的操作。首先最基本的是image的一格與filter的一格進(jìn)行的乘法運(yùn)算。在一個(gè)卷積窗口內(nèi),這樣一次又一次的乘法操作結(jié)束后需要進(jìn)行累加,得到最后的卷積結(jié)果。
代碼
`timescale 100 ns / 10 psmodule processingElement16(clk,reset,floatA,floatB,result);parameter DATA_WIDTH = 16;input clk, reset;
input [DATA_WIDTH-1:0] floatA, floatB;
output reg [DATA_WIDTH-1:0] result;wire [DATA_WIDTH-1:0] multResult;
wire [DATA_WIDTH-1:0] addResult;floatMult16 FM (floatA,floatB,multResult);
floatAdd16 FADD (multResult,result,addResult);always @ (posedge clk or posedge reset) beginif (reset == 1'b1) beginresult = 0;end else beginresult = addResult;end
endendmodule
模塊結(jié)構(gòu)
- floatA和floatB分別是image和filter中的一格數(shù)據(jù),他們輸入到PE里來(lái)進(jìn)行運(yùn)算。
- 實(shí)例化floatMult16和floatAdd16,依"先乘后累加"的邏輯將他們連接起來(lái)。
? 值得注意的是,這里用到了latch的結(jié)構(gòu)進(jìn)行累加,即把輸出addResult作為輸入再次參與加運(yùn)算。
時(shí)序邏輯分析
① 每個(gè)時(shí)鐘周期上升沿到來(lái)時(shí),兩個(gè)16bit數(shù)A和B輸入進(jìn)來(lái)。在很短的時(shí)間里(一個(gè)clk周期內(nèi))Mult模塊計(jì)算出乘積結(jié)果AB,并交付于Add模塊。
② 上一個(gè)時(shí)鐘周期運(yùn)算完的累加結(jié)果addResult輸入到Add模塊,在極短的時(shí)間內(nèi)(一個(gè)clk周期內(nèi))與AB進(jìn)行加運(yùn)算,得到本次的累加結(jié)果sum+AB,交付給后方寄存器result。
③ 在下個(gè)時(shí)鐘上升沿到來(lái)時(shí),result內(nèi)存儲(chǔ)的累加結(jié)果更新為本次的運(yùn)算結(jié)果。同時(shí),result也作為本模塊的輸出。
④ 下一個(gè)時(shí)鐘上升沿到來(lái)…
對(duì)其上層模塊CU的要求
? 每一個(gè)時(shí)鐘周期都必須輸入新的兩個(gè)數(shù)A和B,或者當(dāng)沒有新的卷積任務(wù)時(shí)將輸入口置零。否則將會(huì)一直對(duì)同一格進(jìn)行乘加造作,導(dǎo)致重復(fù)運(yùn)算的錯(cuò)誤。
單窗口卷積塊CU
? CU是PE的上一層,負(fù)責(zé)完成一整個(gè)窗口卷積結(jié)果的輸出。換言之,在每一個(gè)時(shí)鐘上升沿到來(lái)時(shí),CU需要將一個(gè)窗口內(nèi)n*n個(gè)格的數(shù)依次輸入給PE。
? 本工程中使用的filter大小是5*5單通道的,因此一個(gè)窗口的大小也是1*5*5=25格,也就是25*16=400bit。
代碼
`timescale 100 ns / 10 psmodule convUnit(clk,reset,image,filter,result);parameter DATA_WIDTH = 16;
parameter D = 1; //depth of the filter
parameter F = 5; //size of the filterinput clk, reset;
input [0:D*F*F*DATA_WIDTH-1] image, filter;
output [0:DATA_WIDTH-1] result;reg [DATA_WIDTH-1:0] selectedInput1, selectedInput2;integer i;processingElement16 PE(.clk(clk),.reset(reset),.floatA(selectedInput1),.floatB(selectedInput2),.result(result));// The convolution is calculated in a sequential process to save hardware
// The result of the element wise matrix multiplication is finished after (F*F+2) cycles (2 cycles to reset the processing element and F*F cycles to accumulate the result of the F*F multiplications)
always @ (posedge clk, posedge reset) beginif (reset == 1'b1) begin // reseti = 0;selectedInput1 = 0;selectedInput2 = 0;end else if (i > D*F*F-1) begin selectedInput1 = 0;selectedInput2 = 0;end else beginselectedInput1 = image[DATA_WIDTH*i+:DATA_WIDTH];selectedInput2 = filter[DATA_WIDTH*i+:DATA_WIDTH];i = i + 1;end
endendmodule
重要變量說(shuō)明:
- selectedInput1和 selectedInput2:在遍歷時(shí),分別存儲(chǔ)image和filter的一格,輸入到PE。
- i :索引變量。
邏輯分析
? 其實(shí)邏輯非常清晰易懂:
- 每個(gè)時(shí)鐘上升沿,選擇從DATA_WIDTH*i位置開始,往低位DATA_WIDTH位的數(shù)據(jù)(即一格16bit數(shù)據(jù))。image的一格交給input1,filter的一格交給input2。
- 當(dāng)一個(gè)窗口全都交付運(yùn)算(i > D*F*F-1)時(shí),A與B均輸入16bit的0,防止重復(fù)運(yùn)算最后一格的數(shù)據(jù)。
- 此模塊的reset受其上層模塊convLayerSingle控制。每完成一個(gè)窗口的卷積操作,中頓2個(gè)時(shí)鐘周期,隨后進(jìn)行復(fù)位,重新開始新的卷積任務(wù)。
(圖片和卷積核本是二維數(shù)據(jù)矩陣,但經(jīng)過(guò)了RFselector后被展平為一維數(shù)據(jù),可以通過(guò)單變量索引拿取)
開源項(xiàng)目github-URL:CNN-FPGA