# 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

另外BNN 因為參數的總容量小,整個model 可以保存在on-chip buffer 上,
因此BNN 能達到計算峰值。
# Acc. Trade-Off
本文也對BNN 常被詬病的低精度進行討論,結論如下:
1. 隨著模型規模增加,BNN 與float model 的acc 差異漸漸縮小
2. 為了達到相同的acc.,BNN 的建議參數量與操作量約需要float model 的**2~11倍**

# NN Architecture
採用streaming 架構,並且每一層都有單獨配置的compute engine;
一旦前一個engine開始輸出,後續的engine便開始計算;
並且所有BNN weight都保存在on-chip buffer 上,這避免了訪問off-chip的功耗浪費。
對於這項映射,還必須分配適當的計算資源才能獲得高效的架構,因此FINN 提供了可參數化的
建構層和控制分類吞吐量的方法會在下面提及。
選擇Vivado HLS實現,使開發周期縮短,並提供**自動化的pipeline**以滿足時序目標。

# 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

3. 文獻中的BNN 是對在進入Sign之前的非二值化值進行Maxpooling,然後再經過BN+Sign
可利用boolean OR operation 有效實現Maxpooling(詳細見文)
# FINN Design Flow

# Matrix-Vector-Threshold Unit (MVTU)
* MVTU 將FC layer 當作獨立組件實現,也實現Conv的部分組件
* PE( P ) and SIMD lanes( S ) 的數量是可自由配置以控制吞吐量
* 此方法屬於**weight stationary** and **output stationary** (每個popcount的計算結果都保持在PE中)

* 計算input vector and kernel matrix一行的 dot product結果,並將計算結果與threshold 比較,得到最終的single-bit output
* 使用XNOR gate 實現dot product,並累加到accumulator register 裡面

# Convolution : The Sliding Window Unit (SWU)
* 類似進入systolic array 之前的數據重排 (經由interleaving filter)
* ifm 0,1 為不同的ifm channel,自行推導一下如何進行
* interleaving filter 是off-line 完成的,不需要耗費額外成本 (?什麼意思,意思是FPGA的輸入已經是經過重排的數據嗎?)


# 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**

# 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:

**Evaluation Result :**
power 每10秒計算一次平均,並且**clock 的快慢,正比於throughput 跟power**
* P_chip: 使用PMBus 接口來監控FPGA 電供量
* P_wall: 使用wall power meter(?) 來監控板子總功耗

# 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 這個指標不熟悉)

## Energy Efficiency
**目標: 最小化每個圖像分類所耗費的能量 -> 即最大化每瓦的FPS**
其中max/smax 差異在於smax 為clock 減慢為250kHz 的版本

結論: 只要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 的使用數量取決於並行化的程度和折疊比例

# 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 這邊或許可以請教公司怎麼判讀;另外對於怎麼監測跟看功耗也有稍微了解