# Quantization and Training of Neural Networks for Efficient Integer-Arithmetic-Only Inference
作者:Benoit Jacob, Skirmantas Kligys, Bo Chen, Menglong Zhu, Matthew Tang, Andrew Howard, Hartwig Adam, Dmitry Kalenichenko
論文連結:https://arxiv.org/abs/1712.05877
整理by: [chewei](https://hackmd.io/@WTuIbJANSB26DiAX-WL4Sg)
- - - - -
## 前言:小模型的優勢
在不管手機,AR/VR,或是無人機等,這些裝置都需要模型在**受限的記憶體**(limited memory)以及**較低的模型在硬體上運行的時間**(low latency)
## 0.先前模型問題
* 先前的量化模型都是在AlexNet、VGG和GoogleNet等,而這些模型其實本身就有過度參數化的問題,導致在這些架構上進行量化可以輕易地獲得顯著的模型壓縮效果,但這樣的實驗更多只能證明概念,而不是提供實際應用中有意義的挑戰。
* 缺乏在實際硬件上的效率改進證明
$\rightarrow$因此作者決定**在MobileNets進行量化**,並且實做在**ARM(Advanced RISC Machine) 的 CPU**
-----
1. **x86 / x64 的 CPU** 跑起來比較快但是較吃電,所以通常會用在桌機 上,因為可以接電源。大部分的 windows 版本都跑在 x86 / x64 上。
2. **ARM 的 CPU** 較不吃電,通常用在手機上的 iOS 與 Android,早期還有用在 PDA 上。
## 1.本篇論文貢獻
1. 提供了一種**量化策略**,將權重和激活量化為INT8,並將少數幾個參數量化為INT32。
2. 提供了一個**quantized inference framework**,用來檢測整數運算在硬體上運行的結果。
3. 提供了一個**quantized training framework**,以最小化實際模型上量化的準確度損失。
4. 將這些框架應用於基於MobileNets的分類和檢測,並在ARM CPU上提供檢測結果。
$\rightarrow$**"Latency-vs-Accuracy"** tradeoffs for state-of-the-art MobileNet architectures
## 2.Quantization scheme(量化策略)
* inference:
* 使用integer-only計算
* training:
* 使用floating-point計算
## 3.Inference 狀態的量化

### 3-1.量化方式
把所有的**activations**跟**weights**個別集合成一個**array**,這兩個arrays為一個**set**,採用以下方程式做轉換:
$$
r=S(q-Z)
$$
* q:Quantization後的數
* r:Quantization前的真實floating-point
* S:Scale通常為floating-point的隨機正實數
* Z:“zero-point”,代表在floating-point的0被Quantization後的值
```cpp
template<typename QType>//e.g. QType=uint8
struct QuantizedBuffer{
vector<QType> q; //the quantized values
float S; //the scale
QType Z; //the zero-point
};
```
### 3-2.實際量化細節(數學地獄)
依據剛才提到的公式
$$
r=S(q-Z)
$$
* q:Quantization後的數
* r:Quantization前的真實floating-point
* S:Scale通常為floating-point的隨機正實數
* Z:“zero-point”,代表在floating-point的0被Quantization後的值
那將實際情況帶入,還記得我們的set中兩個array是activations跟weights嗎!?
那麼實際參數在跑時就是不斷的activation和weight做內積對八~
因此在floating-point下他們就可以表示成$r_3=r_1r_2$
以每個r都是矩陣來看那就可以寫成:
$r_\alpha(\alpha=1,2\,or\,3)\,as\, r_\alpha^{(i,j)}\text{ for }1\leq\,i,j\,\,\leq N$
其實就是把array(NxN)的矩陣攤開來相乘相加,而將其帶入$r=S(q-Z)$後就可以得到 $\downarrow$
$$
r_\alpha^{(i,j)}=S_\alpha(q_\alpha^{(i,j)}-Z_\alpha).
$$
$$
\rightarrow S_3(q_3^{(i,k)}-Z_3)=\sum_{j=1}^{N}{S_1(q_1^{(i,j)}-Z_1)S_2(q_2^{(j,k)}-Z_2)},
$$
$$
\rightarrow q_3^{(i,k)}=Z_3+M\sum_{j=1}^{N}{(q_1^{(i,j)}-Z_1)(q_2^{(j,k)}-Z_2)}
,where\, M:=\frac{S_1S_2}{S_3}
$$
經整理過後$q_3^{(i,k)}$就是經過第$r_1\text{層activation的第}r_2$層weight。
而以上運算就只剩下M為非int的運算,因此我們用以下方式也**將M轉換為int的表示方式**:
$$
M=2^{-n}M_0
,where\,\,\,M_0 \in[0.5,1]
,n是非負整數
$$
- - - - -
在整理完後作者又將上面得出的$q_3^{(i,k)}$計算再再再做化簡,拆成三個部份:
$$
q_3^{(i,k)}=Z_3+M(NZ_1Z_2-Z_1a_2^{(k)}-Z_2\bar a_1^{(i)}+\sum_{j=1}^{N}{q_1^{(i,j)}}q_2^{(j,k)})
$$
然而其中$a_2^{(k)}$和$\bar a_1^{(i)}$可以預先算好重複使用:
$$
a_2^{(k)}:=\sum_{j=1}^{N}q_2^{(j,k)},\bar a_1^{(i)}:=\sum_{j=1}^{N}q_1^{(i,j)}.
$$
且算式前面定值z,N的乘法也非常好算,這樣唯一比較需要計算的就只剩最後一項:
$$
\sum_{j=1}^{N}{q_1^{(i,j)}}q_2^{(j,k)}
$$
因此這樣分開並重複使用算好的$a_2^{(k)}$和$\bar a_1^{(i)}$可以降低運算時間
### 3-3. 矩陣計算
在矩陣計算中以uint8為例,兩個矩陣的相乘可以寫成:
$$
int32+=uint8*uint8
$$
以32-bits來累加元素相乘後的結果,接著需要把累加器的值縮放(降維)到最終的8-bits量化輸出的規模。然後,進行down-scaling的操作,將32-bits的數據轉換成8-bits的數據,這個過程中會保證數據值落在0到255的範圍內。最後,經過激活函數,通常是某種形式的ReLU函數,進一步確保每個神經元的輸出落在特定的範圍內。
## 4.Training 狀態的量化

* Forward-propagation:使用`simulates quantized inference`(跟inference時相同
* Weights在捲積前會被量化
* Activations在捲積層或全連接層後被使用時也會被量化
* Backward-propagation:不做quantization
**以下為quantization公式:**
$$
\begin{align*}
& clamp(r;a;b):=min(max(x,a)b) \\
& s(a,b,n):=\frac{b-a}{n-1} \\
& q(r;a,b,n):=\lfloor \frac{\text{clamp}(r;a,b) - a}{s(a,b,n)} \rceil s(a,b,n)+a, \\
\end{align*}
$$
* r是Quantization前的真實floating-point
* [a;b]為要量化成的範圍
* n為要quantization的bits使用的值
> e.g. $n=2^8=256$ 那就代表要quantize到8 bits
### 4-1.Quantization ranges
猶如上面式子所述,[a;b]為要量化成的範圍,而這個範為在`weight quantization`時和`activation quantization`**是不同的!!**
* For **weight**:
* $a := min\,w$
* $b := max\,w$
* e.g. for int8 $\rightarrow [−127, 127]$
* For **activations**:
* 量化的範圍由input決定
* 使用exponential moving averages (EMA)找 [a,b]
* 在50 thousand 到2 million steps後才開始使用量化激活函數(因為EMA非常耗時)
在找到[a,b]後會將其shft對到0.0 $\rightarrow z(a,b,n)$
## 5.Batch normalization folding
* 為了簡化inference過程,提高推理時的運算效率因此作者要`將BN層"fold"(化簡)進前一層`,使得"BN層"消失
* 以下為"fold"公式:
$$
\begin{align*}
& w_{fold}=\frac{\gamma}{\sqrt{ETA(\sigma^2_B)+\epsilon}}\cdot w \\ \\
& w_{fold}為折疊後的權重 \\
& \gamma是BN縮放參數(scale parameter) \\
& ETA(\sigma^2_B)是用於估計整個數據集的特徵分佈 \\
& \epsilon是一個很小的常數 \\
& w是原始權重
\end{align*}
$$
## Reference
TWN
[2] [Binary Neural Networks(BNN)](https://hackmd.io/@ntnuaiot/SyOQjnp2T)
XNOR-net
MobileNets