# 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 狀態的量化 ![image](https://hackmd.io/_uploads/SJrwwEP0a.png) ### 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 狀態的量化 ![image](https://hackmd.io/_uploads/Sk99PNvAp.png) * 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