背景:着手深度學習的FPGA實現半年以來,實現了部分功能,現在需要移交項目,所以總結項目所有的情況
目錄
一、項目概覽
項目分爲python端,c代碼端,硬件端。
python端用於確定相應的網絡模型結構,訓練模型。
c++端用於實現神經網絡的推斷,也就是隻有前饋的預測運算。
硬件端用於部署相應的網絡結構。
二、python端
2.1 MTCNN與訓練過程
https://github.com/wangbm/MTCNN-Tensorflow
MTCNN是三個級聯的網絡,Pnet用於生成備選框,Rnet用於對備選框初次篩選,Onet用於確定最終輸出的備選框。
所以訓練過程需要訓練三個網絡。
訓練流程見上面連接的內容。
2.2 mAP的測試
mAP爲目標檢測領域的基礎指標。
首先標籤相同交併比IoU>0.5表示網絡檢測正確。
然後畫出相應的查全率與查準率的曲線,積分得到的藍色區域即爲mAP。
各類的平均AP即mAP
測試mAP需要將程序做一定的修改,將所有圖像的預測標籤與groundTruth放入文件夾之中。然後測試。
這一系列過程被封裝好,封裝到test_all.py之中。
2.3 網絡結構的更改
在原始結構的基礎上,
- 重新制作公交人頭數據集,重新訓練以在公交人頭數據集上運行
- 爲了增加硬件平臺的功能(最好確定爲定長度的),將卷積固定爲3x3,
- 去掉pooling的過程,運用stride爲2的卷積來替代以增加並行性。
- 然後將PReLU改爲ReLU,這樣不用存儲斜率。
- 增加一定量的通道數量,以增加mAP
- 在文件mtcnn.py之中
- 更改後的網絡結構表 https://blog.csdn.net/weixin_36474809/article/details/85990687
2.4 輸出python訓練的權重到c代碼端
python權重與c權重順序很不一樣。python之中權重爲四維張量,c代碼之中爲線性存儲的。
python之中的順序
c代碼之中的順序
因爲是線性存儲,所以需要一系列偏移地址找到權重位置:
三、c代碼端
3.1 文件描述
程序文件
- mtcnn.cpp .hpp : Network structure definition of MTCNN 網絡結構的定義
- network.cpp hpp : Basic functions such as conv , relu , padding 基本的函數實現,比如卷積,reLU,padding
- pbox.cpp .hpp : definition of basic data format. 基本的數據結構定義。例如pBox結構體,裏面存了寬,高,通道數和數據指針指向數據。
權重文件
- Pnet.bin , Rnet.bin , Onet.bin total 3.0 MB 三個權重文件3MB,爲了減少FPGA數據流量
- Generated by python 通過前面的python端訓練產生。
- Read by readData function. 通過c文件之中的readData函數讀取。之前c代碼之中權重文件爲.txt格式,我們改爲 .bin格式,數據更緊密。
- readData function difinied in network.cpp, function called in mtcnn.cpp
更改結構順序
c代碼的網絡結構需要與python代碼的結構一致。每次更改網絡結構之後,需要做以下的修改。
- Changing python code network structure。更改python代碼的結構
- Rerun python training code 重新訓練python端的代碼
- Generate weight file. 輸出權重文件
- In mtcnn.hpp , change the structure of class Pnet(Rnet,Onet) private definition. 在mtcnn.hpp程序之中更改類Pnet(Rnet,Onet)的private定義
- In mtcnn.cpp , change class Pnet(Rnet,Onet) construct function and destruct function. 在mtcnn.cpp更改相應的類的構造函數和析構函數
- Change parameters in dataNumber, pointTeam, readData for weight file read.更改與權重讀取相關的三個函數及參量:dataNumber, pointTeam, readData。
- Change Init function for each layer buffer malloc.更改實現相應的層的init函數,init函數用於開闢內存空間。
- Change run function to run each layer. 更改每層的運行函數。
3.2 卷積的更改
初始的依賴openBLAS的卷積函數
openBLAS爲線性代數實現的函數。
卷積的運用滑窗函數實現爲一個二維矩陣,然後與權重排列成的二維矩陣實現矩陣乘。這也是大多數卷積的實現方式。但是這種方法無法實現於FPGA之上。並且每次進行取框函數會加大運算量。
Convolution in 2D matrix multiplication format:
// input Weight matrix * input feature matrix(Trans) = output feature matrix
// height (outChannels) height (3D_KernelSize) height (outChannels)
// width (3D_KernelSize) width (outFeatureSize) width (outFeatureSize)
重新運用定義編寫卷積代碼
我們需要從卷積的定義出發,編寫卷積函數。
Without feature_2_matrix process:
// outpBox [out_ChannelNum][out_height][out_width]
// +=weightIn[out_ChannelNum][in_ChannelNum][kernelWidth][kernelHeight]
// *pboxIn[in_ChannelNum][width][height]
僞代碼如上,這樣,既不用滑窗函數,而且生成的output也可以被下層當作feature直接運用。
定義出發的卷積方便zynqNet改爲FPGA內並行的結構。實現加速。
加入bias和ReLU
卷積後的過程併入卷積函數利用並行化,儘可能多的將任務給FPGA實現。
存儲順序
四、硬件端
4.1 卷積IPcore
卷積IPcore的實現參考zynqNet的結構,在DDR上搬運數據,傳入BRAM上,然後通過並行實現加速。
關於IPcore的實現有很多內容,可以參考之前的博客
•Validated in MTCNN code 嵌入入MTCNN代碼之中驗證
•Validated in HLS test bench (C-simulation) 嵌入HLS的test Bench之中驗證。也就是實現c仿真。
•Validated in synthesis and generate report 通過synthesisi和生成相應的報告
•Export RTL 輸出RTL代碼
•C-RTL co-simulation C與RTL協同仿真。
4.2 IPcore報告
https://blog.csdn.net/weixin_36474809/article/details/85271940
時間資源
zynqNet的時鐘週期如下,基本與卷積IPcore爲同一個數量級。
從MACC的次數考慮
zynqNet的MACC次數固定爲 : 152,731,648,整個網絡運行時間爲2s
MTCNN:
從43,543,288 到85,176,568
按照此時間預測,MTCNN的時間爲:
From 0.57sec – 1.12sec
空間資源
即使佔用的資源比zynqNet少很多,但是MIZ7020平臺上資源超出預期。
在7035平臺上資源夠用。
4.3 ARM端工作
剛開始的MTCNN代碼分開的開闢每層的卷積,對於調用IPcore來講非常耗時。
所以需要更改爲在DDR一次性的開闢所有的內存反覆調用。
五、交接後續需要的工作
模型壓縮,使資源可以在7020平臺上運行