# FINN: A Framework for Fast, Scalable Binarized Neural Network Inference # Abstract 提出FINN,一種flexible, heterogeneous and streaming 的專門實現BNN 的框架 在功率低於25w 的FPGA(ZC706) 上實現,並有以下貢獻 1. MNIST上實現每秒1230萬次的圖像分類 2. Latency : 0.31 us 3. Acc. : MNIST(95.8%), CIFAR-10(80.1%), SVHN(94.9%) # Introduction 1. 使用 "roofline model" 此指標量化BNN 的峰值性能 2. 提出的FINN 為有效將BNN映射到FPGA,並優化此過程 3. 允許使用者自訂 Throughput # NN in Hardware 大致將硬體上的NN 架構分為以下4類 1. **single processing engine :** 代表性架構即systolic array,依次處理每一個模型層 2. **streaming architecture :** 每個模型層皆配置一個processing engine 3. **vector processor :** 用於加速convolution操作的指令,即Vector Thread類型的指令 4. **neurosynaptic processor :** 實現神經元連接的模式,突觸陣列(完全沒研究過) 本文提出的FINN 架構為type 2 # BNN Performance Analysis 利用roofline 指標,考慮了 1. memory bandwidth 2. peak computational performance 3. off-chip memory read and write(in order to complete NN operations) 以下圖表比較了在Xilinx Zynq UltraScale+ ZU19EG FPGA 上 不同bit ops的roofline ![](https://i.imgur.com/fM6sytP.png) 另外BNN 因為參數的總容量小,整個model 可以保存在on-chip buffer 上, 因此BNN 能達到計算峰值。 # Acc. Trade-Off 本文也對BNN 常被詬病的低精度進行討論,結論如下: 1. 隨著模型規模增加,BNN 與float model 的acc 差異漸漸縮小 2. 為了達到相同的acc.,BNN 的建議參數量與操作量約需要float model 的**2~11倍** ![](https://i.imgur.com/QHsKSuG.png) # NN Architecture 採用streaming 架構,並且每一層都有單獨配置的compute engine; 一旦前一個engine開始輸出,後續的engine便開始計算; 並且所有BNN weight都保存在on-chip buffer 上,這避免了訪問off-chip的功耗浪費。 對於這項映射,還必須分配適當的計算資源才能獲得高效的架構,因此FINN 提供了可參數化的 建構層和控制分類吞吐量的方法會在下面提及。 選擇Vivado HLS實現,使開發周期縮短,並提供**自動化的pipeline**以滿足時序目標。 ![](https://i.imgur.com/9pIkjPA.png) # NN specification 以下說明了本文架構中BNN 的屬性: 1. 對每一層而言,輸入、輸出、權重,皆為二值化的(unset bit 代表-1, set bit 代表+1) 2. 在激活函數前使用BN layer 3. 使用Sign 作為激活函數 # Layer Architecture 1. 使用了XNOR Net 中popcount取代有號數字乘法,相比省下了約50%左右的LUT和FF resource 2. BN layer 接在Conv or FC 的output,並接續著 Sign func. 因此將Sign與BN結合在一起,設定threshold以推導結果,如何取得threshold在文中有解釋; 結論是,Vivado HLS 表示常規的BN+Sign 需要2xDSP, 55xFF, 40xLUT,而用此結合法,只需要6xLUT ![](https://i.imgur.com/201YvmG.png) 3. 文獻中的BNN 是對在進入Sign之前的非二值化值進行Maxpooling,然後再經過BN+Sign 可利用boolean OR operation 有效實現Maxpooling(詳細見文) # FINN Design Flow ![](https://i.imgur.com/vj93id4.png) # Matrix-Vector-Threshold Unit (MVTU) * MVTU 將FC layer 當作獨立組件實現,也實現Conv的部分組件 * PE( P ) and SIMD lanes( S ) 的數量是可自由配置以控制吞吐量 * 此方法屬於**weight stationary** and **output stationary** (每個popcount的計算結果都保持在PE中) ![](https://i.imgur.com/0Yz7VQA.png) * 計算input vector and kernel matrix一行的 dot product結果,並將計算結果與threshold 比較,得到最終的single-bit output * 使用XNOR gate 實現dot product,並累加到accumulator register 裡面 ![](https://i.imgur.com/sTelz7E.png) # Convolution : The Sliding Window Unit (SWU) * 類似進入systolic array 之前的數據重排 (經由interleaving filter) * ifm 0,1 為不同的ifm channel,自行推導一下如何進行 * interleaving filter 是off-line 完成的,不需要耗費額外成本 (?什麼意思,意思是FPGA的輸入已經是經過重排的數據嗎?) ![](https://i.imgur.com/cuquwgr.png) ![](https://i.imgur.com/4YviCck.png) # The Pooling Unit * 非常類似我設計的maxpooling,不過本文的buffer size 為pooling size 我設計的為input size,因為試過pooling size 的buffer 會產生每個output 持續延長pooling size 倍,而本文的方式為先在單個channel內 水平比較,再全部channel 垂直比較 (?暫時無法理解) # Folding * 根據MVTU 段描述,每個PE 對應一個硬體神經元,每個SIMD 通道充當神經元突觸, 因為resource 有限,不可能完全並行化,需要依用戶約束執行折疊 * 折疊直接影響系統的resource and power * 折疊是通過控制MVTU 的P跟S來劃分 **ex: 6x4 的weight matrix 如何劃分給3個PE** ![](https://i.imgur.com/kmDdYgs.png) # Evaluation **Device :** * OS: Ubuntu 15.04 * Board: Xilinx Zynq7000 All Programmable SoC ZC706 * Core: dual ARM Cortex-A9 cores (run host code: initialize images) * LUT: 218600 / BRAM: 545 * DRAM: 10000 images **Experimental Setup :** 1. * **Dataset: MNIST(28x28 gray binary image)** * SFC: 3-FC layer(256-256-256-10) -> 95.83% * LFC: 3-FC layer(1024-1024-1024-10) -> 98.4% 2. * **Dataset: CIFAR-10 -> 80.1%, SVHN -> 94.9% (32x32 RGB? 24-bit image)** * CNV: [Conv(3x3)-Conv(3x3)-Maxpool(2x2)] x3 - 2-FC layer(512-512-10) 每次Conv輸出的channel 數為(64-128-512) 3. * max: FINN 允許達到峰值FPS的配置 * fix: 具有固定FPS要求,並且依照使用場景實行折疊配置 以下為針對上面的各種實驗設置的workloads: ![](https://i.imgur.com/ncDkSVE.png) **Evaluation Result :** power 每10秒計算一次平均,並且**clock 的快慢,正比於throughput 跟power** * P_chip: 使用PMBus 接口來監控FPGA 電供量 * P_wall: 使用wall power meter(?) 來監控板子總功耗 ![](https://i.imgur.com/3SFefO6.png) # Results ## Maximum Throughput and Bottlenecks 所有max prototypes 都達到了TOPS 範圍內的性能,但由於不同的因素而受到瓶頸。 * CNV-max 達到 2.5 TOPS,並且受架構限制 (reason: SWU 設計不能像MVTU 那樣並行化擴展) * CNV-max 複雜度更高,但觀察到 CNV-max 實際上需要比 SFC-max 少 2 倍的 LUT,因為 CNV-max 的折疊參數是根據瓶頸規定的最大性能選擇的 * SFC-max 達到 8.2 TOPS 並且受內存限制 (只能在增加更多DRAM bandwidth 的情況下才能提升性能) * LFC-max 達到 9.1 TOPS,佔roofline的46% (這邊完全看不懂,主要是對roofline 這個指標不熟悉) ![](https://i.imgur.com/T0e0mZF.png) ## Energy Efficiency **目標: 最小化每個圖像分類所耗費的能量 -> 即最大化每瓦的FPS** 其中max/smax 差異在於smax 為clock 減慢為250kHz 的版本 ![](https://i.imgur.com/igtPMYE.png) 結論: 只要FPGA resource 可用,高度並行化可提升能源效率 ## Resource Efficiency 兩項指標: 1.計算單元在運行時的**運行效率** 2.FPGA資源映射成計算單元的**映射效率** 1. 運行效率: 模塊中每個週期的實際操作數(FPS * Ops / F_clk) 除以每個週期的突觸操作(summary of 2 * P * S)(?) * CNV: 70% * SFC: 80% * LFC: 90% 結論: 通過微調不同層之間的折疊因子可以提升運行效率 2. 映射效率: 內文提到,直接比較不同類型的層會損失一些公平的資訊,例如以下層之間的資源利用差異 * CNV: 在SWU, PU上使用了LUT * Fully connected layer: 沒有使用任何LUT 結論: 1. 每個Ops 所需的LUTs 量會隨著折疊因子P 增加而減少 P=64 時達到最小值 1.83,在P>64 時再度增加 2. BRAM的使用數量同樣隨著P 增加而增加,因為每個PE 都需要自己的weight reg.和threshold reg. 因此意味著當1<P<64 時,BRAM沒有被妥善利用 3. 比較SFC-fix/SFC-max,兩者使用完全相同的BNN參數,但由於SFC-max 實現了最高的並行度,所以使用的BRAM數量有幾乎10倍的差異 4. 在P<64 時,Vivado HLS會選擇使用LUT 來合成weight reg.和threshold reg. 而非BRAM,因此BRAM 的使用數量取決於並行化的程度和折疊比例 ![](https://i.imgur.com/6Fedi8e.png) # Comparison to prior work 本文建議,在比較不同平台的最佳方式,是處理相同benchmark MNIST,CIFAR-10,SVHN 時,比較以下三種指標: 1. Acc. 2. FPS 3. Power consumption **與先前的研究相比,最大的優點在於圖像的吞吐量 而準確率則沒有優於比其他人提出的研究成果,但精度差異仍然在與他人相比3% 以內** # Personal Conclusion 1. 在本論文前面有提到一些關於實現架構的分類,以及差異在哪 2. 每個層的實現方式都有明確講解,了解到跟我設計的差異在哪 不過論文使用HLS 設計,感覺上更改結構會比我更簡單,這方面也會跟公司問問看,純verilog 設計跟HLS 在開發上的差異,跟優化的細緻度(感覺上純verilog 會比較能更細優化) 3. 最大的收穫應該在,本文後段提出的衡量指標,不過對於roofline 這邊或許可以請教公司怎麼判讀;另外對於怎麼監測跟看功耗也有稍微了解