到上一篇為止,我們已經完成了卷積層、全連接層、池化層、激活函數ReLU的所有C的編程實現。在本文中,我們將結合這些層來創建一個完整的推理函數。
模型實現
下面是在第 2 篇文章中創建的推理模型的圖表。
首先輸入一張1x28x28的圖片,然后兩次通過Conv2d -> ReLU -> MaxPool2d提取特征,最后轉為linear,> ReLU -> Linear為10階向量值。
用C寫的時候,只需按如下依次逐層處理即可。
voidconv2d(constfloat*x,constfloat*weight,constfloat*bias,int32_twidth,int32_theight, int32_tin_channels,int32_tout_channels,int32_tksize,float*y){ for(int32_toch=0;och=height||pw0?||?pw?>=width){ continue; } int64_tpix_idx=(ich*height+ph)*width+pw; int64_tweight_idx=((och*in_channels+ich)*ksize+kh)*ksize+kw; sum+=x[pix_idx]*weight[weight_idx]; } } } //addbias sum+=bias[och]; y[(och*height+h)*width+w]=sum; } } } }
函數內部的緩沖區 (x1-x8) 用于連接各層之間的特征數據。
在HLS中,在哪里定義這個buffer很重要,如果像這次一樣把它放在函數中,就可以指定使用FPGA中的RAM(或寄存器)。
另一方面,如果將此緩沖區作為函數的參數提供,則可以將數據連接到外部 DRAM。這個區域需要根據應用來設計,但是這次內部SRAM已經夠用了,所以定義在函數內部。
如果像以前一樣編寫接口規范,將如下所示:
輸入
x: 輸入圖像。shape=(1, 28, 28)
weight0:第一個卷積層的權重。shape=(4, 1, 3, 3)
bias0:第一個卷積層的偏差。shape=(4)
weight1:第二個卷積層的權重。shape=(8, 4, 3, 3)
bias1:第二個卷積層的偏差。shape=(8)
weight2:第一個全連接層的權重。shape=(32, 8 * 7 * 7)
bias2:第一個全連接層的偏差。shape=(32)
weight3:第二個全連接層的權重。shape=(10, 32)
bias3:第二個全連接層的偏差。shape=(10)
輸出
y:輸出向量。shape=(10)
界面設置
在目前創建的函數中,我們還沒有具體定義創建電路的接口。未指定接口時,HLS 會為簡單 SRAM 生成一個接口。
該接口不能用于訪問DRAM等訪問時間不確定的接口,不方便在真機上操作。為此,我們告訴HLS使用一種稱為AMBA AXI4接口協議(以下簡稱AXI)的協議,該協議主要用于Xilinx FPGA上IP之間的接口。
Xilinx IP主要使用以下三種協議。
AXI4:高速內存訪問協議(主要用途:訪問DRAM、PCIe等)
AXI4-Lite:AXI4的一個子集,一種用于低速內存訪問的協議(主要用途:IP寄存器控制)
AXI4-Stream:僅用于單向數據傳輸的協議,無地址(主要用途:流數據處理)
這次我們將使用 AXI4 訪問輸入/輸出數據,使用 AXI4-Lite 控制 IP。
具有接口定義的推理函數如下所示:
voidinference_top(constfloatx[kMaxSize], constfloatweight0[kMaxSize],constfloatbias0[kMaxSize], constfloatweight1[kMaxSize],constfloatbias1[kMaxSize], constfloatweight2[kMaxSize],constfloatbias2[kMaxSize], constfloatweight3[kMaxSize],constfloatbias3[kMaxSize], floaty[kMaxSize]){ #pragmaHLSinterfacem_axiport=xoffset=slavebundle=gmem0 #pragmaHLSinterfacem_axiport=weight0offset=slavebundle=gmem1 #pragmaHLSinterfacem_axiport=weight1offset=slavebundle=gmem2 #pragmaHLSinterfacem_axiport=weight2offset=slavebundle=gmem3 #pragmaHLSinterfacem_axiport=weight3offset=slavebundle=gmem4 #pragmaHLSinterfacem_axiport=bias0offset=slavebundle=gmem5 #pragmaHLSinterfacem_axiport=bias1offset=slavebundle=gmem6 #pragmaHLSinterfacem_axiport=bias2offset=slavebundle=gmem7 #pragmaHLSinterfacem_axiport=bias3offset=slavebundle=gmem8 #pragmaHLSinterfacem_axiport=yoffset=slavebundle=gmem9 #pragmaHLSinterfaces_axiliteport=xbundle=control #pragmaHLSinterfaces_axiliteport=weight0bundle=control #pragmaHLSinterfaces_axiliteport=weight1bundle=control #pragmaHLSinterfaces_axiliteport=weight2bundle=control #pragmaHLSinterfaces_axiliteport=weight3bundle=control #pragmaHLSinterfaces_axiliteport=bias0bundle=control #pragmaHLSinterfaces_axiliteport=bias1bundle=control #pragmaHLSinterfaces_axiliteport=bias2bundle=control #pragmaHLSinterfaces_axiliteport=bias3bundle=control #pragmaHLSinterfaces_axiliteport=ybundle=control #pragmaHLSinterfaces_axiliteport=returnbundle=control dnnk::inference(x, weight0,bias0, weight1,bias1, weight2,bias2, weight3,bias3, y); }
dnnk::inference函數就是前面提到的推理函數,這個函數將dnnk::inference“包起來”了。
和上一篇文章一樣,top函數的接口是一個數組,而不是一個指針。在仿真 HLS 時,此符號對于指定仿真器保留的內存緩沖區的大小是必需的,但它并不是很重要。
第 30-50 行 #pragma HLS interfaceport=<參數名稱>bundle=<要分配的接口名稱> 使用語法為每個函數參數指定接口協議,使用的協議有兩個,m_axi和s_axilite,其中m_/s_部分表示請求是發送還是接收(AXI術語中的master/slave),后面的部分就是前面提到的協議部分增加。
在此函數中,每個數據端口都成為 AXI4 主端口并主動從 DRAM (L30-39) 中獲取數據。此時主機CPU等訪問的存儲器地址可以通過AXI4-Lite從端口(L40-49)進行設置。
最后,用于開始處理的控制寄存器和用于檢查處理完成的狀態寄存器port=return鏈接到 AXI4-Lite 從端口 (L50)。
綜合/結果確認
界面
將這個電路作為IP輸出,放到Vivado的IP Integrator中,如下圖。每個端口的名稱對應于上面的interface pragma bundle位置。
熟悉 Vivado 開發的都知道,剩下要做的就是適當地連接端口,將能夠創建能夠進行推理處理的 FPGA 圖像。
綜合
綜合時的表現如下:執行時間最短 1.775 ms,最長 7.132 ms。
在這里,我想知道為什么輸入圖像大小是固定的,但執行時間不固定,這是因為第三篇文章中創建的卷積函數continue包括補零處理。
由于這個補零過程只在屏幕邊緣進行,實際執行時間幾乎是最大時間7.132 ms。
for(int32_tkw=0;kw=height||pw0?||?pw?>=width){ continue; } int64_tpix_idx=(ich*height+ph)*width+pw; int64_tweight_idx=((och*in_channels+ich)*ksize+kh)*ksize+kw; sum+=x[pix_idx]*weight[weight_idx]; }
在這里為了可讀性,用continue中止,但是在FPGA上,與在這里中斷循環的處理相比,使用已經安裝的乘法加法器進行0加法運算的成本更少。
資源使用
FPGA的資源利用率如下所示:總體使用量是微不足道的,因為沒有增加并行化和流水線等資源的加速。
審核編輯:劉清
-
DRAM
+關注
關注
40文章
2316瀏覽量
183570 -
寄存器
+關注
關注
31文章
5355瀏覽量
120531 -
SRAM芯片
+關注
關注
0文章
65瀏覽量
12107 -
HLS
+關注
關注
1文章
129瀏覽量
24134
原文標題:總結
文章出處:【微信號:Open_FPGA,微信公眾號:OpenFPGA】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論