基于PYNQ-Z2实现BNN硬件加速
用HLS工具在PYNQ-Z2開發(fā)板上實現(xiàn)BNN(二值神經(jīng)網(wǎng)絡)硬件加速——畢設小結
本文主要是本人本科畢業(yè)設計的主要工作。
主要工作有兩部分,一是使用Vivado HLS工具實現(xiàn)二值卷積神經(jīng)網(wǎng)絡模型并完成硬件加速工作,二是將二值神經(jīng)網(wǎng)絡的前向計算過程部署到PYNQ-Z2板上,并在Jupyter Notebook上實現(xiàn)IP核的調用。
BNN參考論文《Binarized Neural Networks Training Neural Networks with Weights and Activations Constrainedto +1 or ?1》、《FINN A Framework for Fast, Scalable Binarized Neural Network Inference》。因為畢設要求實現(xiàn)云圖像分類的功能,所以訓練集由灰度云圖組成,格式與mnist數(shù)據(jù)集相同。訓練采用深度學習框架theano,導出訓練好的參數(shù),然后在Vivado HLS上實現(xiàn)BNN前向計算的加速過程。
BNN由卷積層、池化層和全連接層組成,主要問題其實只有一個:如何加速卷積?(全連接層主要是乘累加運算,此處可參考卷積層的加速)
卷積加速
卷積的加速主要分為4個層面:位寬加速、算法加速、HLS優(yōu)化指令加速、訪存加速。
位寬加速
位寬加速其實就是用數(shù)據(jù)精度換取計算速度,這也是二值神經(jīng)網(wǎng)絡參數(shù)二值化的主要作用,參數(shù)二值化后大大降低了參數(shù)量。參數(shù)二值化是指我們在訓練網(wǎng)絡的時候將前向計算的權重進行二值化處理,但反向傳播過程中會出現(xiàn)梯度消失的問題(sign函數(shù)的導數(shù)幾乎處處為0),所以反向傳播時會進行松弛化處理,將符號函數(shù)Sign變?yōu)榭蓪Ш瘮?shù)Htanh,并更新全精度的權重,這里的相關內(nèi)容可以參考XNOR-NET的論文或者相關文獻。主要過程如下圖所示:
算法加速
- 乘加優(yōu)化
算法方面的加速其實就是充分使用二值神經(jīng)網(wǎng)絡的特點進行運算符優(yōu)化,因為前面我們已經(jīng)將參數(shù)二值化,所以在進行卷積操作的時候可以利用同或操作和計數(shù)器代替乘加運算,即使用XNOR和PopCount實現(xiàn)乘加運算,具體可以參考XNOR-Net。
以A=[1,-1,1,1,-1]和W=[-1,1,1,-1,-1]兩個向量進行內(nèi)積運算為例:
正常的乘法運算為1×(-1)+(-1)×1+1×1+1×(-1)+(-1)×(-1)= -1;
從同或運算的角度來看,A=[1,0,1,1,0],W=[0,1,1,0,0]
A 與W 進行異或的結果為A^W=[1,1,0,1,0](HLS 中不存在同或操作,需對異或取反進行同或操作)
PopCount 的作用是計算1的個數(shù)來對二進制的乘積進行求和。所以PopCount(A^W)= 3,即結果中有3個-1;所以最終二進制的乘積的結果為(5-PopCount)×1+PopCount×(-1)= 5-2×PopCount= -1.
偽代碼如下,其中F 為卷積窗口大小,window_result 為當前卷積窗口的計算結果,weight_buff 為卷積核參數(shù),bit_num 為卷積窗口內(nèi)數(shù)據(jù)的總位數(shù)。
- 池化優(yōu)化
普通的最大值池化就是對滑動窗口內(nèi)的數(shù)據(jù)進行比較,將其中最大的數(shù)據(jù)作為該滑動窗口的結果。在BNN計算過程中,最大值池化后還要對輸出結果再次進行二值化操作
因為滑動窗口內(nèi)任意一個值滿足大于s 的條件都可以使當前滑動窗口的輸出為1,即最大池化操作與計算順序沒有關系,因此二值神經(jīng)網(wǎng)絡的最大值池化操作可以簡化為或運算
訪存加速
引入緩存,將緩存置于訪存速度更快的內(nèi)存塊中,從而加速整個卷積層的計算速度。同時相鄰的卷積窗口的數(shù)據(jù)重復率較高,無需讀取大量重復使用的數(shù)據(jù)。
本文使用了行緩存器和窗緩存器實現(xiàn)了卷積窗口的流水操作,下圖為窗口緩存結構示意圖:
參數(shù)更新過程如下:
偽代碼如下:
HLS優(yōu)化指令加速
本文中主要用到的HLS的優(yōu)化指令主要包括以下三個方面:(詳細過程可參考Xilinx官方文檔UG902)
- 循環(huán)展開
循環(huán)展開是指將一個循環(huán)函數(shù)分為多個獨立操作,對應的優(yōu)化指令為#pragma HLS UNROLL。一般來說,對內(nèi)層循環(huán)采用循環(huán)展開優(yōu)化較合適,若對外層循環(huán)進行循環(huán)展開的話,會顯著提高資源的使用率。
- 流水優(yōu)化
在HLS 中,循環(huán)結構默認是折疊的,即只使用一組相同的硬件資源進行計算。流水線操作可以改善啟動間隔與時延,對應的優(yōu)化指令為#pragma HLS PIPELINE。
上圖所示的函數(shù),每三個時鐘周期讀取一個輸入,兩個時鐘周期后輸出一個值。使用Pipeline 優(yōu)化指令后,每個時鐘周期都可以讀取一個新的輸入,但輸出的延遲不變。 - 數(shù)組分割
在進行上述優(yōu)化后仍存在部分問題—讀寫操作的瓶頸問題。之前所示的循環(huán)展開中,對每個數(shù)組而言,每個時鐘周期需要執(zhí)行3個讀操作或3個寫操作,但是一個BRAM 最多只有兩個端口,即一個時鐘周期內(nèi)最多執(zhí)行兩個讀或寫操作。
數(shù)組分割是通過將一個塊RAM 資源分割成多個較小的陣列,從而提高帶寬,有效增加端口的數(shù)量,提高讀/寫密集型算法的吞吐量。
改進后的Resource Viewer如下,此時不存在讀寫瓶頸。
實驗結果
硬件系統(tǒng)模塊的Block Design:
Jupyter Notebook結果:
PYNQ-Z2板硬件加速效果:
| CPU | 100 | 8032.8 |
| FPGA | 100 | 2.2 |
小結
論文前期用了一段時間學習HDL,用Verilog語言搭建了一些小模塊熟悉硬件搭建流程,熟悉PYNQ-Z2開發(fā)板的開發(fā)流程。后來參考BNN-PYNQ在PYNQ-Z2板上跑通了BNN的例程,參考HLS-BNN學習BNN各模塊在HLS的搭建及加速過程,實現(xiàn)BNN各模塊的加速。
同時,畢設選擇硬件開發(fā)時,可參考的中文資料較少,靠譜的英文文獻有UG871(官方提供的HLS例程,建議跟著步驟都做一遍)以及UG902(當工具書查詢)
論文中提及的工作占時不是很多 ,主要時間都在熟悉HDL、HLS開發(fā)工具以及PYNQ-Z2的開發(fā)流程,期間也遇到了很多問題,比如如何定義接口類型、如何調用板子以及如何在Jupyter Notebook進行數(shù)據(jù)格式轉換等。
完成大部分畢設工作已是立夏,回顧大學四年,我努力著,付出著。
在此十分感謝女友,同我交流感受,為我加油打氣;
非常感謝我的家人,替我燒水煮飯,喚我添衣保暖;
也很感謝大學摯友,與我交流思路,攜我共同進步。
參考資料
PYNQ-Z2板卡簡介與資源整理
Xilinx/BNN-PYNQ
板卡鏡像下載地址
PYNQ官方Getting Started
PYNQ官方例程—熟悉PYNQ的開發(fā)流程
PYNQ入門中文資料
HLS生成IP進行硬件加速
FPGA并行編程
BitCount函數(shù)解釋
BNN-PYNQ安裝
模仿mnist制作數(shù)據(jù)集
FINN_Documentation
吳恩達深度學習課程第四課 — 卷積神經(jīng)網(wǎng)絡
HLS入門視頻
正點原子ZYNQ系列
[2020.8.27更新,添加BNN的HLS和Vivado工程復現(xiàn)教程]
BNN工程復現(xiàn)教程
[2020.11.26更新,更新Block Design框圖]
總結
以上是生活随笔為你收集整理的基于PYNQ-Z2实现BNN硬件加速的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 填问卷,得《2015中国呼叫中心知识库现
- 下一篇: “.公司”域名注册总量TOP15:新网问